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.netbeans.core.windows.model.ModelElement;
045: import org.openide.windows.TopComponent;
046:
047: import java.awt.*;
048: import java.util.*;
049: import java.util.List;
050:
051: /**
052: * Snapshot of split structure in model.
053: *
054: * @author Peter Zavadsky
055: */
056: public class ModeStructureSnapshot {
057:
058: private final ElementSnapshot splitRootSnapshot;
059:
060: private final Set<ModeSnapshot> separateModeSnapshots;
061:
062: private final Set<SlidingModeSnapshot> slidingModeSnapshots;
063:
064: /** Creates a new instance of ModesModelSnapshot. */
065: public ModeStructureSnapshot(ElementSnapshot splitRootSnapshot,
066: Set<ModeSnapshot> separateModeSnapshots,
067: Set<SlidingModeSnapshot> slidingModeSnapshots) {
068: this .splitRootSnapshot = splitRootSnapshot;
069: this .separateModeSnapshots = separateModeSnapshots;
070: this .slidingModeSnapshots = slidingModeSnapshots;
071: }
072:
073: public ElementSnapshot getSplitRootSnapshot() {
074: return splitRootSnapshot;
075: }
076:
077: public ModeSnapshot[] getSeparateModeSnapshots() {
078: return separateModeSnapshots.toArray(new ModeSnapshot[0]);
079: }
080:
081: public SlidingModeSnapshot[] getSlidingModeSnapshots() {
082: return slidingModeSnapshots.toArray(new SlidingModeSnapshot[0]);
083: }
084:
085: /** @param name name of mode */
086: public ModeSnapshot findModeSnapshot(String name) {
087: ModeSnapshot ma = findModeSnapshotOfName(splitRootSnapshot,
088: name);
089: if (ma != null) {
090: return ma;
091: }
092:
093: for (Iterator it = separateModeSnapshots.iterator(); it
094: .hasNext();) {
095: ma = (ModeSnapshot) it.next();
096: if (name.equals(ma.getName())) {
097: return ma;
098: }
099: }
100:
101: for (Iterator it = slidingModeSnapshots.iterator(); it
102: .hasNext();) {
103: ma = (SlidingModeSnapshot) it.next();
104: if (name.equals(ma.getName())) {
105: return ma;
106: }
107: }
108:
109: return null;
110: }
111:
112: private static ModeSnapshot findModeSnapshotOfName(
113: ElementSnapshot snapshot, String name) {
114: if (snapshot instanceof ModeSnapshot) {
115: ModeSnapshot ma = (ModeSnapshot) snapshot;
116: if (name.equals(ma.getName())) {
117: return ma;
118: }
119: } else if (snapshot instanceof SplitSnapshot) {
120: SplitSnapshot split = (SplitSnapshot) snapshot;
121: for (Iterator it = split.getChildSnapshots().iterator(); it
122: .hasNext();) {
123: ElementSnapshot child = (ElementSnapshot) it.next();
124: ModeSnapshot ma = findModeSnapshotOfName(child, name);
125: if (ma != null) {
126: return ma;
127: }
128: }
129: } else if (snapshot instanceof EditorSnapshot) {
130: EditorSnapshot editorSnapshot = (EditorSnapshot) snapshot;
131: ModeSnapshot ma = findModeSnapshotOfName(editorSnapshot
132: .getEditorAreaSnapshot(), name);
133: if (ma != null) {
134: return ma;
135: }
136: }
137:
138: return null;
139: }
140:
141: /** Superclass for snapshot of model element.
142: * There are three types, split, mode, and editor (represents editor area) type. */
143: public static abstract class ElementSnapshot {
144: // PENDING revise
145: /** Corresponding object in model (SplitNode or ModeNode or ModeImpl for separate mode). */
146: private final ModelElement originator;
147:
148: private/*final*/SplitSnapshot parent;
149:
150: public ElementSnapshot(ModelElement originator,
151: SplitSnapshot parent) {
152: this .originator = originator;
153: setParent(parent);
154: }
155:
156: /** Gets originator object. Used only in model. */
157: public ModelElement getOriginator() {
158: return originator;
159: }
160:
161: public void setParent(SplitSnapshot parent) {
162: if (this .parent == null) {
163: this .parent = parent;
164: } else {
165: throw new IllegalStateException(
166: "Parent can be set only once," // NOI18N
167: + " this.parent="
168: + this .parent
169: + ", parent=" + parent); // NOI18N
170: }
171: }
172:
173: public SplitSnapshot getParent() {
174: return parent;
175: }
176:
177: public boolean originatorEquals(ElementSnapshot o) {
178: return getClass().equals(o.getClass()) // To prevent mismatch between split and mode snapshot.
179: // Split has now originator corresponding to first child.
180: && ((ElementSnapshot) o).originator == originator;
181: }
182:
183: public abstract double getResizeWeight();
184:
185: /** Indicates whether component represented by this element is visible or not. */
186: public abstract boolean isVisibleInSplit();
187:
188: /** Indicates whether there is at least one visible descendant (split relevant). */
189: public abstract boolean hasVisibleDescendant();
190:
191: public String toString() {
192: return "Snapshot[originatorHash="
193: + (originator != null ? Integer
194: .toHexString(originator.hashCode())
195: : "null") + "]"; // NOI18N
196: }
197: }
198:
199: /** */
200: public static class SplitSnapshot extends ElementSnapshot {
201: private final int orientation;
202: private final List<ElementSnapshot> childSnapshots = new ArrayList<ElementSnapshot>();
203: private final Map<ElementSnapshot, Double> childSnapshot2splitWeight = new HashMap<ElementSnapshot, Double>();
204: private final double resizeWeight;
205:
206: public SplitSnapshot(ModelElement originator,
207: SplitSnapshot parent, int orientation,
208: List<ElementSnapshot> childSnapshots,
209: Map<ElementSnapshot, Double> childSnapshot2splitWeight,
210: double resizeWeight) {
211: super (originator, parent); // XXX PENDING originator corresponds to the first child model element.
212:
213: this .orientation = orientation;
214: this .childSnapshots.addAll(childSnapshots);
215: this .childSnapshot2splitWeight
216: .putAll(childSnapshot2splitWeight);
217: this .resizeWeight = resizeWeight;
218: }
219:
220: public int getOrientation() {
221: return orientation;
222: }
223:
224: public List getVisibleChildSnapshots() {
225: List<ElementSnapshot> l = getChildSnapshots();
226: for (Iterator<ElementSnapshot> it = l.iterator(); it
227: .hasNext();) {
228: ElementSnapshot child = it.next();
229: if (!child.hasVisibleDescendant()) {
230: it.remove();
231: }
232: }
233:
234: return l;
235: }
236:
237: public List<ElementSnapshot> getChildSnapshots() {
238: return new ArrayList<ElementSnapshot>(childSnapshots);
239: }
240:
241: public double getChildSnapshotSplitWeight(
242: ElementSnapshot childSnapshot) {
243: Double d = (Double) childSnapshot2splitWeight
244: .get(childSnapshot);
245: return d == null ? -1 : d.doubleValue();
246: }
247:
248: public double getResizeWeight() {
249: return resizeWeight;
250: }
251:
252: /** Indicates whether component represented by this node is visible or not. */
253: public boolean isVisibleInSplit() {
254: int count = 0;
255: for (Iterator it = getChildSnapshots().iterator(); it
256: .hasNext();) {
257: ElementSnapshot child = (ElementSnapshot) it.next();
258: if (child.hasVisibleDescendant()) {
259: count++;
260: // At leas two are needed so the split is showing.
261: if (count >= 2) {
262: return true;
263: }
264: }
265: }
266:
267: return false;
268: }
269:
270: /** Indicates whether there is at least one visible descendant. */
271: public boolean hasVisibleDescendant() {
272: for (Iterator it = getChildSnapshots().iterator(); it
273: .hasNext();) {
274: ElementSnapshot child = (ElementSnapshot) it.next();
275: if (child.hasVisibleDescendant()) {
276: return true;
277: }
278: }
279:
280: return false;
281: }
282:
283: public String toString() {
284: return super .toString()
285: + "[orientation=" // NOI18N
286: + (orientation == Constants.HORIZONTAL ? "horizontal"
287: : "vertical") // NOI18N
288: + "]"; // NOI18N
289: }
290:
291: }
292:
293: /** */
294: public static class ModeSnapshot extends ElementSnapshot {
295: private final ModeImpl mode;
296:
297: private final String name;
298: private final int state;
299: private final int kind;
300: private final Rectangle bounds;
301: private final int frameState;
302: private final TopComponent selectedTopComponent;
303: private final TopComponent[] openedTopComponents;
304: private final double resizeWeight;
305:
306: public ModeSnapshot(ModelElement originator,
307: SplitSnapshot parent, ModeImpl mode, double resizeWeight) {
308: super (originator, parent);
309:
310: this .mode = mode;
311:
312: this .name = mode.getName();
313: this .state = mode.getState();
314: this .kind = mode.getKind();
315: this .bounds = mode.getBounds();
316: this .frameState = mode.getFrameState();
317: this .selectedTopComponent = mode.getSelectedTopComponent();
318: this .openedTopComponents = mode.getOpenedTopComponents()
319: .toArray(new TopComponent[0]);
320: this .resizeWeight = resizeWeight;
321: }
322:
323: public boolean originatorEquals(ElementSnapshot o) {
324: if (!super .originatorEquals(o)) {
325: return false;
326: }
327:
328: // XXX Even if originators are same, they differ if their states are different.
329: // Difference -> split vs. separate representations.
330: ModeSnapshot me = (ModeSnapshot) o;
331: return getState() == me.getState();
332: }
333:
334: public ModeImpl getMode() {
335: return mode;
336: }
337:
338: public String getName() {
339: return name;
340: }
341:
342: public int getState() {
343: return state;
344: }
345:
346: public int getKind() {
347: return kind;
348: }
349:
350: public Rectangle getBounds() {
351: return bounds;
352: }
353:
354: public int getFrameState() {
355: return frameState;
356: }
357:
358: public TopComponent getSelectedTopComponent() {
359: return selectedTopComponent;
360: }
361:
362: public TopComponent[] getOpenedTopComponents() {
363: return openedTopComponents;
364: }
365:
366: public double getResizeWeight() {
367: return resizeWeight;
368: }
369:
370: public boolean isVisibleInSplit() {
371: if (getOpenedTopComponents().length == 0) {
372: return false;
373: }
374:
375: if (getState() == Constants.MODE_STATE_SEPARATED) {
376: return false;
377: }
378:
379: if (mode.getKind() == Constants.MODE_KIND_EDITOR) {
380: WindowManagerImpl wm = WindowManagerImpl.getInstance();
381: if (null != wm.getEditorMaximizedMode()
382: && wm.getEditorMaximizedMode() != mode)
383: return false;
384: }
385:
386: return true;
387: }
388:
389: public boolean isVisibleSeparate() {
390: if (getOpenedTopComponents().length == 0) {
391: return false;
392: }
393:
394: if (getState() == Constants.MODE_STATE_JOINED) {
395: return false;
396: }
397:
398: return true;
399: }
400:
401: public boolean hasVisibleDescendant() {
402: return isVisibleInSplit();
403: }
404:
405: public String toString() {
406: return super .toString() + "[name=" + mode.getName()
407: + ", permanent="
408: + mode.isPermanent() // NOI18N
409: + ", constraints="
410: + Arrays.asList(mode.getConstraints()) + "]"; // NOI18N
411: }
412:
413: }
414:
415: public static class SlidingModeSnapshot extends ModeSnapshot {
416:
417: private final String side;
418: private final Map<TopComponent, Integer> slideInSizes;
419:
420: public SlidingModeSnapshot(ModeImpl mode, String side,
421: Map<TopComponent, Integer> slideInSizes) {
422: super (null, null, mode, 0D);
423:
424: this .side = side;
425: this .slideInSizes = slideInSizes;
426: }
427:
428: public String getSide() {
429: return side;
430: }
431:
432: public Map<TopComponent, Integer> getSlideInSizes() {
433: return slideInSizes;
434: }
435: } // end of SlidingModeSnapshot
436:
437: /** */
438: public static class EditorSnapshot extends ElementSnapshot {
439: private final ModeStructureSnapshot.ElementSnapshot editorAreaSnapshot;
440: private final double resizeWeight;
441:
442: public EditorSnapshot(ModelElement originator,
443: SplitSnapshot parent,
444: ElementSnapshot editorAreaSnapshot, double resizeWeight) {
445: super (originator, parent);
446:
447: this .editorAreaSnapshot = editorAreaSnapshot;
448: this .resizeWeight = resizeWeight;
449: }
450:
451: public double getResizeWeight() {
452: return resizeWeight;
453: }
454:
455: public ElementSnapshot getEditorAreaSnapshot() {
456: return editorAreaSnapshot;
457: }
458:
459: /** Indicates whether component represented by this node is visible or not. */
460: public boolean isVisibleInSplit() {
461: if (Constants.SWITCH_HIDE_EMPTY_DOCUMENT_AREA) {
462: return editorAreaSnapshot.isVisibleInSplit();
463: } else {
464: return true;
465: }
466: }
467:
468: /** Indicates whether there is at least one visible descendant. */
469: public boolean hasVisibleDescendant() {
470: return isVisibleInSplit();
471: }
472:
473: public String toString() {
474: return super .toString() + "\n" + editorAreaSnapshot; // NOI18N
475: }
476: }
477:
478: public String toString() {
479: StringBuffer sb = new StringBuffer();
480: sb.append("\nModesSnapshot hashCode="
481: + Integer.toHexString(hashCode())); // NOI18N
482: sb.append("\nSplit modes:\n"); // NOI18N
483: sb.append(dumpSnapshot(splitRootSnapshot, 0));
484: sb.append("\nSeparate Modes:"); // NOI18N
485: sb.append(dumpSet(separateModeSnapshots));
486: return sb.toString();
487: }
488:
489: private static String dumpSnapshot(ElementSnapshot snapshot,
490: int indent) {
491: StringBuffer sb = new StringBuffer();
492: String indentString = createIndentString(indent);
493:
494: if (snapshot instanceof SplitSnapshot) {
495: SplitSnapshot splitSnapshot = (SplitSnapshot) snapshot;
496: sb.append(indentString + "split=" + splitSnapshot); // NOI18N
497: indent++;
498: for (Iterator it = splitSnapshot.getChildSnapshots()
499: .iterator(); it.hasNext();) {
500: ElementSnapshot child = (ElementSnapshot) it.next();
501: sb.append("\n" + dumpSnapshot(child, indent)); // NOI18N
502: }
503: } else if (snapshot instanceof ModeSnapshot) {
504: sb.append(indentString + "mode=" + snapshot); // NOI18N
505: } else if (snapshot instanceof EditorSnapshot) {
506: sb.append(indentString + "editor=" + snapshot); // NOI18N
507: sb.append(dumpSnapshot(((EditorSnapshot) snapshot)
508: .getEditorAreaSnapshot(), ++indent));
509: }
510:
511: return sb.toString();
512: }
513:
514: private static String createIndentString(int indent) {
515: StringBuffer sb = new StringBuffer(indent);
516: for (int i = 0; i < indent; i++) {
517: sb.append(' ');
518: }
519:
520: return sb.toString();
521: }
522:
523: private static String dumpSet(Set separateModes) {
524: StringBuffer sb = new StringBuffer();
525:
526: for (java.util.Iterator it = separateModes.iterator(); it
527: .hasNext();) {
528: sb.append("\nmode=" + it.next());
529: }
530:
531: return sb.toString();
532: }
533:
534: }
|