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.explorer.*;
044: import org.openide.explorer.ExplorerManager.Provider;
045: import org.openide.nodes.Node;
046: import org.openide.nodes.Node.Property;
047:
048: import java.beans.*;
049:
050: import java.io.*;
051:
052: import javax.swing.*;
053:
054: /** Explorer view based on a combo box.
055: * <p>
056: * This class is a <q>view</q>
057: * to use it properly you need to add it into a component which implements
058: * {@link Provider}. Good examples of that can be found
059: * in {@link ExplorerUtils}. Then just use
060: * {@link Provider#getExplorerManager} call to get the {@link ExplorerManager}
061: * and control its state.
062: * </p>
063: * <p>
064: * There can be multiple <q>views</q> under one container implementing {@link Provider}. Select from
065: * range of predefined ones or write your own:
066: * </p>
067: * <ul>
068: * <li>{@link org.openide.explorer.view.BeanTreeView} - shows a tree of nodes</li>
069: * <li>{@link org.openide.explorer.view.ContextTreeView} - shows a tree of nodes without leaf nodes</li>
070: * <li>{@link org.openide.explorer.view.ListView} - shows a list of nodes</li>
071: * <li>{@link org.openide.explorer.view.IconView} - shows a rows of nodes with bigger icons</li>
072: * <li>{@link org.openide.explorer.view.ChoiceView} - creates a combo box based on the explored nodes</li>
073: * <li>{@link org.openide.explorer.view.TreeTableView} - shows tree of nodes together with a set of their {@link Property}</li>
074: * <li>{@link org.openide.explorer.view.MenuView} - can create a {@link JMenu} structure based on structure of {@link Node}s</li>
075: * </ul>
076: * <p>
077: * All of these views use {@link ExplorerManager#find} to walk up the AWT hierarchy and locate the
078: * {@link ExplorerManager} to use as a controler. They attach as listeners to
079: * it and also call its setter methods to update the shared state based on the
080: * user action. Not all views make sence together, but for example
081: * {@link org.openide.explorer.view.ContextTreeView} and {@link org.openide.explorer.view.ListView} were designed to complement
082: * themselves and behaves like windows explorer. The {@link org.openide.explorer.propertysheet.PropertySheetView}
083: * for example should be able to work with any other view.
084: * </p>
085: * @author Jaroslav Tulach
086: */
087: public class ChoiceView extends JComboBox implements Externalizable {
088: /** generated Serialized Version UID */
089: static final long serialVersionUID = 2522310031223476067L;
090:
091: /** The local reference to the explorerManager. It is transient
092: * because it will be reset in initializeManager() after deserialization.*/
093: transient private ExplorerManager manager;
094:
095: /** Listens on ExplorerManager. */
096: transient private PropertyIL iListener;
097:
098: /** model to use */
099: transient private NodeListModel model;
100:
101: /** Value of property showExploredContext. */
102: private boolean showExploredContext = true;
103:
104: // init .................................................................................
105:
106: /** Default constructor. */
107: public ChoiceView() {
108: super ();
109: initializeChoice();
110: }
111:
112: /** Initialize view. */
113: private void initializeChoice() {
114: setRenderer(new NodeRenderer());
115:
116: setModel(model = createModel());
117:
118: iListener = new PropertyIL();
119: }
120:
121: // XXX [PENDING] setting new model via setModel() is in fact ignored, see model
122: // field -> which 'replaces' normal combo model thus the underlying one making
123: // useless.
124:
125: /*
126: * Write view's state to output stream.
127: */
128: public void writeExternal(ObjectOutput out) throws IOException {
129: out.writeObject(showExploredContext ? Boolean.TRUE
130: : Boolean.FALSE);
131: }
132:
133: /*
134: * Reads view's state form output stream.
135: */
136: public void readExternal(ObjectInput in) throws IOException,
137: ClassNotFoundException {
138: showExploredContext = ((Boolean) in.readObject())
139: .booleanValue();
140: }
141:
142: //
143: // To override
144: //
145:
146: /** Creates the model that this view should show.
147: */
148: protected NodeListModel createModel() {
149: return new NodeListModel();
150: }
151:
152: // main methods .........................................................................
153:
154: /** Set showing of explored contexts.
155: * @param b <code>true</code> to show the explored context, <code>false</code> the root context
156: */
157: public void setShowExploredContext(boolean b) {
158: showExploredContext = b;
159: updateChoice();
160: }
161:
162: /**
163: * Get explored context toggle.
164: * @return whether currently showing explored context (default <code>false</code>)
165: */
166: public boolean getShowExploredContext() {
167: return showExploredContext;
168: }
169:
170: // main methods .........................................................................
171:
172: /* Initializes view.
173: */
174: public void addNotify() {
175: manager = ExplorerManager.find(this );
176: manager.addVetoableChangeListener(iListener);
177: manager.addPropertyChangeListener(iListener);
178:
179: updateChoice();
180:
181: addActionListener(iListener);
182:
183: super .addNotify();
184: }
185:
186: /* Deinitializes view.
187: */
188: public void removeNotify() {
189: super .removeNotify();
190:
191: removeActionListener(iListener);
192:
193: manager.removeVetoableChangeListener(iListener);
194: manager.removePropertyChangeListener(iListener);
195: }
196:
197: private void updateSelection() {
198: Node[] nodes = manager.getSelectedNodes();
199:
200: if (nodes.length > 0) {
201: setSelectedItem(VisualizerNode
202: .getVisualizer(null, nodes[0]));
203: } else {
204: setSelectedItem(showExploredContext ? manager
205: .getExploredContext() : manager.getRootContext());
206: }
207: }
208:
209: private void updateChoice() {
210: if (showExploredContext) {
211: model.setNode(manager.getExploredContext());
212: } else {
213: model.setNode(manager.getRootContext());
214: }
215:
216: updateSelection();
217: }
218:
219: // innerclasses .........................................................................
220:
221: /* The inner adaptor class for listening to the ExplorerManager's property and vetoable changes. */
222: final class PropertyIL extends Object implements
223: PropertyChangeListener, VetoableChangeListener,
224: java.awt.event.ActionListener {
225: public void vetoableChange(PropertyChangeEvent evt)
226: throws PropertyVetoException {
227: if (ExplorerManager.PROP_SELECTED_NODES.equals(evt
228: .getPropertyName())) {
229: Node[] nodes = (Node[]) evt.getNewValue();
230:
231: if (nodes.length > 1) {
232: throw new PropertyVetoException("", evt); // we do not allow multiple selection // NOI18N
233: }
234: }
235: }
236:
237: public void propertyChange(PropertyChangeEvent evt) {
238: ChoiceView.this .removeActionListener(this );
239:
240: try {
241: if (ExplorerManager.PROP_SELECTED_NODES.equals(evt
242: .getPropertyName())) {
243: Node[] selectedNodes = (Node[]) evt.getNewValue();
244: updateSelection();
245:
246: return;
247: }
248:
249: if (!showExploredContext
250: && ExplorerManager.PROP_ROOT_CONTEXT.equals(evt
251: .getPropertyName())) {
252: updateChoice();
253:
254: return;
255: }
256:
257: if (showExploredContext
258: && ExplorerManager.PROP_EXPLORED_CONTEXT
259: .equals(evt.getPropertyName())) {
260: updateChoice();
261:
262: return;
263: }
264: } finally {
265: ChoiceView.this .addActionListener(this );
266: }
267: }
268:
269: public void actionPerformed(
270: java.awt.event.ActionEvent actionEvent) {
271: int s = getSelectedIndex();
272:
273: if ((s < 0) || (s >= model.getSize())) {
274: return;
275: }
276:
277: Node n = Visualizer.findNode(model.getElementAt(s));
278:
279: manager.removeVetoableChangeListener(this );
280: manager.removePropertyChangeListener(this );
281:
282: try {
283: manager.setSelectedNodes(new Node[] { n });
284: } catch (PropertyVetoException ex) {
285: updateChoice(); // no selection change allowed
286: } finally {
287: manager.addVetoableChangeListener(this);
288: manager.addPropertyChangeListener(this);
289: }
290: }
291: }
292: }
|