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