2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6
* The contents of this file are subject to the terms of either the GNU
7
* General Public License Version 2 only ("GPL") or the Common
8
* Development and Distribution License("CDDL") (collectively, the
9
* "License"). You may not use this file except in compliance with the
10
* License. You can obtain a copy of the License at
11
* http://www.netbeans.org/cddl-gplv2.html
12
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
* specific language governing permissions and limitations under the
14
* License. When distributing the software, include this License Header
15
* Notice in each file and include the License file at
16
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17
* particular file as subject to the "Classpath" exception as provided
18
* by Sun in the GPL Version 2 section of the License file that
19
* accompanied this code. If applicable, add the following below the
20
* License Header, with the fields enclosed by brackets [] replaced by
21
* your own identifying information:
22
* "Portions Copyrighted [year] [name of copyright owner]"
26
* The Original Software is NetBeans. The Initial Developer of the Original
27
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
28
* Microsystems, Inc. All Rights Reserved.
30
* If you wish your version of this file to be governed by only the CDDL
31
* or only the GPL Version 2, indicate your decision by adding
32
* "[Contributor] elects to include this software in this distribution
33
* under the [CDDL or GPL Version 2] license." If you do not indicate a
34
* single choice of license, a recipient has the option to distribute
35
* your version of this file under either the CDDL, the GPL Version 2 or
36
* to extend the choice of license to its licensees as provided above.
37
* However, if you add GPL Version 2 code and therefore, elected the GPL
38
* Version 2 license, then the option applies only if the new code is
39
* made subject to such option by the copyright holder.
41
package org.netbeans.modules.mercurial.ui.diff;
43
import org.openide.explorer.view.NodeTableModel;
44
import org.openide.util.NbBundle;
45
import org.openide.nodes.Node;
46
import org.openide.nodes.PropertySupport;
47
import org.openide.ErrorManager;
48
import org.openide.windows.TopComponent;
49
import org.netbeans.modules.versioning.util.TableSorter;
50
import org.netbeans.modules.versioning.util.FilePathCellRenderer;
52
import javax.swing.event.*;
54
import javax.swing.table.DefaultTableCellRenderer;
55
import java.awt.event.MouseListener;
56
import java.awt.event.KeyEvent;
57
import java.awt.event.ActionEvent;
58
import java.awt.event.MouseEvent;
59
import java.awt.Color;
60
import java.awt.Point;
61
import java.awt.Component;
63
import java.lang.reflect.InvocationTargetException;
68
* @author Maros Sandor
70
class DiffFileTable implements MouseListener, ListSelectionListener, AncestorListener {
72
private NodeTableModel tableModel;
74
private JScrollPane component;
75
private Node [] nodes = new Node[0];
77
private String [] tableColumns;
78
private TableSorter sorter;
81
* Defines labels for Diff view table columns.
83
private static final Map<String, String[]> columnLabels = new HashMap<String, String[]>(4);
86
ResourceBundle loc = NbBundle.getBundle(DiffFileTable.class);
87
columnLabels.put(DiffNode.COLUMN_NAME_NAME, new String [] {
88
loc.getString("CTL_DiffTable_Column_Name_Title"),
89
loc.getString("CTL_DiffTable_Column_Name_Desc")});
90
columnLabels.put(DiffNode.COLUMN_NAME_PROPERTY, new String [] {
91
loc.getString("CTL_DiffTable_Column_Property_Title"),
92
loc.getString("CTL_DiffTable_Column_Property_Desc")});
93
columnLabels.put(DiffNode.COLUMN_NAME_STATUS, new String [] {
94
loc.getString("CTL_DiffTable_Column_Status_Title"),
95
loc.getString("CTL_DiffTable_Column_Status_Desc")});
96
columnLabels.put(DiffNode.COLUMN_NAME_LOCATION, new String [] {
97
loc.getString("CTL_DiffTable_Column_Location_Title"),
98
loc.getString("CTL_DiffTable_Column_Location_Desc")});
103
private static final Comparator NodeComparator = new Comparator() {
104
public int compare(Object o1, Object o2) {
105
Node.Property p1 = (Node.Property) o1;
106
Node.Property p2 = (Node.Property) o2;
107
String sk1 = (String) p1.getValue("sortkey"); // NOI18N
109
String sk2 = (String) p2.getValue("sortkey"); // NOI18N
110
return sk1.compareToIgnoreCase(sk2);
113
String s1 = (String) p1.getValue();
114
String s2 = (String) p2.getValue();
115
return s1.compareToIgnoreCase(s2);
116
} catch (Exception e) {
117
ErrorManager.getDefault().notify(e);
123
private final MultiDiffPanel master;
125
public DiffFileTable(MultiDiffPanel master) {
126
this.master = master;
127
tableModel = new NodeTableModel();
128
sorter = new TableSorter(tableModel);
129
sorter.setColumnComparator(Node.Property.class, DiffFileTable.NodeComparator);
130
table = new JTable(sorter);
131
table.getSelectionModel().addListSelectionListener(this);
132
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
133
sorter.setTableHeader(table.getTableHeader());
134
table.setRowHeight(table.getRowHeight() * 6 / 5);
135
component = new JScrollPane(table, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
136
component.getViewport().setBackground(table.getBackground());
137
Color borderColor = UIManager.getColor("scrollpane_border"); // NOI18N
138
if (borderColor == null) borderColor = UIManager.getColor("controlShadow"); // NOI18N
139
component.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, borderColor));
140
table.addMouseListener(this);
141
table.setDefaultRenderer(Node.Property.class, new DiffTableCellRenderer());
142
table.getSelectionModel().addListSelectionListener(this);
143
table.addAncestorListener(this);
144
table.getAccessibleContext().setAccessibleName(NbBundle.getMessage(DiffFileTable.class, "ACSN_DiffTable")); // NOI18N
145
table.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(DiffFileTable.class, "ACSD_DiffTable")); // NOI18N
146
setColumns(new String[] {
147
DiffNode.COLUMN_NAME_NAME,
148
DiffNode.COLUMN_NAME_PROPERTY,
149
DiffNode.COLUMN_NAME_STATUS,
150
DiffNode.COLUMN_NAME_LOCATION}
152
table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ).put(
153
KeyStroke.getKeyStroke(KeyEvent.VK_F10, KeyEvent.SHIFT_DOWN_MASK ), "org.openide.actions.PopupAction");
154
table.getActionMap().put("org.openide.actions.PopupAction", new AbstractAction() {
155
public void actionPerformed(ActionEvent e) {
156
showPopup(org.netbeans.modules.versioning.util.Utils.getPositionForPopup(table));
161
void setDefaultColumnSizes() {
162
SwingUtilities.invokeLater(new Runnable() {
164
int width = table.getWidth();
165
if (tableColumns.length == 3) {
166
for (int i = 0; i < tableColumns.length; i++) {
167
if (DiffNode.COLUMN_NAME_LOCATION.equals(tableColumns[i])) {
168
table.getColumnModel().getColumn(i).setPreferredWidth(width * 60 / 100);
170
table.getColumnModel().getColumn(i).setPreferredWidth(width * 20 / 100);
173
} else if (tableColumns.length == 4) {
174
for (int i = 0; i < tableColumns.length; i++) {
175
if (DiffNode.COLUMN_NAME_LOCATION.equals(tableColumns[i])) {
176
table.getColumnModel().getColumn(i).setPreferredWidth(width * 55 / 100);
178
table.getColumnModel().getColumn(i).setPreferredWidth(width * 15 / 100);
186
public void ancestorAdded(AncestorEvent event) {
187
setDefaultColumnSizes();
190
public void ancestorMoved(AncestorEvent event) {
193
public void ancestorRemoved(AncestorEvent event) {
196
public JComponent getComponent() {
201
* Sets visible columns in the Versioning table.
203
* @param columns array of column names, they must be one of SyncFileNode.COLUMN_NAME_XXXXX constants.
205
final void setColumns(String [] columns) {
206
if (Arrays.equals(columns, tableColumns)) return;
207
setModelProperties(columns);
208
tableColumns = columns;
209
for (int i = 0; i < tableColumns.length; i++) {
210
sorter.setColumnComparator(i, null);
211
sorter.setSortingStatus(i, TableSorter.NOT_SORTED);
212
if (DiffNode.COLUMN_NAME_STATUS.equals(tableColumns[i])) {
213
sorter.setSortingStatus(i, TableSorter.ASCENDING);
217
setDefaultColumnSizes();
220
private void setModelProperties(String [] columns) {
221
Node.Property [] properties = new Node.Property[columns.length];
222
for (int i = 0; i < columns.length; i++) {
223
String column = columns[i];
224
String [] labels = (String[]) columnLabels.get(column);
225
properties[i] = new ColumnDescriptor(column, String.class, labels[0], labels[1]);
227
tableModel.setProperties(properties);
230
void setTableModel(Node [] nodes) {
232
tableModel.setNodes(nodes);
236
table.requestFocus();
239
void setSelectedIndex(int currentIndex) {
240
if (currentIndex == table.getSelectedRow()) return;
241
table.getSelectionModel().setSelectionInterval(currentIndex, currentIndex);
242
table.scrollRectToVisible(table.getCellRect(currentIndex, 0, true));
245
public int getSelectedIndex() {
246
return table.getSelectedRow();
249
public int getSelectedModelIndex() {
250
return getModelIndex(table.getSelectedRow());
253
public int getModelIndex(int viewIndex) {
254
return viewIndex != -1 ? sorter.modelIndex(viewIndex) : -1;
257
public JTable getTable() {
261
private static class ColumnDescriptor extends PropertySupport.ReadOnly {
263
@SuppressWarnings("unchecked")
264
public ColumnDescriptor(String name, Class type, String displayName, String shortDescription) {
265
super(name, type, displayName, shortDescription);
268
public Object getValue() throws IllegalAccessException, InvocationTargetException {
273
private void showPopup(final MouseEvent e) {
274
int row = table.rowAtPoint(e.getPoint());
276
boolean makeRowSelected = true;
277
int [] selectedrows = table.getSelectedRows();
279
for (int i = 0; i < selectedrows.length; i++) {
280
if (row == selectedrows[i]) {
281
makeRowSelected = false;
285
if (makeRowSelected) {
286
table.getSelectionModel().setSelectionInterval(row, row);
289
SwingUtilities.invokeLater(new Runnable() {
291
// invoke later so the selection on the table will be set first
292
// JPopupMenu menu = getPopup();
293
// menu.show(table, e.getX(), e.getY());
298
private void showPopup(Point p) {
299
// JPopupMenu menu = getPopup();
300
// menu.show(table, p.x, p.y);
303
private JPopupMenu getPopup() {
304
JPopupMenu menu = new JPopupMenu();
309
public void mouseEntered(MouseEvent e) {
312
public void mouseExited(MouseEvent e) {
315
public void mousePressed(MouseEvent e) {
316
if (e.isPopupTrigger()) {
321
public void mouseReleased(MouseEvent e) {
322
if (e.isPopupTrigger()) {
327
public void mouseClicked(MouseEvent e) {
329
if (SwingUtilities.isLeftMouseButton(e) && MouseUtils.isDoubleClick(e)) {
330
int row = table.rowAtPoint(e.getPoint());
331
if (row == -1) return;
332
row = sorter.modelIndex(row);
333
Action action = nodes[row].getPreferredAction();
334
if (action == null || !action.isEnabled()) action = new OpenInEditorAction();
335
if (action.isEnabled()) {
336
action.actionPerformed(new ActionEvent(this, 0, "")); // NOI18N
342
public void valueChanged(ListSelectionEvent e) {
343
final TopComponent tc = (TopComponent) SwingUtilities.getAncestorOfClass(TopComponent.class, table);
344
if (tc == null) return; // table is no longer in component hierarchy
345
master.setSelectedIndex(table.getSelectedRow());
348
private class DiffTableCellRenderer extends DefaultTableCellRenderer {
350
private FilePathCellRenderer pathRenderer = new FilePathCellRenderer();
352
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
354
int modelColumnIndex = table.convertColumnIndexToModel(column);
355
if (modelColumnIndex == 0) {
356
Node node = nodes[sorter.modelIndex(row)];
358
value = "<html>" + node.getHtmlDisplayName(); // NOI18N
361
if (modelColumnIndex == 2) {
362
renderer = pathRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
364
renderer = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
366
if (renderer instanceof JComponent) {
367
File file = nodes[sorter.modelIndex(row)].getLookup().lookup(File.class);
368
String path = file != null ? file.getAbsolutePath() : null;
369
((JComponent) renderer).setToolTipText(path);