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-2006 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.openide.explorer.view;
042:
043: import org.openide.nodes.*;
044:
045: import javax.swing.JTree;
046: import javax.swing.SwingUtilities;
047: import javax.swing.event.*;
048: import javax.swing.tree.TreePath;
049:
050: /* NodeTableModel synchronizing tree and table model. Used by TreeTable.
051: *
052: * @author Jan Rojcek
053: */
054: class TreeTableModelAdapter extends NodeTableModel {
055: private JTree tree;
056: private NodeTableModel nodeTableModel;
057:
058: public TreeTableModelAdapter(JTree t, NodeTableModel ntm) {
059: this .tree = t;
060: this .nodeTableModel = ntm;
061:
062: Listener listener = new Listener();
063: tree.addTreeExpansionListener(listener);
064: tree.getModel().addTreeModelListener(listener);
065: nodeTableModel.addTableModelListener(listener);
066: }
067:
068: // NodeTableModel methods
069: public void setNodes(Node[] nodes) {
070: nodeTableModel.setNodes(nodes);
071: }
072:
073: public void setProperties(Node.Property[] props) {
074: nodeTableModel.setProperties(props);
075: }
076:
077: protected Node.Property getPropertyFor(Node node, Node.Property prop) {
078: return nodeTableModel.getPropertyFor(node, prop);
079: }
080:
081: Node nodeForRow(int row) {
082: return Visualizer.findNode(tree.getPathForRow(row)
083: .getLastPathComponent());
084: }
085:
086: Node.Property propertyForColumn(int column) {
087: return nodeTableModel.propertyForColumn(column - 1);
088: }
089:
090: // Wrappers, implementing TableModel interface.
091: public int getColumnCount() {
092: return nodeTableModel.getColumnCount() + 1;
093: }
094:
095: public String getColumnName(int column) {
096: return (column == 0) ? Visualizer.findNode(
097: tree.getModel().getRoot()).getDisplayName()
098: : nodeTableModel.getColumnName(column - 1);
099: }
100:
101: public Class getColumnClass(int column) {
102: return (column == 0) ? TreeTableModelAdapter.class
103: : nodeTableModel.getColumnClass(column - 1);
104: }
105:
106: public int getRowCount() {
107: return tree.getRowCount();
108: }
109:
110: public Object getValueAt(int row, int column) {
111: return (column == 0) ? tree.getPathForRow(row)
112: .getLastPathComponent() : nodeTableModel
113: .getPropertyFor(nodeForRow(row),
114: propertyForColumn(column));
115: }
116:
117: public boolean isCellEditable(int row, int column) {
118: if (column == 0) {
119: return true;
120: }
121:
122: Object o = getValueAt(row, column);
123:
124: if (o == null) {
125: return false;
126: }
127:
128: if (o instanceof Node.Property) {
129: return ((Node.Property) o).canWrite();
130: }
131:
132: return false;
133: }
134:
135: public void setValueAt(Object value, int row, int column) {
136: }
137:
138: /* Listener for synchronizing tree and table model.
139: */
140: class Listener implements TreeExpansionListener, TreeModelListener,
141: TableModelListener, Runnable {
142: // selection paths stored for restore after update
143: TreePath[] tps = null;
144:
145: ///////// TreeExpansionListener
146: public void treeExpanded(TreeExpansionEvent event) {
147: updateNodes();
148: }
149:
150: public void treeCollapsed(TreeExpansionEvent event) {
151: updateNodes();
152: }
153:
154: ///////////// TreeModelListener
155: // Install a TreeModelListener that can update the table when
156: // tree changes. We use delayedUpdateNodes as we can
157: // not be guaranteed the tree will have finished processing
158: // the event before us.
159: public void treeNodesChanged(TreeModelEvent e) {
160: delayedUpdateNodes(e);
161: }
162:
163: public void treeNodesInserted(TreeModelEvent e) {
164: delayedUpdateNodes(e);
165: }
166:
167: public void treeNodesRemoved(TreeModelEvent e) {
168: delayedUpdateNodes(e);
169: }
170:
171: public void treeStructureChanged(TreeModelEvent e) {
172: // bugfix #23757, store selection paths
173: tps = tree.getSelectionPaths();
174:
175: // bugfix #30355, don't restore selection when the tree root changed
176: // (see javadoc TreeModelListener.treeStructureChanged)
177: if ((e.getPath().length == 1)
178: && !e.getTreePath().equals(e.getPath()[0])) {
179: tps = null;
180: }
181:
182: delayedUpdateNodes(e);
183: }
184:
185: ///////// TableModelListener
186: public void tableChanged(TableModelEvent e) {
187: int c = e.getColumn();
188: int column = (c == TableModelEvent.ALL_COLUMNS) ? TableModelEvent.ALL_COLUMNS
189: : (c + 1);
190: fireTableChanged(new TableModelEvent(
191: TreeTableModelAdapter.this , e.getFirstRow(), e
192: .getLastRow(), column, e.getType()));
193: }
194:
195: /**
196: * Invokes fireTableDataChanged after all the pending events have been processed.
197: */
198: protected void delayedUpdateNodes(TreeModelEvent e) {
199: // Something like this can be used for updating tree column name ?!
200: //if (tree.getModel().getRoot().equals(e.getTreePath().getLastPathComponent())) {
201: // fireTableStructureChanged();
202: //}
203: SwingUtilities.invokeLater(this );
204: }
205:
206: public void run() {
207: updateNodes();
208: }
209:
210: private void updateNodes() {
211: Node[] nodes = new Node[tree.getRowCount()];
212:
213: for (int i = 0; i < tree.getRowCount(); i++) {
214: nodes[i] = Visualizer.findNode(tree.getPathForRow(i)
215: .getLastPathComponent());
216: }
217:
218: setNodes(nodes);
219:
220: // retore selection paths
221: if (tps != null) {
222: tree.setSelectionPaths(tps);
223: tps = null;
224: }
225: }
226: }
227: }
|