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 java.util.concurrent.CopyOnWriteArrayList;
044: import org.openide.nodes.Node;
045: import org.openide.util.*;
046:
047: import java.beans.*;
048:
049: import java.lang.ref.Reference;
050: import java.lang.ref.WeakReference;
051:
052: import javax.swing.*;
053: import javax.swing.event.*;
054: import javax.swing.tree.*;
055:
056: /** Model for displaying the nodes in tree.
057: *
058: * @author Jaroslav Tulach
059: */
060: public class NodeTreeModel extends DefaultTreeModel {
061: static final long serialVersionUID = 1900670294524747212L;
062:
063: /** listener used to listen to changes in trees */
064: private transient Listener listener;
065:
066: // Workaround for JDK issue 6472844 (NB #84970)
067: // second part is in the listener and third in the TreeView
068: private CopyOnWriteArrayList<TreeView> views = new CopyOnWriteArrayList<TreeView>();
069:
070: void addView(TreeView tw) {
071: views.add(tw);
072: }
073:
074: /** Creates new NodeTreeModel
075: */
076: public NodeTreeModel() {
077: super (VisualizerNode.EMPTY, true);
078: }
079:
080: /** Creates new NodeTreeModel
081: * @param root the root of the model
082: */
083: public NodeTreeModel(Node root) {
084: super (VisualizerNode.EMPTY, true);
085: setNode(root);
086: }
087:
088: /** Changes the root of the model. This is thread safe method.
089: * @param root the root of the model
090: */
091: public void setNode(final Node root) {
092: Mutex.EVENT.readAccess(new Runnable() {
093: public void run() {
094: VisualizerNode v = (VisualizerNode) getRoot();
095: VisualizerNode nr = VisualizerNode.getVisualizer(null,
096: root);
097:
098: if (v == nr) {
099: // no change
100: return;
101: }
102:
103: v.removeNodeModel(listener());
104:
105: nr.addNodeModel(listener());
106: setRoot(nr);
107: }
108: });
109: }
110:
111: /** Getter for the listener. Only from AWT-QUEUE.
112: */
113: private Listener listener() {
114: if (listener == null) {
115: listener = new Listener(this );
116: }
117:
118: return listener;
119: }
120:
121: /**
122: * This sets the user object of the TreeNode identified by path
123: * and posts a node changed. If you use custom user objects in
124: * the TreeModel you'returngoing to need to subclass this and
125: * set the user object of the changed node to something meaningful.
126: */
127: public void valueForPathChanged(TreePath path, Object newValue) {
128: if (path == null) {
129: return;
130: }
131:
132: Object o = path.getLastPathComponent();
133:
134: if (o instanceof VisualizerNode) {
135: nodeChanged((VisualizerNode) o);
136:
137: return;
138: }
139:
140: MutableTreeNode aNode = (MutableTreeNode) o;
141:
142: aNode.setUserObject(newValue);
143: nodeChanged(aNode);
144: }
145:
146: /** The listener */
147: private static final class Listener implements NodeModel {
148: /** weak reference to the model */
149: private Reference<NodeTreeModel> model;
150:
151: /** Constructor.
152: */
153: public Listener(NodeTreeModel m) {
154: model = new WeakReference<NodeTreeModel>(m);
155: }
156:
157: /** Getter for the model or null.
158: */
159: private NodeTreeModel get(VisualizerEvent ev) {
160: NodeTreeModel m = model.get();
161:
162: if ((m == null) && (ev != null)) {
163: ev.getVisualizer().removeNodeModel(this );
164:
165: return null;
166: }
167:
168: return m;
169: }
170:
171: /** Notification of children addded event. Modifies the list of nodes
172: * and fires info to all listeners.
173: */
174: public void added(VisualizerEvent.Added ev) {
175: NodeTreeModel m = get(ev);
176:
177: if (m == null) {
178: return;
179: }
180:
181: m.nodesWereInserted(ev.getVisualizer(), ev.getArray());
182: }
183:
184: /** Notification that children has been removed. Modifies the list of nodes
185: * and fires info to all listeners.
186: */
187: public void removed(VisualizerEvent.Removed ev) {
188: NodeTreeModel m = get(ev);
189:
190: if (m == null) {
191: return;
192: }
193:
194: for (TreeView tw : m.views)
195: tw.removedNodes(ev.removed);
196:
197: m.nodesWereRemoved(ev.getVisualizer(), ev.getArray(),
198: ev.removed.toArray());
199: }
200:
201: /** Notification that children has been reordered. Modifies the list of nodes
202: * and fires info to all listeners.
203: */
204: public void reordered(VisualizerEvent.Reordered ev) {
205: NodeTreeModel m = get(ev);
206:
207: if (m == null) {
208: return;
209: }
210:
211: m.nodeStructureChanged(ev.getVisualizer());
212: }
213:
214: /** Update a visualizer (change of name, icon, description, etc.)
215: */
216: public void update(VisualizerNode v) {
217: NodeTreeModel m = get(null);
218:
219: if (m == null) {
220: return;
221: }
222:
223: m.nodeChanged(v);
224: }
225:
226: /** Notification about large change in the sub tree
227: */
228: public void structuralChange(VisualizerNode v) {
229: NodeTreeModel m = get(null);
230:
231: if (m == null) {
232: return;
233: }
234:
235: m.nodeStructureChanged(v);
236: }
237: }
238: }
|