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:
042: package org.netbeans.modules.project.ui;
043:
044: import java.awt.Frame;
045: import java.awt.Image;
046: import java.awt.Rectangle;
047: import java.awt.event.WindowAdapter;
048: import java.awt.event.WindowEvent;
049: import java.beans.PropertyChangeListener;
050: import java.beans.PropertyChangeSupport;
051: import java.net.URL;
052: import java.util.ArrayList;
053: import java.util.Arrays;
054: import java.util.HashMap;
055: import java.util.HashSet;
056: import java.util.Iterator;
057: import java.util.Map;
058: import java.util.Set;
059: import java.util.TreeMap;
060: import java.util.WeakHashMap;
061: import javax.swing.Action;
062: import javax.swing.JFrame;
063: import javax.swing.SwingUtilities;
064: import org.openide.nodes.Node;
065: import org.openide.text.CloneableEditorSupport;
066: import org.openide.util.Utilities;
067: import org.openide.util.actions.SystemAction;
068: import org.openide.windows.CloneableTopComponent;
069: import org.openide.windows.Mode;
070: import org.openide.windows.TopComponent;
071: import org.openide.windows.TopComponentGroup;
072: import org.openide.windows.WindowManager;
073: import org.openide.windows.Workspace;
074:
075: /**
076: * Trivial window manager that just keeps track of "workspaces" and "modes"
077: * according to contract but does not really use them, and just opens all
078: * top components in their own frames.
079: * Useful in case core-windows.jar is not installed, e.g. in standalone usage.
080: * @author Jesse Glick
081: * @see "#29933"
082: *
083: */
084: @SuppressWarnings("deprecation")
085: public final class ProjectUtilitiesDummyWindowManager extends
086: WindowManager {
087:
088: private static final boolean VISIBLE = Boolean.parseBoolean(System
089: .getProperty(
090: "org.openide.windows.DummyWindowManager.VISIBLE",
091: "true"));
092: private static final long serialVersionUID = 1L;
093: private static Action[] DEFAULT_ACTIONS_CLONEABLE;
094: private static Action[] DEFAULT_ACTIONS_NOT_CLONEABLE;
095: private final Map<String, Workspace> workspaces;
096: private transient Frame mw;
097: private transient PropertyChangeSupport pcs;
098: private transient R r;
099:
100: public ProjectUtilitiesDummyWindowManager() {
101: workspaces = new TreeMap<String, Workspace>();
102: createWorkspace("default", null).createMode(
103: /*CloneableEditorSupport.EDITOR_MODE*/"editor",
104: "editor", null); // NOI18N
105: }
106:
107: public synchronized void addPropertyChangeListener(
108: PropertyChangeListener l) {
109: if (pcs == null) {
110: pcs = new PropertyChangeSupport(this );
111: }
112:
113: pcs.addPropertyChangeListener(l);
114: }
115:
116: public synchronized void removePropertyChangeListener(
117: PropertyChangeListener l) {
118: if (pcs != null) {
119: pcs.removePropertyChangeListener(l);
120: }
121: }
122:
123: protected TopComponent.Registry componentRegistry() {
124: TopComponent.Registry reg = super .componentRegistry();
125:
126: if (reg != null) {
127: return reg;
128: } else {
129: return registry();
130: }
131: }
132:
133: synchronized R registry() {
134: if (r == null) {
135: r = new R();
136: }
137:
138: return r;
139: }
140:
141: protected WindowManager.Component createTopComponentManager(
142: TopComponent c) {
143: return null; // Not used anymore.
144: }
145:
146: public synchronized Workspace createWorkspace(String name,
147: String displayName) {
148: Workspace w = new W(name);
149: workspaces.put(name, w);
150:
151: if (pcs != null) {
152: pcs.firePropertyChange(PROP_WORKSPACES, null, null);
153: pcs.firePropertyChange(PROP_CURRENT_WORKSPACE, null, null);
154: }
155:
156: return w;
157: }
158:
159: synchronized void delete(Workspace w) {
160: workspaces.remove(w.getName());
161:
162: if (workspaces.isEmpty()) {
163: createWorkspace("default", null); // NOI18N
164: }
165:
166: if (pcs != null) {
167: pcs.firePropertyChange(PROP_WORKSPACES, null, null);
168: pcs.firePropertyChange(PROP_CURRENT_WORKSPACE, null, null);
169: }
170: }
171:
172: public synchronized Workspace findWorkspace(String name) {
173: return workspaces.get(name);
174: }
175:
176: public synchronized Workspace getCurrentWorkspace() {
177: return workspaces.values().iterator().next();
178: }
179:
180: public synchronized Workspace[] getWorkspaces() {
181: return workspaces.values().toArray(new Workspace[0]);
182: }
183:
184: public synchronized void setWorkspaces(Workspace[] ws) {
185: if (ws.length == 0) {
186: throw new IllegalArgumentException();
187: }
188:
189: workspaces.clear();
190:
191: for (int i = 0; i < ws.length; i++) {
192: workspaces.put(ws[i].getName(), ws[i]);
193: }
194:
195: if (pcs != null) {
196: pcs.firePropertyChange(PROP_WORKSPACES, null, null);
197: pcs.firePropertyChange(PROP_CURRENT_WORKSPACE, null, null);
198: }
199: }
200:
201: public synchronized Frame getMainWindow() {
202: if (mw == null) {
203: mw = new JFrame("dummy"); // NOI18N
204: }
205:
206: return mw;
207: }
208:
209: public void updateUI() {
210: }
211:
212: // Modes
213: public Set<Mode> getModes() {
214: Set<Mode> s = new HashSet<Mode>();
215:
216: for (Iterator<Workspace> it = new HashSet<Workspace>(workspaces
217: .values()).iterator(); it.hasNext();) {
218: Workspace w = it.next();
219: s.addAll(w.getModes());
220: }
221:
222: return s;
223: }
224:
225: public Mode findMode(TopComponent tc) {
226: for (Iterator<Mode> it = getModes().iterator(); it.hasNext();) {
227: Mode m = it.next();
228:
229: if (Arrays.asList(m.getTopComponents()).contains(tc)) {
230: return m;
231: }
232: }
233:
234: return null;
235: }
236:
237: @Override
238: public boolean isEditorTopComponent(TopComponent tc) {
239: Mode md = findMode(tc);
240: if (md != null
241: && CloneableEditorSupport.EDITOR_MODE.equals(md
242: .getName())) {
243: return true;
244: }
245: return false;
246: }
247:
248: @Override
249: public boolean isOpenedEditorTopComponent(TopComponent tc) {
250: Mode md = findMode(tc);
251: if (md != null
252: && CloneableEditorSupport.EDITOR_MODE.equals(md
253: .getName())) {
254: return tc.isOpened();
255: }
256: return super .isOpenedEditorTopComponent(tc);
257: }
258:
259: public Mode findMode(String name) {
260: if (name == null) {
261: return null;
262: }
263:
264: for (Iterator<Mode> it = getModes().iterator(); it.hasNext();) {
265: Mode m = it.next();
266:
267: if (name.equals(m.getName())) {
268: return m;
269: }
270: }
271:
272: return null;
273: }
274:
275: // PENDING Groups not supported.
276: public TopComponentGroup findTopComponentGroup(String name) {
277: return null;
278: }
279:
280: //Not supported. Need to access PersistenceManager.
281: public TopComponent findTopComponent(String tcID) {
282: return null;
283: }
284:
285: protected String topComponentID(TopComponent tc, String preferredID) {
286: return preferredID;
287: }
288:
289: protected Action[] topComponentDefaultActions(TopComponent tc) {
290: // XXX It could be better to provide non-SystemAction instances.
291: synchronized (ProjectUtilitiesDummyWindowManager.class) {
292: //Bugfix #33557: Do not provide CloneViewAction when
293: //TopComponent does not implement TopComponent.Cloneable
294: if (tc instanceof TopComponent.Cloneable) {
295: if (DEFAULT_ACTIONS_CLONEABLE == null) {
296: DEFAULT_ACTIONS_CLONEABLE = loadActions(new String[] {
297: "Save", // NOI18N
298: "CloneView", // NOI18N
299: null, "CloseView" // NOI18N
300: });
301: }
302:
303: return DEFAULT_ACTIONS_CLONEABLE;
304: } else {
305: if (DEFAULT_ACTIONS_NOT_CLONEABLE == null) {
306: DEFAULT_ACTIONS_NOT_CLONEABLE = loadActions(new String[] {
307: "Save", // NOI18N
308: null, "CloseView" // NOI18N
309: });
310: }
311:
312: return DEFAULT_ACTIONS_NOT_CLONEABLE;
313: }
314: }
315: }
316:
317: private static Action[] loadActions(String[] names) {
318: ArrayList<Action> arr = new ArrayList<Action>();
319: ClassLoader loader = Thread.currentThread()
320: .getContextClassLoader();
321:
322: for (int i = 0; i < names.length; i++) {
323: if (names[i] == null) {
324: arr.add(null);
325:
326: continue;
327: }
328:
329: try {
330: Class<? extends SystemAction> sa = Class.forName(
331: "org.openide.actions." + names[i] + "Action",
332: true, loader).asSubclass(SystemAction.class);
333: arr.add(SystemAction.get(sa)); // NOI18N
334: } catch (ClassNotFoundException e) {
335: // ignore it, missing org-openide-actions.jar
336: }
337: }
338:
339: return arr.toArray(new Action[0]);
340: }
341:
342: protected boolean topComponentIsOpened(TopComponent tc) {
343: return tc.isShowing();
344: }
345:
346: protected void topComponentActivatedNodesChanged(TopComponent tc,
347: Node[] nodes) {
348: registry().setActivatedNodes(tc, nodes);
349: }
350:
351: protected void topComponentIconChanged(TopComponent tc, Image icon) {
352: JFrame f = (JFrame) SwingUtilities.getAncestorOfClass(
353: JFrame.class, tc);
354:
355: if (f != null) {
356: f.setIconImage(icon);
357: }
358: }
359:
360: protected void topComponentToolTipChanged(TopComponent tc,
361: String tooltip) {
362: // No op.
363: }
364:
365: protected void topComponentDisplayNameChanged(TopComponent tc,
366: String displayName) {
367: JFrame f = (JFrame) SwingUtilities.getAncestorOfClass(
368: JFrame.class, tc);
369:
370: if (f != null) {
371: f.setTitle(displayName);
372: }
373: }
374:
375: protected void topComponentHtmlDisplayNameChanged(TopComponent tc,
376: String htmlDisplayName) {
377: // no operarion, html looks ugly in frame titles
378: }
379:
380: protected void topComponentOpen(TopComponent tc) {
381: JFrame f = (JFrame) SwingUtilities.getAncestorOfClass(
382: JFrame.class, tc);
383:
384: if (f == null) {
385: f = new JFrame(tc.getName());
386:
387: Image icon = tc.getIcon();
388:
389: if (icon != null) {
390: f.setIconImage(icon);
391: }
392:
393: f.getContentPane().add(tc);
394: f.pack();
395:
396: final java.lang.ref.WeakReference<TopComponent> ref = new java.lang.ref.WeakReference<TopComponent>(
397: tc);
398: f.addWindowListener(new WindowAdapter() {
399: public void windowClosing(WindowEvent ev) {
400: TopComponent tc = ref.get();
401:
402: if (tc == null) {
403: return;
404: }
405:
406: tc.close();
407: }
408:
409: public void windowActivated(WindowEvent e) {
410: TopComponent tc = ref.get();
411:
412: if (tc == null) {
413: return;
414: }
415:
416: tc.requestActive();
417: }
418: });
419: }
420:
421: if (!tc.isShowing()) {
422: componentOpenNotify(tc);
423: componentShowing(tc);
424: if (VISIBLE) {
425: f.setVisible(true);
426: }
427: registry().open(tc);
428: }
429: }
430:
431: protected void topComponentOpenAtTabPosition(TopComponent tc,
432: int index) {
433: topComponentOpen(tc);
434: }
435:
436: protected int topComponentGetTabPosition(TopComponent tc) {
437: return topComponentIsOpened(tc) ? 0 : -1;
438: }
439:
440: protected void topComponentClose(TopComponent tc) {
441: componentHidden(tc);
442: componentCloseNotify(tc);
443:
444: JFrame f = (JFrame) SwingUtilities.getAncestorOfClass(
445: JFrame.class, tc);
446:
447: if (f != null) {
448: if (VISIBLE) {
449: f.setVisible(false);
450: }
451: tc.getParent().remove(tc);
452: }
453:
454: registry().close(tc);
455:
456: java.util.Iterator it = workspaces.values().iterator();
457:
458: while (it.hasNext()) {
459: W w = (W) it.next();
460: w.close(tc);
461: }
462: }
463:
464: protected void topComponentRequestVisible(TopComponent tc) {
465: JFrame f = (JFrame) SwingUtilities.getAncestorOfClass(
466: JFrame.class, tc);
467:
468: if (f != null) {
469: if (VISIBLE) {
470: f.setVisible(true);
471: }
472: }
473: }
474:
475: protected void topComponentRequestActive(TopComponent tc) {
476: JFrame f = (JFrame) SwingUtilities.getAncestorOfClass(
477: JFrame.class, tc);
478:
479: if (f != null) {
480: f.toFront();
481: }
482:
483: registry().setActive(tc);
484: activateComponent(tc);
485: }
486:
487: protected void topComponentRequestAttention(TopComponent tc) {
488: //TODO what to do here?
489: }
490:
491: protected void topComponentCancelRequestAttention(TopComponent tc) {
492: //TODO what to do here?
493: }
494:
495: private final class W implements Workspace {
496: private static final long serialVersionUID = 1L;
497: private final String name;
498: private final Map<String, Mode> modes = new HashMap<String, Mode>();
499: private final Map<TopComponent, Mode> modesByComponent = new WeakHashMap<TopComponent, Mode>();
500: private transient PropertyChangeSupport pcs;
501:
502: public W(String name) {
503: this .name = name;
504: }
505:
506: public void activate() {
507: }
508:
509: public synchronized void addPropertyChangeListener(
510: PropertyChangeListener list) {
511: if (pcs == null) {
512: pcs = new PropertyChangeSupport(this );
513: }
514:
515: pcs.addPropertyChangeListener(list);
516: }
517:
518: public synchronized void removePropertyChangeListener(
519: PropertyChangeListener list) {
520: if (pcs != null) {
521: pcs.removePropertyChangeListener(list);
522: }
523: }
524:
525: public void remove() {
526: ProjectUtilitiesDummyWindowManager.this .delete(this );
527: }
528:
529: public synchronized Mode createMode(String name,
530: String displayName, URL icon) {
531: Mode m = new M(name);
532: modes.put(name, m);
533:
534: if (pcs != null) {
535: pcs.firePropertyChange(PROP_MODES, null, null);
536: }
537:
538: return m;
539: }
540:
541: public synchronized Set<Mode> getModes() {
542: return new HashSet<Mode>(modes.values());
543: }
544:
545: public synchronized Mode findMode(String name) {
546: return modes.get(name);
547: }
548:
549: public synchronized Mode findMode(TopComponent c) {
550: return modesByComponent.get(c);
551: }
552:
553: synchronized void dock(Mode m, TopComponent c) {
554: modesByComponent.put(c, m);
555: }
556:
557: public Rectangle getBounds() {
558: return Utilities.getUsableScreenBounds();
559: }
560:
561: public String getName() {
562: return name;
563: }
564:
565: public String getDisplayName() {
566: return getName();
567: }
568:
569: public void close(TopComponent tc) {
570: java.util.Iterator it = modes.values().iterator();
571:
572: while (it.hasNext()) {
573: M m = (M) it.next();
574: m.close(tc);
575: }
576: }
577:
578: private final class M implements Mode {
579: private static final long serialVersionUID = 1L;
580: private final String name;
581: private final Set<TopComponent> components = new HashSet<TopComponent>();
582:
583: public M(String name) {
584: this .name = name;
585: }
586:
587: public void close(TopComponent tc) {
588: components.remove(tc);
589: }
590:
591: /* Not needed:
592: private transient PropertyChangeSupport pcs;
593: public synchronized void addPropertyChangeListener(PropertyChangeListener list) {
594: if (pcs == null) {
595: pcs = new PropertyChangeSupport(this);
596: }
597: pcs.addPropertyChangeListener(list);
598: }
599: public synchronized void removePropertyChangeListener(PropertyChangeListener list) {
600: if (pcs != null) {
601: pcs.removePropertyChangeListener(list);
602: }
603: }
604: */
605: public void addPropertyChangeListener(
606: PropertyChangeListener l) {
607: }
608:
609: public void removePropertyChangeListener(
610: PropertyChangeListener l) {
611: }
612:
613: public boolean canDock(TopComponent tc) {
614: return true;
615: }
616:
617: public synchronized boolean dockInto(TopComponent c) {
618: if (components.add(c)) {
619: Mode old = findMode(c);
620:
621: if ((old != null) && (old != this )
622: && old instanceof M) {
623: synchronized (old) {
624: ((M) old).components.remove(c);
625: }
626: }
627:
628: dock(this , c);
629: }
630:
631: return true;
632: }
633:
634: public String getName() {
635: return name;
636: }
637:
638: public String getDisplayName() {
639: return getName();
640: }
641:
642: public Image getIcon() {
643: return null;
644: }
645:
646: public synchronized TopComponent[] getTopComponents() {
647: return components.toArray(new TopComponent[0]);
648: }
649:
650: public Workspace getWorkspace() {
651: return W.this ;
652: }
653:
654: public synchronized Rectangle getBounds() {
655: return W.this .getBounds();
656: }
657:
658: public void setBounds(Rectangle s) {
659: }
660:
661: public TopComponent getSelectedTopComponent() {
662: TopComponent[] tcs = components
663: .toArray(new TopComponent[0]);
664:
665: return (tcs.length > 0) ? tcs[0] : null;
666: }
667: }
668: }
669:
670: private static final class R implements TopComponent.Registry {
671: private TopComponent active;
672: private final Set<TopComponent> opened;
673: private Node[] nodes;
674: private PropertyChangeSupport pcs;
675:
676: public R() {
677: opened = new HashSet<TopComponent>();
678: nodes = new Node[0];
679: }
680:
681: public synchronized void addPropertyChangeListener(
682: PropertyChangeListener l) {
683: if (pcs == null) {
684: pcs = new PropertyChangeSupport(this );
685: }
686:
687: pcs.addPropertyChangeListener(l);
688: }
689:
690: public synchronized void removePropertyChangeListener(
691: PropertyChangeListener l) {
692: if (pcs != null) {
693: pcs.removePropertyChangeListener(l);
694: }
695: }
696:
697: synchronized void open(TopComponent tc) {
698: opened.add(tc);
699:
700: if (pcs != null) {
701: pcs.firePropertyChange(PROP_TC_OPENED, null, tc);
702: pcs.firePropertyChange(PROP_OPENED, null, null);
703: }
704: }
705:
706: synchronized void close(TopComponent tc) {
707: opened.remove(tc);
708:
709: if (pcs != null) {
710: pcs.firePropertyChange(PROP_TC_CLOSED, null, tc);
711: pcs.firePropertyChange(PROP_OPENED, null, null);
712: }
713:
714: if (active == tc) {
715: setActive(null);
716: }
717: }
718:
719: public synchronized Set<TopComponent> getOpened() {
720: return new HashSet<TopComponent>(opened);
721: }
722:
723: synchronized void setActive(TopComponent tc) {
724: active = tc;
725:
726: Node[] _nodes = (tc == null) ? new Node[0] : tc
727: .getActivatedNodes();
728:
729: if (_nodes != null) {
730: nodes = _nodes;
731:
732: if (pcs != null) {
733: pcs.firePropertyChange(PROP_ACTIVATED_NODES, null,
734: null);
735: }
736: }
737:
738: if (pcs != null) {
739: pcs.firePropertyChange(PROP_ACTIVATED, null, null);
740: pcs.firePropertyChange(PROP_CURRENT_NODES, null, null);
741: }
742: }
743:
744: synchronized void setActivatedNodes(TopComponent tc,
745: Node[] _nodes) {
746: if (tc == active) {
747: if (_nodes != null) {
748: nodes = _nodes;
749:
750: if (pcs != null) {
751: pcs.firePropertyChange(PROP_ACTIVATED_NODES,
752: null, null);
753: }
754: }
755:
756: if (pcs != null) {
757: pcs.firePropertyChange(PROP_CURRENT_NODES, null,
758: null);
759: }
760: }
761: }
762:
763: public TopComponent getActivated() {
764: return active;
765: }
766:
767: public Node[] getActivatedNodes() {
768: return nodes;
769: }
770:
771: public synchronized Node[] getCurrentNodes() {
772: if (active != null) {
773: return active.getActivatedNodes();
774: } else {
775: return null;
776: }
777: }
778: }
779: }
|