001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.subversion.ui.diff;
042:
043: import org.openide.explorer.view.NodeTableModel;
044: import org.openide.util.NbBundle;
045: import org.openide.nodes.Node;
046: import org.openide.nodes.PropertySupport;
047: import org.openide.windows.TopComponent;
048: import org.netbeans.modules.versioning.util.TableSorter;
049: import org.netbeans.modules.versioning.util.FilePathCellRenderer;
050:
051: import javax.swing.event.*;
052: import javax.swing.*;
053: import javax.swing.table.DefaultTableCellRenderer;
054: import java.awt.event.MouseListener;
055: import java.awt.event.KeyEvent;
056: import java.awt.event.ActionEvent;
057: import java.awt.event.MouseEvent;
058: import java.awt.Color;
059: import java.awt.Point;
060: import java.awt.Component;
061: import java.util.*;
062: import java.lang.reflect.InvocationTargetException;
063: import java.io.File;
064: import java.util.logging.Level;
065: import org.netbeans.modules.subversion.Subversion;
066:
067: /**
068: *
069: * @author Maros Sandor
070: */
071: class DiffFileTable implements MouseListener, ListSelectionListener,
072: AncestorListener {
073:
074: private NodeTableModel tableModel;
075: private JTable table;
076: private JScrollPane component;
077: private Node[] nodes = new Node[0];
078:
079: private String[] tableColumns;
080: private TableSorter sorter;
081:
082: /**
083: * Defines labels for Diff view table columns.
084: */
085: private static final Map<String, String[]> columnLabels = new HashMap<String, String[]>(
086: 4);
087:
088: {
089: ResourceBundle loc = NbBundle.getBundle(DiffFileTable.class);
090: columnLabels.put(DiffNode.COLUMN_NAME_NAME, new String[] {
091: loc.getString("CTL_DiffTable_Column_Name_Title"),
092: loc.getString("CTL_DiffTable_Column_Name_Desc") });
093: columnLabels.put(DiffNode.COLUMN_NAME_PROPERTY, new String[] {
094: loc.getString("CTL_DiffTable_Column_Property_Title"),
095: loc.getString("CTL_DiffTable_Column_Property_Desc") });
096: columnLabels.put(DiffNode.COLUMN_NAME_STATUS, new String[] {
097: loc.getString("CTL_DiffTable_Column_Status_Title"),
098: loc.getString("CTL_DiffTable_Column_Status_Desc") });
099: columnLabels.put(DiffNode.COLUMN_NAME_LOCATION, new String[] {
100: loc.getString("CTL_DiffTable_Column_Location_Title"),
101: loc.getString("CTL_DiffTable_Column_Location_Desc") });
102: }
103:
104: private static final Comparator NodeComparator = new Comparator() {
105: public int compare(Object o1, Object o2) {
106: Node.Property p1 = (Node.Property) o1;
107: Node.Property p2 = (Node.Property) o2;
108: String sk1 = (String) p1.getValue("sortkey"); // NOI18N
109: if (sk1 != null) {
110: String sk2 = (String) p2.getValue("sortkey"); // NOI18N
111: return sk1.compareToIgnoreCase(sk2);
112: } else {
113: try {
114: String s1 = (String) p1.getValue();
115: String s2 = (String) p2.getValue();
116: return s1.compareToIgnoreCase(s2);
117: } catch (Exception e) {
118: Subversion.LOG.log(Level.SEVERE, null, e);
119: return 0;
120: }
121: }
122: }
123: };
124: private final MultiDiffPanel master;
125:
126: public DiffFileTable(MultiDiffPanel master) {
127: this .master = master;
128: tableModel = new NodeTableModel();
129: sorter = new TableSorter(tableModel);
130: sorter.setColumnComparator(Node.Property.class,
131: DiffFileTable.NodeComparator);
132: table = new JTable(sorter);
133: table.getSelectionModel().addListSelectionListener(this );
134: table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
135: sorter.setTableHeader(table.getTableHeader());
136: table.setRowHeight(table.getRowHeight() * 6 / 5);
137: component = new JScrollPane(table,
138: JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
139: JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
140: component.getViewport().setBackground(table.getBackground());
141: Color borderColor = UIManager.getColor("scrollpane_border"); // NOI18N
142: if (borderColor == null)
143: borderColor = UIManager.getColor("controlShadow"); // NOI18N
144: component.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0,
145: borderColor));
146: table.addMouseListener(this );
147: table.setDefaultRenderer(Node.Property.class,
148: new DiffTableCellRenderer());
149: table.getSelectionModel().addListSelectionListener(this );
150: table.addAncestorListener(this );
151: table.getAccessibleContext().setAccessibleName(
152: NbBundle.getMessage(DiffFileTable.class,
153: "ACSN_DiffTable")); // NOI18N
154: table.getAccessibleContext().setAccessibleDescription(
155: NbBundle.getMessage(DiffFileTable.class,
156: "ACSD_DiffTable")); // NOI18N
157: setColumns(new String[] { DiffNode.COLUMN_NAME_NAME,
158: DiffNode.COLUMN_NAME_PROPERTY,
159: DiffNode.COLUMN_NAME_STATUS,
160: DiffNode.COLUMN_NAME_LOCATION });
161: table
162: .getInputMap(
163: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
164: .put(
165: KeyStroke.getKeyStroke(KeyEvent.VK_F10,
166: KeyEvent.SHIFT_DOWN_MASK),
167: "org.openide.actions.PopupAction");
168: table.getActionMap().put("org.openide.actions.PopupAction",
169: new AbstractAction() {
170: public void actionPerformed(ActionEvent e) {
171: showPopup(org.netbeans.modules.versioning.util.Utils
172: .getPositionForPopup(table));
173: }
174: });
175: }
176:
177: void setDefaultColumnSizes() {
178: SwingUtilities.invokeLater(new Runnable() {
179: public void run() {
180: int width = table.getWidth();
181: if (tableColumns.length == 3) {
182: for (int i = 0; i < tableColumns.length; i++) {
183: if (DiffNode.COLUMN_NAME_LOCATION
184: .equals(tableColumns[i])) {
185: table
186: .getColumnModel()
187: .getColumn(i)
188: .setPreferredWidth(width * 60 / 100);
189: } else {
190: table
191: .getColumnModel()
192: .getColumn(i)
193: .setPreferredWidth(width * 20 / 100);
194: }
195: }
196: } else if (tableColumns.length == 4) {
197: for (int i = 0; i < tableColumns.length; i++) {
198: if (DiffNode.COLUMN_NAME_LOCATION
199: .equals(tableColumns[i])) {
200: table
201: .getColumnModel()
202: .getColumn(i)
203: .setPreferredWidth(width * 55 / 100);
204: } else {
205: table
206: .getColumnModel()
207: .getColumn(i)
208: .setPreferredWidth(width * 15 / 100);
209: }
210: }
211: }
212: }
213: });
214: }
215:
216: public void ancestorAdded(AncestorEvent event) {
217: setDefaultColumnSizes();
218: }
219:
220: public void ancestorMoved(AncestorEvent event) {
221: }
222:
223: public void ancestorRemoved(AncestorEvent event) {
224: }
225:
226: public JComponent getComponent() {
227: return component;
228: }
229:
230: /**
231: * Sets visible columns in the Versioning table.
232: *
233: * @param columns array of column names, they must be one of SyncFileNode.COLUMN_NAME_XXXXX constants.
234: */
235: final void setColumns(String[] columns) {
236: if (Arrays.equals(columns, tableColumns))
237: return;
238: setModelProperties(columns);
239: tableColumns = columns;
240: for (int i = 0; i < tableColumns.length; i++) {
241: sorter.setColumnComparator(i, null);
242: sorter.setSortingStatus(i, TableSorter.NOT_SORTED);
243: if (DiffNode.COLUMN_NAME_STATUS.equals(tableColumns[i])) {
244: sorter.setSortingStatus(i, TableSorter.ASCENDING);
245: break;
246: }
247: }
248: setDefaultColumnSizes();
249: }
250:
251: private void setModelProperties(String[] columns) {
252: Node.Property[] properties = new Node.Property[columns.length];
253: for (int i = 0; i < columns.length; i++) {
254: String column = columns[i];
255: String[] labels = (String[]) columnLabels.get(column);
256: properties[i] = new ColumnDescriptor(column, String.class,
257: labels[0], labels[1]);
258: }
259: tableModel.setProperties(properties);
260: }
261:
262: void setTableModel(Node[] nodes) {
263: this .nodes = nodes;
264: tableModel.setNodes(nodes);
265: }
266:
267: void focus() {
268: table.requestFocus();
269: }
270:
271: void setSelectedIndex(int currentIndex) {
272: if (currentIndex == table.getSelectedRow())
273: return;
274: table.getSelectionModel().setSelectionInterval(currentIndex,
275: currentIndex);
276: table.scrollRectToVisible(table.getCellRect(currentIndex, 0,
277: true));
278: }
279:
280: public int getSelectedIndex() {
281: return table.getSelectedRow();
282: }
283:
284: public int getSelectedModelIndex() {
285: return getModelIndex(table.getSelectedRow());
286: }
287:
288: public int getModelIndex(int viewIndex) {
289: return viewIndex != -1 ? sorter.modelIndex(viewIndex) : -1;
290: }
291:
292: public JTable getTable() {
293: return table;
294: }
295:
296: private static class ColumnDescriptor extends
297: PropertySupport.ReadOnly {
298:
299: public ColumnDescriptor(String name, Class type,
300: String displayName, String shortDescription) {
301: super (name, type, displayName, shortDescription);
302: }
303:
304: public Object getValue() throws IllegalAccessException,
305: InvocationTargetException {
306: return null;
307: }
308: }
309:
310: private void showPopup(final MouseEvent e) {
311: int row = table.rowAtPoint(e.getPoint());
312: if (row != -1) {
313: boolean makeRowSelected = true;
314: int[] selectedrows = table.getSelectedRows();
315:
316: for (int i = 0; i < selectedrows.length; i++) {
317: if (row == selectedrows[i]) {
318: makeRowSelected = false;
319: break;
320: }
321: }
322: if (makeRowSelected) {
323: table.getSelectionModel()
324: .setSelectionInterval(row, row);
325: }
326: }
327: SwingUtilities.invokeLater(new Runnable() {
328: public void run() {
329: // invoke later so the selection on the table will be set first
330: // JPopupMenu menu = getPopup();
331: // menu.show(table, e.getX(), e.getY());
332: }
333: });
334: }
335:
336: private void showPopup(Point p) {
337: // JPopupMenu menu = getPopup();
338: // menu.show(table, p.x, p.y);
339: }
340:
341: private JPopupMenu getPopup() {
342: JPopupMenu menu = new JPopupMenu();
343: JMenuItem item;
344: return menu;
345: }
346:
347: public void mouseEntered(MouseEvent e) {
348: }
349:
350: public void mouseExited(MouseEvent e) {
351: }
352:
353: public void mousePressed(MouseEvent e) {
354: if (e.isPopupTrigger()) {
355: showPopup(e);
356: }
357: }
358:
359: public void mouseReleased(MouseEvent e) {
360: if (e.isPopupTrigger()) {
361: showPopup(e);
362: }
363: }
364:
365: public void mouseClicked(MouseEvent e) {
366: /*
367: if (SwingUtilities.isLeftMouseButton(e) && MouseUtils.isDoubleClick(e)) {
368: int row = table.rowAtPoint(e.getPoint());
369: if (row == -1) return;
370: row = sorter.modelIndex(row);
371: Action action = nodes[row].getPreferredAction();
372: if (action == null || !action.isEnabled()) action = new OpenInEditorAction();
373: if (action.isEnabled()) {
374: action.actionPerformed(new ActionEvent(this, 0, "")); // NOI18N
375: }
376: }
377: */
378: }
379:
380: public void valueChanged(ListSelectionEvent e) {
381: final TopComponent tc = (TopComponent) SwingUtilities
382: .getAncestorOfClass(TopComponent.class, table);
383: if (tc == null)
384: return; // table is no longer in component hierarchy
385: master.setSelectedIndex(table.getSelectedRow());
386: }
387:
388: private class DiffTableCellRenderer extends
389: DefaultTableCellRenderer {
390:
391: private FilePathCellRenderer pathRenderer = new FilePathCellRenderer();
392:
393: public Component getTableCellRendererComponent(JTable table,
394: Object value, boolean isSelected, boolean hasFocus,
395: int row, int column) {
396: Component renderer;
397: int modelColumnIndex = table
398: .convertColumnIndexToModel(column);
399: if (modelColumnIndex == 0) {
400: Node node = nodes[sorter.modelIndex(row)];
401: if (!isSelected) {
402: value = "<html>" + node.getHtmlDisplayName(); // NOI18N
403: }
404: }
405: if (modelColumnIndex == 2) {
406: renderer = pathRenderer
407: .getTableCellRendererComponent(table, value,
408: isSelected, hasFocus, row, column);
409: } else {
410: renderer = super .getTableCellRendererComponent(table,
411: value, isSelected, hasFocus, row, column);
412: }
413: if (renderer instanceof JComponent) {
414: File file = nodes[sorter.modelIndex(row)].getLookup()
415: .lookup(File.class);
416: String path = file != null ? file.getAbsolutePath()
417: : null;
418: ((JComponent) renderer).setToolTipText(path);
419: }
420: return renderer;
421: }
422: }
423: }
|