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: * The Original Software is NetBeans. The Initial Developer of the Original
026: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
027: * Microsystems, Inc. All Rights Reserved.
028: *
029: * If you wish your version of this file to be governed by only the CDDL
030: * or only the GPL Version 2, indicate your decision by adding
031: * "[Contributor] elects to include this software in this distribution
032: * under the [CDDL or GPL Version 2] license." If you do not indicate a
033: * single choice of license, a recipient has the option to distribute
034: * your version of this file under either the CDDL, the GPL Version 2 or
035: * to extend the choice of license to its licensees as provided above.
036: * However, if you add GPL Version 2 code and therefore, elected the GPL
037: * Version 2 license, then the option applies only if the new code is
038: * made subject to such option by the copyright holder.
039: */
040:
041: package org.netbeans.lib.profiler.ui.components.treetable;
042:
043: import org.netbeans.lib.profiler.results.CCTNode;
044: import org.netbeans.lib.profiler.ui.components.JTreeTable;
045: import java.util.Enumeration;
046: import java.util.Vector;
047: import javax.swing.*;
048: import javax.swing.event.TreeExpansionEvent;
049: import javax.swing.event.TreeExpansionListener;
050: import javax.swing.event.TreeModelEvent;
051: import javax.swing.event.TreeModelListener;
052: import javax.swing.table.AbstractTableModel;
053: import javax.swing.tree.TreePath;
054:
055: public class TreeTableModelAdapter extends AbstractTableModel {
056: //~ Instance fields ----------------------------------------------------------------------------------------------------------
057:
058: protected AbstractTreeTableModel treeTableModel;
059: protected JTree tree;
060: protected JTreeTable treeTable;
061:
062: //~ Constructors -------------------------------------------------------------------------------------------------------------
063:
064: /**
065: * Constructs a TreeTableModelAdapter, bridging the given treeTable and the model
066: *
067: * @param treeTableModel the model to use
068: * @param treeTable the table which is going to use this model
069: */
070: public TreeTableModelAdapter(AbstractTreeTableModel treeTableModel,
071: JTreeTable treeTable) {
072: this .treeTable = treeTable;
073: this .tree = treeTable.getTree();
074: this .treeTableModel = treeTableModel;
075:
076: tree.addTreeExpansionListener(new TreeExpansionListener() {
077: // Don't use fireTableRowsInserted() here; the selection model
078: // would get updated twice.
079: public void treeExpanded(TreeExpansionEvent event) {
080: TreePath[] selectedPaths = tree.getSelectionPaths();
081: fireTableDataChanged();
082: tree.setSelectionPaths(selectedPaths);
083: }
084:
085: public void treeCollapsed(TreeExpansionEvent event) {
086: TreePath[] selectedPaths = tree.getSelectionPaths();
087: fireTableDataChanged();
088: tree.setSelectionPaths(selectedPaths);
089: }
090: });
091:
092: // Install a TreeModelListener that can updateState the table when
093: // tree changes. We use delayedFireTableDataChanged as we can
094: // not be guaranteed the tree will have finished processing
095: // the event before us.
096: treeTableModel.addTreeModelListener(new TreeModelListener() {
097: public void treeNodesChanged(TreeModelEvent e) {
098: delayedFireTableDataChanged();
099: }
100:
101: public void treeNodesInserted(TreeModelEvent e) {
102: delayedFireTableDataChanged();
103: }
104:
105: public void treeNodesRemoved(TreeModelEvent e) {
106: delayedFireTableDataChanged();
107: }
108:
109: public void treeStructureChanged(TreeModelEvent e) {
110: delayedFireTableDataChanged();
111: }
112: });
113: }
114:
115: //~ Methods ------------------------------------------------------------------------------------------------------------------
116:
117: /**
118: * TableModel wrapper, passes it through to the model after
119: * fetching the right TreeTableNode for the given row.
120: */
121: public boolean isCellEditable(int row, int column) {
122: return treeTableModel.isCellEditable(nodeForRow(row), column);
123: }
124:
125: /**
126: * TableModel wrapper, passes it through to the model.
127: */
128: public Class getColumnClass(int column) {
129: return treeTableModel.getColumnClass(column);
130: }
131:
132: /**
133: * TableModel wrapper, passes it through to the model.
134: */
135: public int getColumnCount() {
136: return treeTableModel.getColumnCount();
137: }
138:
139: /**
140: * TableModel wrapper, passes it through to the model.
141: */
142: public String getColumnName(int column) {
143: return treeTableModel.getColumnName(column);
144: }
145:
146: /**
147: * Returns a vector of open paths in the tree, can be used to
148: * re-open the paths in a tree after a call to 'treeStructureChanged'
149: * (which causes all open paths to collapse)
150: */
151: public Vector getExpandedPaths() {
152: Enumeration expanded = tree
153: .getExpandedDescendants(getRootPath());
154: Vector paths = new Vector();
155:
156: if (expanded != null) {
157: while (expanded.hasMoreElements()) {
158: paths.add(expanded.nextElement());
159: }
160: }
161:
162: return paths;
163: }
164:
165: /**
166: * Returns the (tree)path to the root of the model.
167: *
168: * @return
169: */
170: public TreePath getRootPath() {
171: return new TreePath(treeTableModel
172: .getPathToRoot((CCTNode) treeTableModel.getRoot()));
173: }
174:
175: /**
176: * TableModel wrapper, passes it through to the model.
177: */
178: public int getRowCount() {
179: return tree.getRowCount();
180: }
181:
182: /**
183: * TableModel wrapper, passes it through to the model after
184: * fetching the right TreeTableNode for the given row.
185: */
186: public void setValueAt(Object value, int row, int column) {
187: treeTableModel.setValueAt(value, nodeForRow(row), column);
188: }
189:
190: /**
191: * Returns the object on the given row and column.
192: */
193: public Object getValueAt(int row, int column) {
194: Object j = treeTableModel.getValueAt(nodeForRow(row), column);
195:
196: return j;
197: }
198:
199: /**
200: * Opens the root node.
201: */
202: public void expandRoot() {
203: tree.expandPath(getRootPath());
204: }
205:
206: /**
207: * Restores the given open paths on the treeModel.
208: *
209: * @param paths a Vector of TreePaths which are going to be opened.
210: */
211: public void restoreExpandedPaths(Vector paths) {
212: Enumeration e = paths.elements();
213:
214: while (e.hasMoreElements()) {
215: TreePath path = (TreePath) e.nextElement();
216: tree.expandPath(path);
217: }
218: }
219:
220: public void updateTreeTable() {
221: SwingUtilities.invokeLater(new Runnable() {
222: public void run() {
223: Vector pathState = getExpandedPaths();
224:
225: TreePath[] selectedPaths = tree.getSelectionPaths();
226: treeTableModel.fireTreeStructureChanged(this ,
227: treeTableModel
228: .getPathToRoot((CCTNode) treeTableModel
229: .getRoot()), null, null);
230: tree.setSelectionPaths(selectedPaths);
231:
232: restoreExpandedPaths(pathState);
233:
234: treeTable.getTableHeader().repaint();
235:
236: delayedFireTableDataChanged();
237: }
238: });
239: }
240:
241: /**
242: * Invokes fireTableDataChanged after all the pending events have been
243: * processed. SwingUtilities.invokeLater is used to handle this.
244: */
245: protected void delayedFireTableDataChanged() {
246: SwingUtilities.invokeLater(new Runnable() {
247: public void run() {
248: TreePath[] selectedPaths = tree.getSelectionPaths();
249: fireTableDataChanged();
250: tree.setSelectionPaths(selectedPaths);
251: }
252: });
253: }
254:
255: /**
256: * Returns the object (TreeTableNode) on the given row in the tree.
257: */
258: protected Object nodeForRow(int row) {
259: TreePath treePath = tree.getPathForRow(row);
260:
261: if (treePath != null) {
262: return treePath.getLastPathComponent();
263: } else {
264: return null;
265: }
266: }
267: }
|