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.core.windows;
043:
044: import org.openide.windows.Mode;
045: import org.openide.windows.TopComponent;
046: import org.openide.windows.Workspace;
047:
048: import java.beans.PropertyChangeListener;
049: import java.beans.PropertyChangeSupport;
050: import java.util.Iterator;
051: import java.util.List;
052: import java.util.Set;
053: import javax.swing.SwingUtilities;
054: import java.awt.Image;
055: import java.awt.Rectangle;
056:
057: /** This class is an implementation of Mode interface.
058: * It designates 'place' on screen, at wich TopComponent can occure.
059: *
060: * @author Peter Zavadsky
061: */
062: public final class ModeImpl implements Mode {
063:
064: /** Name constant as a base for nonamed modes. */
065: private static final String MODE_ANONYMOUS_NAME = "anonymousMode"; // NOI18N
066:
067: /** asociated property change support for firing property changes */
068: private final PropertyChangeSupport changeSupport = new PropertyChangeSupport(
069: this );
070:
071: /** Debugging flag. */
072: private static final boolean DEBUG = Debug
073: .isLoggable(ModeImpl.class);
074:
075: /** Construct new mode with given properties */
076: private ModeImpl(String name, int state, int kind, boolean permanent) {
077: getCentral()
078: .createModeModel(this , name, state, kind, permanent);
079: }
080:
081: /** Factory method which creates <code>ModeImpl</code> instances. */
082: public static ModeImpl createModeImpl(String name, int state,
083: int kind, boolean permanent) {
084: return new ModeImpl(name, state, kind, permanent);
085: }
086:
087: ///////////////////////////////////////////////////////////////////
088: // Start of org.openide.windows.Mode interface implementation.
089: ///////////////////////////////////////////////////////////////////
090: /** Gets the programmatic name of this mode.
091: * This name should be unique, as it is used to find modes etc.
092: * Implements <code>Mode</code> interface method.
093: * @return programmatic name of this mode */
094: public String getName() {
095: WindowManagerImpl.assertEventDispatchThreadWeak();
096:
097: return getCentral().getModeName(this );
098: }
099:
100: /** Gets display name of this mode.
101: ** Implements <code>Mode</code> interface method.
102: * @return Human presentable name of this mode implementation
103: * @deprecated It is not used anymore. This impl delegated to {@link #getName} method. */
104: public String getDisplayName() {
105: WindowManagerImpl.assertEventDispatchThreadWeak();
106:
107: return getName();
108: }
109:
110: /** Gets icon for this mode.
111: * Implements <code>Mode</code> interface method.
112: * @return null
113: * @deprecated It is not used anymore. */
114: public Image getIcon() {
115: WindowManagerImpl.assertEventDispatchThreadWeak();
116:
117: return null;
118: }
119:
120: /** Indicates whether specified <code>TopComponent</code> can be docked
121: * into this <code>Mode</code>.
122: * Implements <code>Mode</code> interface method.
123: * @return <code>true</code> */
124: public boolean canDock(TopComponent tc) {
125: WindowManagerImpl.assertEventDispatchThreadWeak();
126:
127: return true;
128: }
129:
130: /** Attaches a component to a mode for this workspace.
131: * If the component is in different mode on this desktop, it is
132: * removed from the original and moved to this one.
133: * Implements <code>Mode</code> interface method.
134: *
135: * @param tc top component to dock into this mode
136: * @return true if top component was succesfully docked to this
137: * mode, false otherwise */
138: public boolean dockInto(TopComponent tc) {
139: WindowManagerImpl.assertEventDispatchThreadWeak();
140:
141: return dockIntoImpl(tc, true);
142: }
143:
144: /** Sets bounds of this mode.
145: * Implements <code>Mode</code> interface method.
146: * @param rect bounds for the mode */
147: public void setBounds(Rectangle bounds) {
148: WindowManagerImpl.assertEventDispatchThreadWeak();
149:
150: getCentral().setModeBounds(this , bounds);
151: }
152:
153: /** Getter for current bounds of the mode.
154: * Implements <code>Mode</code> interface method.
155: * @return the bounds of the mode
156: */
157: public Rectangle getBounds() {
158: WindowManagerImpl.assertEventDispatchThreadWeak();
159:
160: return getCentral().getModeBounds(this );
161: }
162:
163: /** Getter for asociated workspace.
164: * Implements <code>Mode</code> interface method.
165: * @return The workspace instance to which is this mode asociated.
166: * @deprecated XXX Don't use anymore.
167: */
168: public Workspace getWorkspace() {
169: WindowManagerImpl.assertEventDispatchThreadWeak();
170:
171: // Here is the only fake workspace.
172: return WindowManagerImpl.getInstance();
173: }
174:
175: /** Gets array of <code>TopComponent</code>S in this mode.
176: * Implements <code>Mode</code> interface method.
177: * @return array of top components which are currently
178: * docked in this mode. May return empty array if no top component
179: * is docked in this mode.
180: */
181: public TopComponent[] getTopComponents() {
182: WindowManagerImpl.assertEventDispatchThreadWeak();
183:
184: return getCentral().getModeTopComponents(this ).toArray(
185: new TopComponent[0]);
186: }
187:
188: /** Adds listener to the property changes.
189: * Implements <code>Mode</code> interface support. */
190: public void addPropertyChangeListener(PropertyChangeListener pchl) {
191: changeSupport.addPropertyChangeListener(pchl);
192: }
193:
194: /** Removes listener to the property changes.
195: * Implements <code>Mode</code> interface method. */
196: public void removePropertyChangeListener(PropertyChangeListener pchl) {
197: changeSupport.removePropertyChangeListener(pchl);
198: }
199:
200: ///////////////////////////////////////////////////////////////////
201: // End of org.openide.windows.Mode interface implementation.
202: ///////////////////////////////////////////////////////////////////
203:
204: /** Actually performs the docking operation.
205: * @param tc top component to dock into this mode
206: * @param orderWeight weight for ordering. Smaller weight number means
207: * smaller position index, which means closer to the top or start in
208: * visual representations
209: * @param select <code>true</code> if the docked <code>TopComponent</code>
210: * will be selected afterwards
211: * @return true if top component was succesfully docked to this */
212: private boolean dockIntoImpl(final TopComponent tc,
213: final boolean select) {
214: if (DEBUG) {
215: Debug.log(ModeImpl.class, "Docking tc=" + tc.getName()
216: + " into mode=" + this ); // NOI18N
217: Debug.dumpStack(ModeImpl.class);
218: }
219:
220: // PENDING
221: // Preferably all in one step.
222: ModeImpl mode = (ModeImpl) WindowManagerImpl.getInstance()
223: .findMode(tc);
224: if (mode != null && mode != this ) {
225: // XXX if only closin (mode.close(tc)) there could happen,
226: // there is the same TopComponent as closed in two modes. Revise.
227: mode.removeTopComponent(tc);
228: }
229:
230: addClosedTopComponent(tc);
231: return true;
232: }
233:
234: /** Closes given top component. */
235: public void close(TopComponent tc) {
236: if (!getOpenedTopComponents().contains(tc)) {
237: return;
238: }
239: addClosedTopComponent(tc);
240: }
241:
242: /** Gets list of opened TopComponentS. */
243: public List<TopComponent> getOpenedTopComponents() {
244: return getCentral().getModeOpenedTopComponents(this );
245: }
246:
247: /** Sets selected TopComponent. */
248: public void setSelectedTopComponent(TopComponent tc) {
249: if (!getOpenedTopComponents().contains(tc)) {
250: return;
251: }
252:
253: TopComponent old = getSelectedTopComponent();
254: if (tc == old) {
255: return;
256: }
257:
258: getCentral().setModeSelectedTopComponent(this , tc);
259: }
260:
261: /** Gets selected TopComponent. */
262: public TopComponent getSelectedTopComponent() {
263: WindowManagerImpl.assertEventDispatchThread();
264:
265: return getCentral().getModeSelectedTopComponent(this );
266: }
267:
268: /**
269: * Remember which top component was previously the selected one.
270: * Used when switching to/from maximized mode.
271: */
272: public void setPreviousSelectedTopComponentID(String tcId) {
273: String old = getPreviousSelectedTopComponentID();
274: if (null != tcId && tcId.equals(old)) {
275: return;
276: }
277: getCentral().setModePreviousSelectedTopComponentID(this , tcId);
278: }
279:
280: /**
281: * @return The top component that was the selected one before switching to/from
282: * the maximized mode.
283: */
284: public TopComponent getPreviousSelectedTopComponent() {
285: String tcId = getPreviousSelectedTopComponentID();
286: TopComponent res = null;
287: if (null != tcId)
288: res = WindowManagerImpl.getInstance()
289: .findTopComponent(tcId);
290: WindowManagerImpl.assertEventDispatchThread();
291:
292: return res;
293: }
294:
295: /**
296: * @return The ID top component that was the selected one before switching to/from
297: * the maximized mode.
298: */
299: public String getPreviousSelectedTopComponentID() {
300: WindowManagerImpl.assertEventDispatchThread();
301:
302: return getCentral().getModePreviousSelectedTopComponentID(this );
303: }
304:
305: public void addOpenedTopComponent(TopComponent tc) {
306: getCentral().addModeOpenedTopComponent(this , tc);
307: }
308:
309: public void addOpenedTopComponent(TopComponent tc, int index) {
310: getCentral().insertModeOpenedTopComponent(this , tc, index);
311: }
312:
313: public void addClosedTopComponent(TopComponent tc) {
314: getCentral().addModeClosedTopComponent(this , tc);
315: }
316:
317: public void addUnloadedTopComponent(String tcID) {
318: getCentral().addModeUnloadedTopComponent(this , tcID);
319: }
320:
321: public void setUnloadedSelectedTopComponent(String tcID) {
322: getCentral().setUnloadedSelectedTopComponent(this , tcID);
323: }
324:
325: public void setUnloadedPreviousSelectedTopComponent(String tcID) {
326: getCentral()
327: .setUnloadedPreviousSelectedTopComponent(this , tcID);
328: }
329:
330: public List<String> getOpenedTopComponentsIDs() {
331: return getCentral().getModeOpenedTopComponentsIDs(this );
332: }
333:
334: public List getClosedTopComponentsIDs() {
335: return getCentral().getModeClosedTopComponentsIDs(this );
336: }
337:
338: public List getTopComponentsIDs() {
339: return getCentral().getModeTopComponentsIDs(this );
340: }
341:
342: /** Gets opened top component position in the mode */
343: public int getTopComponentTabPosition(TopComponent tc) {
344: return getCentral().getModeTopComponentTabPosition(this , tc);
345: }
346:
347: /** Sets and updates the state of associated frame, if frame exists.
348: * Otherwise remembers state for futher use
349: */
350: public void setFrameState(int state) {
351: getCentral().setModeFrameState(this , state);
352: }
353:
354: /** @return state of the frame
355: * If frame exists, its real state is returned.
356: * Last remembered frame state is returned if frame currently
357: * doesn't exist. FrameType.NORMAL is returned as default if state cannot be
358: * obtained by mentioned procedures.
359: */
360: public int getFrameState() {
361: return getCentral().getModeFrameState(this );
362: }
363:
364: /** Indicates whether this mode is permanent, it means it is kept in model
365: * even in case it becomes empty. */
366: public boolean isPermanent() {
367: return getCentral().isModePermanent(this );
368: }
369:
370: /** Indicates whether this mode has no TopComponents. */
371: public boolean isEmpty() {
372: return getCentral().isModeEmpty(this );
373: }
374:
375: public boolean containsTopComponent(TopComponent tc) {
376: return getCentral().containsModeTopComponent(this , tc);
377: }
378:
379: /** Gets state of mode. Either split or separate. */
380: public int getState() {
381: return getCentral().getModeState(this );
382: }
383:
384: /** Gets kind, either editor or view. */
385: public int getKind() {
386: return getCentral().getModeKind(this );
387: }
388:
389: /** Gets side, either null for view and editor kinds, a side constant for sliding kind.. */
390: public String getSide() {
391: return getCentral().getModeSide(this );
392: }
393:
394: // Contstraints and split weights are saved in split structure at wm model level.
395: /** Sets constraints for mode. */
396: public void setConstraints(SplitConstraint[] constraints) {
397: WindowManagerImpl.getInstance().setModeConstraints(this ,
398: constraints);
399: }
400:
401: /** @return Current constraints of this mode, null by default */
402: public SplitConstraint[] getConstraints() {
403: return WindowManagerImpl.getInstance().getModeConstraints(this );
404: }
405:
406: /** Removes TopComponent from this mode. */
407: public void removeTopComponent(TopComponent tc) {
408: getCentral().removeModeTopComponent(this , tc);
409: }
410:
411: public void removeTopComponents(Set topComponentSet) {
412: for (Iterator it = topComponentSet.iterator(); it.hasNext();) {
413: TopComponent tc = (TopComponent) it.next();
414: removeTopComponent(tc);
415: }
416: }
417:
418: // XXX Only use for yet unloaded components, for PersistenceHandler only.
419: public void removeClosedTopComponentID(String tcID) {
420: getCentral().removeModeClosedTopComponentID(this , tcID);
421: }
422:
423: // XXX It is used for user actions only, to prohibit mixing
424: // of view and editor components.
425: /** Indicates whether this mode can contain specified TopComponent. */
426: public boolean canContain(TopComponent tc) {
427: if (Constants.SWITCH_MODE_ADD_NO_RESTRICT
428: || WindowManagerImpl.getInstance()
429: .isTopComponentAllowedToMoveAnywhere(tc)) {
430: return true;
431: }
432:
433: ModeImpl mode = (ModeImpl) WindowManagerImpl.getInstance()
434: .findMode(tc);
435: if (mode == null) {
436: return true;
437: }
438: // allow mixing of view and sliding modes
439: int myKind = getKind();
440: int otherKind = mode.getKind();
441:
442: return (myKind == otherKind)
443: || (myKind != Constants.MODE_KIND_EDITOR && otherKind != Constants.MODE_KIND_EDITOR);
444: }
445:
446: void doFirePropertyChange(final String propName,
447: final Object oldValue, final Object newValue) {
448: // PENDING When #37529 finished, then uncomment the next row and move the
449: // checks of AWT thread away.
450: // WindowManagerImpl.assertEventDispatchThread();
451: if (SwingUtilities.isEventDispatchThread()) {
452: changeSupport.firePropertyChange(propName, oldValue,
453: newValue);
454: } else {
455: SwingUtilities.invokeLater(new Runnable() {
456: public void run() {
457: changeSupport.firePropertyChange(propName,
458: oldValue, newValue);
459: }
460: });
461: }
462: }
463:
464: /** @return string description of this mode */
465: public String toString() {
466: // #42995 - don't scream when toString called from non-AWT thread
467: return super .toString() + "[" + getCentral().getModeName(this )
468: + "]"; // NOI18N
469: }
470:
471: /** Accessor to central unit. Helper method. */
472: private static Central getCentral() {
473: return WindowManagerImpl.getInstance().getCentral();
474: }
475:
476: ////////////////////
477: // Utility methods>>
478: /*private*/static String getUnusedModeName() {
479: String base = MODE_ANONYMOUS_NAME;
480:
481: // don't allow base to be too long, because will act as file name too
482: // PENDING Maximal length is 20.
483: if (base.length() > 20) {
484: base = base.substring(0, 20);
485: }
486:
487: // add numbers to the name
488: String result;
489: int modeNumber = 1;
490: WindowManagerImpl wm = WindowManagerImpl.getInstance();
491: while (wm.findMode(result = base + "_" + modeNumber) != null) { // NOI18N
492: modeNumber++;
493: }
494: return result;
495: }
496: // Utility methods<<
497: ////////////////////
498:
499: }
|