0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.netbeans.core;
0043:
0044: import java.awt.*;
0045: import java.beans.*;
0046: import java.io.ObjectInput;
0047: import java.io.IOException;
0048: import java.util.*;
0049: import java.util.List;
0050: import java.util.logging.Level;
0051: import java.util.logging.Logger;
0052: import java.util.prefs.PreferenceChangeEvent;
0053: import java.util.prefs.PreferenceChangeListener;
0054:
0055: import javax.swing.*;
0056: import javax.swing.event.*;
0057: import org.openide.explorer.*;
0058: import org.openide.explorer.view.BeanTreeView;
0059: import org.openide.explorer.view.TreeView;
0060: import org.openide.nodes.Node;
0061: import org.openide.nodes.NodeListener;
0062: import org.openide.util.Exceptions;
0063: import org.openide.util.HelpCtx;
0064: import org.openide.util.NbBundle;
0065: import org.openide.util.Mutex;
0066: import org.openide.util.WeakListeners;
0067: import org.openide.windows.CloneableTopComponent;
0068: import org.openide.windows.Mode;
0069: import org.openide.windows.TopComponent;
0070: import org.openide.windows.WindowManager;
0071:
0072: /** Main explorer - the class remains here for backward compatibility
0073: * with older serialization protocol. Its responsibilty is also
0074: * to listen to the changes of "roots" nodes and open / close
0075: * explorer's top components properly.
0076: *
0077: * @author Ian Formanek, David Simonek, Jaroslav Tulach
0078: */
0079: public final class NbMainExplorer extends CloneableTopComponent {
0080:
0081: static final long serialVersionUID = 6021472310669753679L;
0082: // static final long serialVersionUID=-9070275145808944151L;
0083:
0084: /** holds list of roots (Node) */
0085: private List<Node> prevRoots;
0086:
0087: /** assignes to each node one top component holding explorer panel
0088: * (Node, ExplorerTab) */
0089: private Map<Node, ExplorerTab> rootsToTCs;
0090:
0091: /** Listener which tracks changes on the root nodes (which are displayed as tabs) */
0092: private transient RootsListener rootsListener;
0093:
0094: /** Minimal initial height of this top component */
0095: public static final int MIN_HEIGHT = 150;
0096: /** Default width of main explorer */
0097: public static final int DEFAULT_WIDTH = 350;
0098:
0099: /** Mapping module tabs to their root node classes */
0100: private static Map<Node, ModuleTab> moduleTabs;
0101:
0102: /** Default constructor */
0103: public NbMainExplorer() {
0104: // System.out.println("NbMainExplorer.<init>");
0105: // listening on changes of roots
0106: rootsListener = new RootsListener();
0107: NbPlaces p = NbPlaces.getDefault();
0108: p.addChangeListener(WeakListeners.change(rootsListener, p));
0109:
0110: refreshRoots();
0111: }
0112:
0113: public HelpCtx getHelpCtx() {
0114: return ExplorerUtils.getHelpCtx(getActivatedNodes(),
0115: new HelpCtx(NbMainExplorer.class));
0116: }
0117:
0118: /** Finds module tab in mapping of module tabs to their root node classes.
0119: * If it is not found it is added when parameter tc is not null. When parameter
0120: * tc is null new ModuleTab is created using default constructor. */
0121: private static synchronized ModuleTab findModuleTab(Node root,
0122: ModuleTab tc) {
0123: System.out.println("NbMainExplorer.findModuleTab " + root);
0124: if (moduleTabs == null) {
0125: moduleTabs = new WeakHashMap<Node, ModuleTab>(5);
0126: }
0127: ModuleTab tab = moduleTabs.get(root);
0128: if (tab != null) {
0129: return tab;
0130: } else {
0131: if (tc != null) {
0132: moduleTabs.put(root, tc);
0133: return tc;
0134: } else {
0135: ModuleTab newTC = new ModuleTab();
0136: moduleTabs.put(root, newTC);
0137: return newTC;
0138: }
0139: }
0140: }
0141:
0142: /** Overriden to open all top components of main explorer and
0143: * close this top component, as this top component exists only because of
0144: * backward serialization compatibility.
0145: * Performed with delay, when WS is in consistent state. */
0146: @SuppressWarnings("deprecation")
0147: public void open(org.openide.windows.Workspace workspace) {
0148: doOpen(workspace);
0149: }
0150:
0151: @SuppressWarnings("deprecation")
0152: private void doOpen(org.openide.windows.Workspace workspace) {
0153: if (workspace == null) {
0154: // refresh roots request
0155: refreshRoots();
0156: } else {
0157: // old explorer open request
0158: super .open(workspace);
0159: close(workspace);
0160: // now open new main explorer top components
0161: NbMainExplorer singleton = NbMainExplorer.getExplorer();
0162: singleton.openRoots(workspace);
0163: }
0164: }
0165:
0166: /** Open all main explorer's top components on current workspace */
0167: @SuppressWarnings("deprecation")
0168: public void openRoots() {
0169: openRoots(WindowManager.getDefault().getCurrentWorkspace());
0170: }
0171:
0172: /** Open all main explorer's top components on given workspace */
0173: @SuppressWarnings("deprecation")
0174: public void openRoots(org.openide.windows.Workspace workspace) {
0175: // save the tab we should activate
0176: ExplorerTab toBeActivated = MainTab.lastActivated;
0177: // perform open operation
0178: refreshRoots();
0179: Node[] rootsArray = getRoots().toArray(new Node[0]);
0180: TopComponent tc = null;
0181: for (int i = 0; i < rootsArray.length; i++) {
0182: tc = getRootPanel(rootsArray[i]);
0183: if (tc != null) {
0184: tc.open(workspace);
0185: }
0186: }
0187: // set focus to saved last activated tab or repository tab
0188: if (toBeActivated == null) {
0189: toBeActivated = getRootPanel(rootsArray[0]);
0190: }
0191:
0192: //Bugfix #9352 20 Feb 2001 by Marek Slama
0193: //requestFocus called directly on mode - it sets
0194: //deferred request so that requestFocus is performed
0195: //on correct workspace when component is shown.
0196: //Delayed call of requestFocus on ExplorerTab
0197: //was performed on incorrect workspace.
0198: /*final ExplorerTab localActivated = toBeActivated;
0199: SwingUtilities.invokeLater(new Runnable () {
0200: public void run () {
0201: System.out.println("++*** localActivated:" + localActivated);
0202: if (localActivated != null) {
0203: System.out.println("++*** Call of localActivated.requestFocus()");
0204: localActivated.requestFocus();
0205: }
0206: }
0207: });*/
0208:
0209: //Bugfix #9815: added check if toBeActivated is null before
0210: //request focus is called.
0211: //Bugfix #17956: Make sure that findMode is called after top component
0212: //is added to mode.
0213: if (SwingUtilities.isEventDispatchThread()) {
0214: if (toBeActivated != null) {
0215: Mode mode = workspace.findMode(toBeActivated);
0216: if (mode != null) {
0217: toBeActivated.requestActive();
0218: }
0219: }
0220: } else {
0221: if (toBeActivated != null) {
0222: final ExplorerTab localActivated = toBeActivated;
0223: final org.openide.windows.Workspace localWorkspace = workspace;
0224: SwingUtilities.invokeLater(new Runnable() {
0225: public void run() {
0226: Mode mode = localWorkspace
0227: .findMode(localActivated);
0228: if (mode != null) {
0229: localActivated.requestActive();
0230: }
0231: }
0232: });
0233: }
0234: }
0235: //End of bugfix #9815
0236: //End of bugfix #9352
0237: }
0238:
0239: /** Refreshes current state of main explorer's top components, so they
0240: * will reflect new nodes. Called when content of "roots" nodes is changed.
0241: */
0242: @SuppressWarnings("deprecation")
0243: final void refreshRoots() {
0244: List<Node> curRoots = getRoots();
0245: // first of all we have to close top components for
0246: // the roots that are no longer present in the roots content
0247: if (prevRoots != null) {
0248: HashSet<Node> toRemove = new HashSet<Node>(prevRoots);
0249: toRemove.removeAll(curRoots);
0250: // ^^^ toRemove now contains only roots that are used no more
0251: for (Map.Entry<Node, ExplorerTab> me : rootsToTCs
0252: .entrySet()) {
0253: Node r = me.getKey();
0254: if (toRemove.contains(r)) {
0255: // close top component asociated with this root context
0256: // on all workspaces
0257: closeEverywhere(me.getValue());
0258: }
0259: }
0260: } else {
0261: // initialize previous roots list
0262: prevRoots();
0263: }
0264:
0265: // create and open top components for newly added roots
0266: List workspaces = whereOpened(rootsToTCs().values().toArray(
0267: new ExplorerTab[0]));
0268: for (Iterator iter = curRoots.iterator(); iter.hasNext();) {
0269: Node r = (Node) iter.next();
0270: ExplorerTab tc = getRootPanel(r);
0271: if (tc == null) {
0272: // newly added root -> create new TC and open it on every
0273: // workspace where some top compoents from main explorer
0274: // are already opened
0275: tc = createTC(r, false);
0276:
0277: for (Iterator iter2 = workspaces.iterator(); iter2
0278: .hasNext();) {
0279: tc.open((org.openide.windows.Workspace) iter2
0280: .next());
0281: }
0282: }
0283: }
0284:
0285: // save roots for use during future changes
0286: prevRoots = curRoots;
0287: }
0288:
0289: /** Helper method - closes given top component on all workspaces
0290: * where it is opened */
0291: @SuppressWarnings("deprecation")
0292: private static void closeEverywhere(TopComponent tc) {
0293: org.openide.windows.Workspace[] workspaces = WindowManager
0294: .getDefault().getWorkspaces();
0295: for (int i = 0; i < workspaces.length; i++) {
0296: if (tc.isOpened(workspaces[i])) {
0297: tc.close(workspaces[i]);
0298: }
0299: }
0300: }
0301:
0302: /** Utility method - returns list of workspaces where at least one from
0303: * given list of top components is opened. */
0304: @SuppressWarnings("deprecation")
0305: private static List<org.openide.windows.Workspace> whereOpened(
0306: TopComponent[] tcs) {
0307: org.openide.windows.Workspace[] workspaces = WindowManager
0308: .getDefault().getWorkspaces();
0309: ArrayList<org.openide.windows.Workspace> result = new ArrayList<org.openide.windows.Workspace>(
0310: workspaces.length);
0311: for (int i = 0; i < workspaces.length; i++) {
0312: for (int j = 0; j < tcs.length; j++) {
0313: if (tcs[j].isOpened(workspaces[i])) {
0314: result.add(workspaces[i]);
0315: break;
0316: }
0317: }
0318: }
0319: return result;
0320: }
0321:
0322: //Temporary solution for bugfix #9352. There is currently
0323: //no way how to select given tab other than focused in split container.
0324: //It requires better solution.
0325: //Method changed from private to public so it can be used in DefaultCreator.
0326:
0327: /** @return List of "root" nodes which has following structure:<br>
0328: * First goes repository, than root nodes added by modules and at last
0329: * runtime root node */
0330: public static List<Node> getRoots() {
0331: NbPlaces places = NbPlaces.getDefault();
0332: // build the list of roots
0333: LinkedList<Node> result = new LinkedList<Node>();
0334:
0335: //repository goes first
0336: /*
0337: #47032: Netbeans hangs for 30 seconds during startup - so commented out
0338: Moreover there isn't any ExlorerTab dedicated to show this repository root.
0339: result.add(RepositoryNodeFactory.getDefault().repository(DataFilter.ALL));
0340: */
0341:
0342: // roots added by modules (javadoc etc...)
0343: result.addAll(Arrays.asList(places.roots()));
0344: // runtime
0345: result.add(places.environment());
0346:
0347: return result;
0348: }
0349:
0350: /** Creates a top component dedicated to exploration of
0351: * specified node, which will serve as root context */
0352: private ExplorerTab createTC(Node rc, boolean deserialize) {
0353: // switch according to the type of the root context
0354: MainTab panel = null;
0355: NbPlaces places = NbPlaces.getDefault();
0356:
0357: if (rc.equals(places.environment())) {
0358: // default tabs
0359: if (deserialize) {
0360: TopComponent tc = WindowManager.getDefault()
0361: .findTopComponent("runtime"); // NOI18N
0362: if (tc != null) {
0363: if (tc instanceof MainTab) {
0364: panel = (MainTab) tc;
0365: } else {
0366: //Incorrect settings file?
0367: IllegalStateException exc = new IllegalStateException(
0368: "Incorrect settings file. Unexpected class returned." // NOI18N
0369: + " Expected:"
0370: + MainTab.class.getName() // NOI18N
0371: + " Returned:"
0372: + tc.getClass().getName()); // NOI18N
0373: Logger
0374: .getLogger(
0375: NbMainExplorer.class.getName())
0376: .log(Level.WARNING, null, exc);
0377: panel = MainTab.getDefaultMainTab();
0378: }
0379: } else {
0380: panel = MainTab.getDefaultMainTab();
0381: }
0382: } else {
0383: panel = MainTab.getDefaultMainTab();
0384: }
0385: panel.setRootContext(rc, false);
0386: } else {
0387: // tabs added by modules
0388: //We cannot use findTopComponent here because we do not know unique
0389: //TC ID ie. proper deserialization of such TC will not work.
0390: panel = NbMainExplorer.findModuleTab(rc, null);
0391: panel.setRootContext(rc);
0392: }
0393:
0394: rootsToTCs().put(rc, panel);
0395: return panel;
0396: }
0397:
0398: /** Safe accessor for root context - top component map. */
0399: private Map<Node, ExplorerTab> rootsToTCs() {
0400: if (rootsToTCs == null) {
0401: rootsToTCs = new HashMap<Node, ExplorerTab>(7);
0402: }
0403: return rootsToTCs;
0404: }
0405:
0406: /** Safe accessor for list of previous root nodes */
0407: private List<Node> prevRoots() {
0408: if (prevRoots == null) {
0409: prevRoots = new LinkedList<Node>();
0410: }
0411: return prevRoots;
0412: }
0413:
0414: /** Deserialize this top component, sets as default.
0415: * Provided provided here only for backward compatibility
0416: * with older serialization protocol */
0417: public void readExternal(ObjectInput in) throws IOException,
0418: ClassNotFoundException {
0419: super .readExternal(in);
0420: //System.out.println("READING old main explorer..."); // NOI18N
0421: // read explorer panels (and managers)
0422: int cnt = in.readInt();
0423: for (int i = 0; i < cnt; i++) {
0424: in.readObject();
0425: }
0426: in.readObject();
0427: // read property sheet switcher state...
0428: in.readBoolean();
0429: in.readBoolean();
0430: in.readInt();
0431: in.readInt();
0432: }
0433:
0434: //Temporary solution for bugfix #9352. There is currently
0435: //no way how to select given tab other than focused in split container.
0436: //It requires better solution.
0437: //Method changed from package to public so it can be used in DefaultCreator.
0438:
0439: /** Finds the right panel for given node.
0440: * @return the panel or null if no such panel exists
0441: */
0442: public final ExplorerTab getRootPanel(Node root) {
0443: return rootsToTCs().get(root);
0444: }
0445:
0446: // -------------------------------------------------------------------------
0447: // Static methods
0448:
0449: /** Static method to obtains the shared instance of NbMainExplorer
0450: * @return the shared instance of NbMainExplorer
0451: */
0452: public static NbMainExplorer getExplorer() {
0453: if (explorer == null) {
0454: explorer = new NbMainExplorer();
0455: }
0456: return explorer;
0457: }
0458:
0459: /** @return The mode for main explorer on given workspace.
0460: * Creates explorer mode if no such mode exists on given workspace */
0461: @SuppressWarnings("deprecation")
0462: private static Mode explorerMode(
0463: org.openide.windows.Workspace workspace) {
0464: Mode result = workspace.findMode("explorer"); // NOI18N
0465: if (result == null) {
0466: // create explorer mode on current workspace
0467: String displayName = NbBundle.getBundle(
0468: NbMainExplorer.class)
0469: .getString("CTL_ExplorerTitle");
0470: result = workspace
0471: .createMode(
0472: "explorer", // NOI18N
0473: displayName,
0474: NbMainExplorer.class
0475: .getResource("/org/netbeans/core/resources/frames/explorer.gif" // NOI18N
0476: ));
0477: }
0478: return result;
0479: }
0480:
0481: /** Shared instance of NbMainExplorer */
0482: private static NbMainExplorer explorer;
0483:
0484: /** Common explorer top component which composites bean tree view
0485: * to view given context. */
0486: public static class ExplorerTab extends
0487: org.netbeans.beaninfo.ExplorerPanel
0488: implements
0489: /*DeferredPerformer.DeferredCommand,*/TopComponent.Cloneable {
0490: static final long serialVersionUID = -8202452314155464024L;
0491: /** composited view */
0492: protected TreeView view;
0493: /** listeners to the root context and IDE settings */
0494: private PropertyChangeListener weakRcL;
0495: private NodeListener weakNRcL;
0496: private IDESettings ideSettings;
0497:
0498: private NodeListener rcListener;
0499: /** validity flag */
0500: private boolean valid = true;
0501: private boolean rootVis = true;
0502:
0503: /** Used by ModuleTab to set persistence type according
0504: * root context node persistence ability. */
0505: protected int persistenceType = TopComponent.PERSISTENCE_ALWAYS;
0506:
0507: public ExplorerTab() {
0508: super ();
0509: // complete initialization of composited explorer actions
0510: ideSettings = IDESettings.getInstance();
0511:
0512: getActionMap().put(
0513: "delete",
0514: ExplorerUtils.actionDelete(getExplorerManager(),
0515: ideSettings.getConfirmDelete()));
0516:
0517: IDESettings.getPreferences().addPreferenceChangeListener(
0518: new PreferenceChangeListener() {
0519: public void preferenceChange(
0520: PreferenceChangeEvent evt) {
0521: if (IDESettings.PROP_CONFIRM_DELETE
0522: .equals(evt.getKey())) {
0523: getActionMap()
0524: .put(
0525: "delete",
0526: ExplorerUtils
0527: .actionDelete(
0528: getExplorerManager(),
0529: ideSettings
0530: .getConfirmDelete()));
0531: }
0532: }
0533: });
0534: }
0535:
0536: /** Overriden to explicitely set persistence type of ExplorerTab
0537: * to PERSISTENCE_ALWAYS
0538: */
0539: public int getPersistenceType() {
0540: return TopComponent.PERSISTENCE_ALWAYS;
0541: }
0542:
0543: /** Initialize visual content of component */
0544: protected void componentShowing() {
0545: super .componentShowing();
0546:
0547: if (view == null) {
0548: view = initGui();
0549: view.setRootVisible(rootVis);
0550:
0551: view.getAccessibleContext().setAccessibleName(
0552: NbBundle.getBundle(NbMainExplorer.class)
0553: .getString("ACSN_ExplorerBeanTree"));
0554: view.getAccessibleContext().setAccessibleDescription(
0555: NbBundle.getBundle(NbMainExplorer.class)
0556: .getString("ACSD_ExplorerBeanTree"));
0557: }
0558: }
0559:
0560: /** Performs superclass addNotify code, then delegates to
0561: * componentShowing if component is used outside window system.
0562: * Needed for proper initialization.
0563: */
0564: public void addNotify() {
0565: super .addNotify();
0566: if (WindowManager.getDefault().findMode(this ) != null) {
0567: return;
0568: }
0569: componentShowing();
0570: }
0571:
0572: /** Transfer focus to view. */
0573: @SuppressWarnings("deprecation")
0574: public void requestFocus() {
0575: super .requestFocus();
0576: if (view != null) {
0577: view.requestFocus();
0578: }
0579: }
0580:
0581: /** Transfer focus to view. */
0582: @SuppressWarnings("deprecation")
0583: public boolean requestFocusInWindow() {
0584: super .requestFocusInWindow();
0585: if (view != null) {
0586: return view.requestFocusInWindow();
0587: } else {
0588: return false;
0589: }
0590: }
0591:
0592: /** Initializes gui of this component. Subclasses can override
0593: * this method to install their own gui.
0594: * @return Tree view that will serve as main view for this explorer.
0595: */
0596: protected TreeView initGui() {
0597: TreeView view = new BeanTreeView();
0598: view.setDragSource(true);
0599: setLayout(new BorderLayout());
0600: add(view);
0601: return view;
0602: }
0603:
0604: /** Ensures that component is valid before opening */
0605: @SuppressWarnings("deprecation")
0606: public void open(org.openide.windows.Workspace workspace) {
0607: setValidRootContext();
0608:
0609: super .open(workspace);
0610: }
0611:
0612: /** Sets new root context to view. Name, icon, tooltip
0613: * of this top component will be updated properly */
0614: public void setRootContext(Node rc) {
0615: Node oldRC = getExplorerManager().getRootContext();
0616: // remove old listener, if possible
0617: if (weakRcL != null) {
0618: oldRC.removePropertyChangeListener(weakRcL);
0619: }
0620: if (weakNRcL != null) {
0621: oldRC.removeNodeListener(weakNRcL);
0622: }
0623: getExplorerManager().setRootContext(rc);
0624: initializeWithRootContext(rc);
0625: }
0626:
0627: public void setRootContext(Node rc, boolean rootVisible) {
0628: rootVis = rootVisible;
0629: if (view != null) {
0630: view.setRootVisible(rootVisible);
0631: }
0632: setRootContext(rc);
0633: }
0634:
0635: // #16375. Not to try to serialize explored nodes which aren't
0636: // serializable (getHandle returns null).
0637: /** Adjusts this component persistence according
0638: * root context node persistence ability. */
0639: public void adjustComponentPersistence() {
0640: Node.Handle handle = getExplorerManager().getRootContext()
0641: .getHandle();
0642: if (handle == null) {
0643: // Not persistent.
0644: persistenceType = TopComponent.PERSISTENCE_NEVER;
0645: } else {
0646: // Persistent.
0647: persistenceType = TopComponent.PERSISTENCE_ONLY_OPENED;
0648: }
0649: }
0650:
0651: public Node getRootContext() {
0652: return getExplorerManager().getRootContext();
0653: }
0654:
0655: /** Deserialization of ExploreTab, if subclass overwrites this method it
0656: MUST call scheduleValidation() */
0657: public Object readResolve()
0658: throws java.io.ObjectStreamException {
0659: // put a request for later validation
0660: // we must do this here, because of ExplorerManager's deserialization.
0661: // Root context of ExplorerManager is validated AFTER all other
0662: // deserialization, so we must wait for it
0663: //Bugfix #17622, call of scheduleValidation() moved from
0664: //readExternal().
0665: scheduleValidation();
0666: return this ;
0667: }
0668:
0669: private void setValidRootContext() {
0670: if (!valid) {
0671: valid = true;
0672: validateRootContext();
0673: }
0674: }
0675:
0676: /** Validates root context of this top component after deserialization.
0677: * It is guaranteed that this method is called at a time when
0678: * getExplorerManager().getRootContext() call will return valid result.
0679: * Subclasses can override this method and peform further validation
0680: * or even set new root context instead of deserialized one.<br>
0681: * Default implementation just initializes top component with standard
0682: * deserialized root context. */
0683: protected void validateRootContext() {
0684: initializeWithRootContext(getExplorerManager()
0685: .getRootContext());
0686: }
0687:
0688: // Bugfix #5891 04 Sep 2001 by Jiri Rechtacek
0689: // the title is derived from the root context
0690: // it isn't changed by a selected node in the tree
0691: /** Called when the explored context changes.
0692: * Overriden - we don't want title to change in this style.
0693: */
0694: protected void updateTitle() {
0695: // set name by the root context
0696: setName(getExplorerManager().getRootContext()
0697: .getDisplayName());
0698: }
0699:
0700: private NodeListener rcListener() {
0701: if (rcListener == null) {
0702: rcListener = new RootContextListener();
0703: }
0704: return rcListener;
0705: }
0706:
0707: /** Initialize this top component properly with information
0708: * obtained from specified root context node */
0709: private void initializeWithRootContext(Node rc) {
0710: // update TC's attributes
0711: setIcon(rc.getIcon(BeanInfo.ICON_COLOR_16x16));
0712: setToolTipText(rc.getShortDescription());
0713: // bugfix #15136
0714: setName(rc.getDisplayName());
0715: updateTitle();
0716:
0717: if (weakRcL == null) {
0718: weakRcL = WeakListeners
0719: .propertyChange(rcListener(), rc);
0720: } else {
0721: rc.removePropertyChangeListener(weakRcL);
0722: }
0723: rc.addPropertyChangeListener(weakRcL);
0724:
0725: if (weakNRcL == null) {
0726: weakNRcL = org.openide.nodes.NodeOp.weakNodeListener(
0727: rcListener(), rc);
0728: } else {
0729: rc.removeNodeListener(weakNRcL);
0730: }
0731: rc.addNodeListener(weakNRcL);
0732: }
0733:
0734: // put a request for later validation
0735: // we must do this here, because of ExplorerManager's deserialization.
0736: // Root context of ExplorerManager is validated AFTER all other
0737: // deserialization, so we must wait for it
0738: protected final void scheduleValidation() {
0739: valid = false;
0740: setValidRootContext();
0741: }
0742:
0743: /* Updated accessible name of the tree view */
0744: public void setName(String name) {
0745: super .setName(name);
0746: if (view != null) {
0747: view.getAccessibleContext().setAccessibleName(name);
0748: }
0749: }
0750:
0751: /* Updated accessible description of the tree view */
0752: public void setToolTipText(String text) {
0753: super .setToolTipText(text);
0754: if (view != null) {
0755: view.getAccessibleContext().setAccessibleDescription(
0756: text);
0757: }
0758: }
0759:
0760: public TopComponent cloneComponent() {
0761: ExplorerTab nue = new ExplorerTab();
0762: nue.getExplorerManager().setRootContext(
0763: getExplorerManager().getRootContext());
0764: try {
0765: nue.getExplorerManager().setSelectedNodes(
0766: getExplorerManager().getSelectedNodes());
0767: } catch (PropertyVetoException pve) {
0768: Exceptions.printStackTrace(pve);
0769: }
0770: return nue;
0771: }
0772:
0773: /** Multi - purpose listener, listens to: <br>
0774: * 1) Changes of name, icon, short description of root context.
0775: * 2) Changes of IDE settings, namely delete confirmation settings */
0776: private final class RootContextListener extends Object
0777: implements NodeListener {
0778:
0779: RootContextListener() {
0780: }
0781:
0782: public void propertyChange(PropertyChangeEvent evt) {
0783: String propName = evt.getPropertyName();
0784: Object source = evt.getSource();
0785: // root context node change
0786: final Node n = (Node) source;
0787: if (Node.PROP_DISPLAY_NAME.equals(propName)
0788: || Node.PROP_NAME.equals(propName)) {
0789: // Fix #39275 start - posted to awt thread.
0790: Mutex.EVENT.readAccess(new Runnable() {
0791: public void run() {
0792: setName(n.getDisplayName());
0793: }
0794: });
0795: // fix #39275 end
0796: } else if (Node.PROP_ICON.equals(propName)) {
0797: // Fix #39275 start - posted to awt thread.
0798: Mutex.EVENT.readAccess(new Runnable() {
0799: public void run() {
0800: setIcon(n
0801: .getIcon(BeanInfo.ICON_COLOR_16x16));
0802: }
0803: });
0804: // fix #39275 end
0805: } else if (Node.PROP_SHORT_DESCRIPTION.equals(propName)) {
0806: setToolTipText(n.getShortDescription());
0807: }
0808: }
0809:
0810: @SuppressWarnings("deprecation")
0811: public void nodeDestroyed(
0812: org.openide.nodes.NodeEvent nodeEvent) {
0813: ExplorerTab.this
0814: .setCloseOperation(TopComponent.CLOSE_EACH);
0815: ExplorerTab.this .close();
0816: }
0817:
0818: public void childrenRemoved(
0819: org.openide.nodes.NodeMemberEvent e) {
0820: }
0821:
0822: public void childrenReordered(
0823: org.openide.nodes.NodeReorderEvent e) {
0824: }
0825:
0826: public void childrenAdded(
0827: org.openide.nodes.NodeMemberEvent e) {
0828: }
0829:
0830: } // end of RootContextListener inner class
0831:
0832: } // end of ExplorerTab inner class
0833:
0834: /** Tab of main explorer. Tries to dock itself to main explorer mode
0835: * before opening, if it's not docked already.
0836: * Also deserialization is enhanced in contrast to superclass */
0837: public static class MainTab extends ExplorerTab {
0838: static final long serialVersionUID = 4233454980309064344L;
0839:
0840: /** Holds main tab which was last activated.
0841: * Used during decision which tab should receive focus
0842: * when opening all tabs at once using NbMainExplorer.openRoots()
0843: */
0844: private static MainTab lastActivated;
0845:
0846: private static MainTab DEFAULT;
0847:
0848: public static synchronized MainTab getDefaultMainTab() {
0849: if (DEFAULT == null) {
0850: DEFAULT = new MainTab();
0851: // put a request for later validation
0852: // we must do this here, because of ExplorerManager's deserialization.
0853: // Root context of ExplorerManager is validated AFTER all other
0854: // deserialization, so we must wait for it
0855: DEFAULT.scheduleValidation();
0856: }
0857:
0858: return DEFAULT;
0859: }
0860:
0861: /** Creator/accessor method of Runtime tab singleton. Instance is properly
0862: * deserialized by winsys.
0863: */
0864: public static MainTab findEnvironmentTab() {
0865: return (MainTab) getExplorer().createTC(
0866: NbPlaces.getDefault().environment(), true);
0867: }
0868:
0869: /** Creator/accessor method used ONLY by winsys for first time instantiation
0870: * of Runtime tab. Use <code>findEnvironmentTab</code> to properly deserialize
0871: * singleton instance.
0872: */
0873: public static MainTab createEnvironmentTab() {
0874: return (MainTab) getExplorer().createTC(
0875: NbPlaces.getDefault().environment(), false);
0876: }
0877:
0878: /** Overriden to explicitely set persistence type of MainTab
0879: * to PERSISTENCE_ALWAYS */
0880: public int getPersistenceType() {
0881: return TopComponent.PERSISTENCE_ALWAYS;
0882: }
0883:
0884: protected String preferredID() {
0885: return "runtime"; //NOI18N
0886: }
0887:
0888: public HelpCtx getHelpCtx() {
0889: return ExplorerUtils.getHelpCtx(getExplorerManager()
0890: .getSelectedNodes(), new HelpCtx(
0891: EnvironmentNode.class));
0892: }
0893:
0894: /** Deserialization of RepositoryTab */
0895: public Object readResolve()
0896: throws java.io.ObjectStreamException {
0897: if (DEFAULT == null) {
0898: DEFAULT = this ;
0899: }
0900: getDefaultMainTab().scheduleValidation();
0901: return getDefaultMainTab();
0902: }
0903:
0904: @SuppressWarnings("deprecation")
0905: public void open(org.openide.windows.Workspace workspace) {
0906: org.openide.windows.Workspace realWorkspace = (workspace == null) ? WindowManager
0907: .getDefault().getCurrentWorkspace()
0908: : workspace;
0909: Mode ourMode = realWorkspace.findMode(this );
0910: if (ourMode == null) {
0911: explorerMode(realWorkspace).dockInto(this );
0912: }
0913: super .open(workspace);
0914: }
0915:
0916: /** Called when the explored context changes.
0917: * Overriden - we don't want title to chnage in this style.
0918: */
0919: protected void updateTitle() {
0920: // empty to keep the title unchanged
0921: }
0922:
0923: /** Overrides superclass' version, remembers last activated
0924: * main tab */
0925: protected void componentActivated() {
0926: super .componentActivated();
0927: lastActivated = this ;
0928: }
0929:
0930: /** Registers root context in main explorer in addition to superclass'
0931: * version */
0932: protected void validateRootContext() {
0933: super .validateRootContext();
0934: registerRootContext(getExplorerManager().getRootContext());
0935: }
0936:
0937: /* Add given root context and this top component
0938: * to the map of main explorer's top components and nodes */
0939: protected void registerRootContext(Node rc) {
0940: NbMainExplorer explorer = NbMainExplorer.getExplorer();
0941: explorer.prevRoots().add(rc);
0942: explorer.rootsToTCs().put(rc, this );
0943: }
0944:
0945: } // end of MainTab inner class
0946:
0947: /** Special class for tabs added by modules to the main explorer */
0948: public static class ModuleTab extends MainTab {
0949: static final long serialVersionUID = 8089827754534653731L;
0950:
0951: public ModuleTab() {
0952: // System.out.println("NbMainExplorer.ModuleTab");
0953: }
0954:
0955: public void setRootContext(Node root) {
0956: super .setRootContext(root);
0957: adjustComponentPersistence();
0958: }
0959:
0960: /** Overriden to explicitely set persistence type of ModuleTab
0961: * to selected type */
0962: public int getPersistenceType() {
0963: return persistenceType;
0964: }
0965:
0966: /** Throws deserialized root context and sets proper node found
0967: * in roots set as new root context for this top component.
0968: * The reason for such construction is to keep the uniquennes of
0969: * root context node after deserialization. */
0970: protected void validateRootContext() {
0971: // find proper node
0972: Class nodeClass = getExplorerManager().getRootContext()
0973: .getClass();
0974: Node[] roots = NbPlaces.getDefault().roots();
0975: for (int i = 0; i < roots.length; i++) {
0976: if (nodeClass.equals(roots[i].getClass())) {
0977: setRootContext(roots[i]);
0978: registerRootContext(roots[i]);
0979: break;
0980: }
0981: }
0982: }
0983:
0984: /** Deserialization of ModuleTab */
0985: public Object readResolve()
0986: throws java.io.ObjectStreamException {
0987: Node root = getExplorerManager().getRootContext();
0988:
0989: ModuleTab tc = NbMainExplorer.findModuleTab(root, this );
0990: if (tc == null) {
0991: throw new java.io.InvalidObjectException(
0992: "Cannot deserialize ModuleTab for node " + root); // NOI18N
0993: }
0994:
0995: tc.scheduleValidation();
0996: return tc;
0997: }
0998:
0999: } // end of ModuleTab inner class
1000:
1001: /** Listener on roots, listens to changes of roots content */
1002: private static final class RootsListener extends Object implements
1003: ChangeListener {
1004:
1005: RootsListener() {
1006: }
1007:
1008: public void stateChanged(ChangeEvent e) {
1009: NbMainExplorer.getExplorer().doOpen(null);
1010: }
1011: } // end of RootsListener inner class
1012:
1013: public static void main(String[] args) throws Exception {
1014: NbMainExplorer e = new NbMainExplorer();
1015: e.open();
1016: }
1017: }
|