001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal;
011:
012: import java.util.ArrayList;
013: import java.util.HashMap;
014: import java.util.Iterator;
015: import java.util.Map;
016:
017: import org.eclipse.core.runtime.IStatus;
018: import org.eclipse.core.runtime.MultiStatus;
019: import org.eclipse.core.runtime.Status;
020: import org.eclipse.swt.SWT;
021: import org.eclipse.swt.dnd.DND;
022: import org.eclipse.swt.dnd.DropTarget;
023: import org.eclipse.swt.graphics.Rectangle;
024: import org.eclipse.swt.widgets.Composite;
025: import org.eclipse.swt.widgets.Control;
026: import org.eclipse.ui.IMemento;
027: import org.eclipse.ui.PlatformUI;
028: import org.eclipse.ui.internal.StartupThreading.StartupRunnable;
029: import org.eclipse.ui.internal.presentations.PresentationSerializer;
030: import org.eclipse.ui.presentations.IStackPresentationSite;
031: import org.eclipse.ui.presentations.StackPresentation;
032:
033: /**
034: * Represents the area set aside for editor workbooks.
035: * This container only accepts EditorStack and PartSash
036: * as layout parts.
037: *
038: * Note no views are allowed within this container.
039: */
040: public class EditorSashContainer extends PartSashContainer {
041:
042: static final String DEFAULT_WORKBOOK_ID = "DefaultEditorWorkbook";//$NON-NLS-1$
043:
044: private ArrayList editorWorkbooks = new ArrayList(3);
045:
046: private EditorStack activeEditorWorkbook;
047:
048: private DropTarget dropTarget;
049:
050: public EditorSashContainer(String editorId, WorkbenchPage page,
051: Composite parent) {
052: super (editorId, page, parent);
053:
054: createDefaultWorkbook();
055: }
056:
057: /**
058: * Add an editor to the active workbook.
059: */
060: public void addEditor(EditorPane pane, EditorStack stack) {
061: //EditorStack workbook = getActiveWorkbook();
062: stack.add(pane);
063: }
064:
065: /* (non-Javadoc)
066: * @see org.eclipse.ui.internal.PartSashContainer#addChild(org.eclipse.ui.internal.PartSashContainer.RelationshipInfo)
067: */
068: protected void addChild(RelationshipInfo info) {
069: super .addChild(info);
070:
071: updateStackButtons();
072: }
073:
074: /**
075: * Hides the min/max buttons for all editor stacks
076: * -except- for the upper/left one.
077: */
078: public void updateStackButtons() {
079: // This is applicable only when the new
080: // min/max behaviour is being used
081: Perspective persp = getPage().getActivePerspective();
082: if (!Perspective.useNewMinMax(persp))
083: return;
084:
085: // Find the upper Right editor stack
086: LayoutPart[] stacks = getChildren();
087: EditorStack winner = getUpperRightEditorStack(stacks);
088:
089: // Now hide the buttons for all but the upper right stack
090: for (int i = 0; i < stacks.length; i++) {
091: if (!(stacks[i] instanceof EditorStack))
092: continue;
093: ((EditorStack) stacks[i]).showMinMax(stacks[i] == winner);
094: }
095:
096: // Force the stack's presentation state to match its perspective
097: persp.refreshEditorAreaVisibility();
098: }
099:
100: /**
101: * @param stacks
102: * @return the EditorStack in the upper right position
103: */
104: public EditorStack getUpperRightEditorStack(LayoutPart[] stacks) {
105: if (stacks == null)
106: stacks = getChildren();
107:
108: // Find the upper Right editor stack
109: EditorStack winner = null;
110: Rectangle winnerRect = null;
111:
112: for (int i = 0; i < stacks.length; i++) {
113: if (!(stacks[i] instanceof EditorStack))
114: continue;
115:
116: EditorStack stack = (EditorStack) stacks[i];
117: Rectangle bb = stack.getBounds();
118: if (winnerRect == null || bb.y < winnerRect.y
119: || (bb.y == winnerRect.y && bb.x > winnerRect.x)) {
120: winner = stack;
121: winnerRect = bb;
122: }
123: }
124:
125: return winner;
126: }
127:
128: /**
129: * Notification that a child layout part has been
130: * added to the container. Subclasses may override
131: * this method to perform any container specific
132: * work.
133: */
134: protected void childAdded(LayoutPart child) {
135: super .childAdded(child);
136:
137: if (child instanceof EditorStack) {
138: editorWorkbooks.add(child);
139: }
140: }
141:
142: /**
143: * Notification that a child layout part has been
144: * removed from the container. Subclasses may override
145: * this method to perform any container specific
146: * work.
147: */
148: protected void childRemoved(LayoutPart child) {
149: super .childRemoved(child);
150:
151: if (child instanceof EditorStack) {
152: editorWorkbooks.remove(child);
153: if (activeEditorWorkbook == child) {
154: setActiveWorkbook(null, false);
155: }
156:
157: updateStackButtons();
158: }
159: }
160:
161: protected EditorStack createDefaultWorkbook() {
162: EditorStack newWorkbook = EditorStack.newEditorWorkbook(this ,
163: page);
164: newWorkbook.setID(DEFAULT_WORKBOOK_ID);
165: add(newWorkbook);
166: return newWorkbook;
167: }
168:
169: /**
170: * Subclasses override this method to specify
171: * the composite to use to parent all children
172: * layout parts it contains.
173: */
174: protected Composite createParent(Composite parentWidget) {
175: return new Composite(parentWidget, SWT.NONE);
176: }
177:
178: /**
179: * Dispose of the editor area.
180: */
181: public void dispose() {
182: // Free editor workbooks.
183: editorWorkbooks.clear();
184:
185: // Free rest.
186: super .dispose();
187: }
188:
189: /**
190: * Subclasses override this method to dispose
191: * of any swt resources created during createParent.
192: */
193: protected void disposeParent() {
194: this .parent.dispose();
195: }
196:
197: /**
198: * Return the editor workbook which is active.
199: */
200: public EditorStack getActiveWorkbook() {
201: if (activeEditorWorkbook == null) {
202: if (editorWorkbooks.size() < 1) {
203: setActiveWorkbook(createDefaultWorkbook(), false);
204: } else {
205: setActiveWorkbook((EditorStack) editorWorkbooks.get(0),
206: false);
207: }
208: }
209:
210: return activeEditorWorkbook;
211: }
212:
213: /**
214: * Return the editor workbook id which is active.
215: */
216: public String getActiveWorkbookID() {
217: return getActiveWorkbook().getID();
218: }
219:
220: /**
221: * Return the all the editor workbooks.
222: */
223: public ArrayList getEditorWorkbooks() {
224: return (ArrayList) editorWorkbooks.clone();
225: }
226:
227: /**
228: * Return the all the editor workbooks.
229: */
230: public int getEditorWorkbookCount() {
231: return editorWorkbooks.size();
232: }
233:
234: /**
235: * Return true is the workbook specified
236: * is the active one.
237: */
238: protected boolean isActiveWorkbook(EditorStack workbook) {
239: return activeEditorWorkbook == workbook;
240: }
241:
242: /**
243: * Find the sashs around the specified part.
244: */
245: public void findSashes(LayoutPart pane, PartPane.Sashes sashes) {
246: //Find the sashes around the current editor and
247: //then the sashes around the editor area.
248: super .findSashes(pane, sashes);
249:
250: ILayoutContainer container = getContainer();
251: if (container != null) {
252: container.findSashes(this , sashes);
253: }
254: }
255:
256: /**
257: * Remove all the editors
258: */
259: public void removeAllEditors() {
260: EditorStack currentWorkbook = getActiveWorkbook();
261:
262: // Iterate over a copy so the original can be modified.
263: Iterator workbooks = ((ArrayList) editorWorkbooks.clone())
264: .iterator();
265: while (workbooks.hasNext()) {
266: EditorStack workbook = (EditorStack) workbooks.next();
267: workbook.removeAll();
268: if (workbook != currentWorkbook) {
269: remove(workbook);
270: workbook.dispose();
271: }
272: }
273: }
274:
275: /**
276: * Remove an editor from its' workbook.
277: */
278: public void removeEditor(EditorPane pane) {
279: EditorStack workbook = pane.getWorkbook();
280: if (workbook == null) {
281: return;
282: }
283: workbook.remove(pane);
284:
285: // remove the editor workbook if empty
286: if (workbook.getItemCount() < 1 /* && editorWorkbooks.size() > 1*/) {
287: // If the user closes the last editor and the editor area
288: // is maximized, restore it
289: Perspective persp = getPage().getActivePerspective();
290: if (Perspective.useNewMinMax(persp)) {
291: if (persp.getPresentation().getMaximizedStack() instanceof EditorStack)
292: persp
293: .getPresentation()
294: .getMaximizedStack()
295: .setState(
296: IStackPresentationSite.STATE_RESTORED);
297: }
298:
299: remove(workbook);
300: workbook.dispose();
301: }
302: }
303:
304: /**
305: * @see IPersistablePart
306: */
307: public IStatus restoreState(IMemento memento) {
308: MultiStatus result = new MultiStatus(
309: PlatformUI.PLUGIN_ID,
310: IStatus.OK,
311: WorkbenchMessages.RootLayoutContainer_problemsRestoringPerspective,
312: null);
313:
314: // Remove the default editor workbook that is
315: // initialy created with the editor area.
316: if (children != null) {
317: StartupThreading
318: .runWithoutExceptions(new StartupRunnable() {
319:
320: public void runWithException() throws Throwable {
321: EditorStack defaultWorkbook = null;
322: for (int i = 0; i < children.size(); i++) {
323: LayoutPart child = (LayoutPart) children
324: .get(i);
325: if (child.getID() == DEFAULT_WORKBOOK_ID) {
326: defaultWorkbook = (EditorStack) child;
327: if (defaultWorkbook.getItemCount() > 0) {
328: defaultWorkbook = null;
329: }
330: }
331: }
332: if (defaultWorkbook != null) {
333: remove(defaultWorkbook);
334: }
335: }
336: });
337:
338: }
339:
340: // Restore the relationship/layout
341: IMemento[] infos = memento
342: .getChildren(IWorkbenchConstants.TAG_INFO);
343: final Map mapIDtoPart = new HashMap(infos.length);
344:
345: for (int i = 0; i < infos.length; i++) {
346: // Get the info details.
347: IMemento childMem = infos[i];
348: final String partID = childMem
349: .getString(IWorkbenchConstants.TAG_PART);
350: final String relativeID = childMem
351: .getString(IWorkbenchConstants.TAG_RELATIVE);
352: int relationship = 0;
353: int left = 0, right = 0;
354: float ratio = 0.5f;
355: if (relativeID != null) {
356: relationship = childMem.getInteger(
357: IWorkbenchConstants.TAG_RELATIONSHIP)
358: .intValue();
359: Float ratioFloat = childMem
360: .getFloat(IWorkbenchConstants.TAG_RATIO);
361: Integer leftInt = childMem
362: .getInteger(IWorkbenchConstants.TAG_RATIO_LEFT);
363: Integer rightInt = childMem
364: .getInteger(IWorkbenchConstants.TAG_RATIO_RIGHT);
365: if (leftInt != null && rightInt != null) {
366: left = leftInt.intValue();
367: right = rightInt.intValue();
368: } else if (ratioFloat != null) {
369: ratio = ratioFloat.floatValue();
370: }
371: }
372:
373: final EditorStack workbook[] = new EditorStack[1];
374: StartupThreading
375: .runWithoutExceptions(new StartupRunnable() {
376:
377: public void runWithException() throws Throwable {
378: // Create the part.
379: workbook[0] = EditorStack
380: .newEditorWorkbook(
381: EditorSashContainer.this ,
382: page);
383: workbook[0].setID(partID);
384: // 1FUN70C: ITPUI:WIN - Shouldn't set Container when not active
385: workbook[0]
386: .setContainer(EditorSashContainer.this );
387: }
388: });
389:
390: IMemento workbookMemento = childMem
391: .getChild(IWorkbenchConstants.TAG_FOLDER);
392: if (workbookMemento != null) {
393: result.add(workbook[0].restoreState(workbookMemento));
394: }
395:
396: final int myLeft = left, myRight = right, myRelationship = relationship;
397: final float myRatio = ratio;
398: StartupThreading
399: .runWithoutExceptions(new StartupRunnable() {
400:
401: public void runWithException() throws Throwable {
402: // Add the part to the layout
403: if (relativeID == null) {
404: add(workbook[0]);
405: } else {
406: LayoutPart refPart = (LayoutPart) mapIDtoPart
407: .get(relativeID);
408: if (refPart != null) {
409: //$TODO pass in left and right
410: if (myLeft == 0 || myRight == 0) {
411: add(workbook[0],
412: myRelationship,
413: myRatio, refPart);
414: } else {
415: add(workbook[0],
416: myRelationship, myLeft,
417: myRight, refPart);
418: }
419: } else {
420: WorkbenchPlugin
421: .log("Unable to find part for ID: " + relativeID);//$NON-NLS-1$
422: }
423: }
424: }
425: });
426:
427: mapIDtoPart.put(partID, workbook[0]);
428: }
429:
430: return result;
431: }
432:
433: /**
434: * @see IPersistablePart
435: */
436: public IStatus saveState(IMemento memento) {
437: RelationshipInfo[] relationships = computeRelation();
438: MultiStatus result = new MultiStatus(
439: PlatformUI.PLUGIN_ID,
440: IStatus.OK,
441: WorkbenchMessages.RootLayoutContainer_problemsSavingPerspective,
442: null);
443:
444: for (int i = 0; i < relationships.length; i++) {
445: // Save the relationship info ..
446: // private LayoutPart part;
447: // private int relationship;
448: // private float ratio;
449: // private LayoutPart relative;
450: RelationshipInfo info = relationships[i];
451: IMemento childMem = memento
452: .createChild(IWorkbenchConstants.TAG_INFO);
453: childMem.putString(IWorkbenchConstants.TAG_PART, info.part
454: .getID());
455:
456: EditorStack stack = (EditorStack) info.part;
457: if (stack != null) {
458: IMemento folderMem = childMem
459: .createChild(IWorkbenchConstants.TAG_FOLDER);
460: result.add(stack.saveState(folderMem));
461: }
462:
463: if (info.relative != null) {
464: childMem.putString(IWorkbenchConstants.TAG_RELATIVE,
465: info.relative.getID());
466: childMem.putInteger(
467: IWorkbenchConstants.TAG_RELATIONSHIP,
468: info.relationship);
469: childMem.putInteger(IWorkbenchConstants.TAG_RATIO_LEFT,
470: info.left);
471: childMem
472: .putInteger(
473: IWorkbenchConstants.TAG_RATIO_RIGHT,
474: info.right);
475: // Note: "ratio" is not used in newer versions of Eclipse, which use "left"
476: // and "right" (above) instead
477: childMem.putFloat(IWorkbenchConstants.TAG_RATIO, info
478: .getRatio());
479: }
480: }
481:
482: return result;
483: }
484:
485: /**
486: * Set the editor workbook which is active.
487: */
488: public void setActiveWorkbook(EditorStack newWorkbook,
489: boolean hasFocus) {
490: if (newWorkbook != null) {
491: if (newWorkbook.isDisposed()) {
492: return;
493: }
494: if (!editorWorkbooks.contains(newWorkbook)) {
495: return;
496: }
497: }
498: EditorStack oldWorkbook = activeEditorWorkbook;
499: activeEditorWorkbook = newWorkbook;
500:
501: if (oldWorkbook != null && oldWorkbook != newWorkbook) {
502: oldWorkbook.setActive(StackPresentation.AS_INACTIVE);
503: }
504:
505: if (newWorkbook != null) {
506: if (hasFocus) {
507: newWorkbook
508: .setActive(StackPresentation.AS_ACTIVE_FOCUS);
509: } else {
510: newWorkbook
511: .setActive(StackPresentation.AS_ACTIVE_NOFOCUS);
512: }
513: }
514:
515: updateTabList();
516: }
517:
518: /**
519: * Set the editor workbook which is active.
520: */
521: public void setActiveWorkbookFromID(String id) {
522: for (int i = 0; i < editorWorkbooks.size(); i++) {
523: EditorStack workbook = (EditorStack) editorWorkbooks.get(i);
524: if (workbook.getID().equals(id)) {
525: setActiveWorkbook(workbook, false);
526: }
527: }
528: }
529:
530: public EditorStack getWorkbookFromID(String id) {
531: for (int i = 0; i < editorWorkbooks.size(); i++) {
532: EditorStack workbook = (EditorStack) editorWorkbooks.get(i);
533: if (workbook.getID().equals(id)) {
534: return workbook;
535: }
536: }
537:
538: return null;
539: }
540:
541: /**
542: * Updates the editor area's tab list to include the active
543: * editor and its tab.
544: */
545: public void updateTabList() {
546: Composite parent = getParent();
547: if (parent != null) { // parent may be null on startup
548: EditorStack wb = getActiveWorkbook();
549: if (wb == null) {
550: parent.setTabList(new Control[0]);
551: } else {
552: parent.setTabList(wb.getTabList());
553: }
554: }
555: }
556:
557: /**
558: * @see org.eclipse.ui.internal.LayoutPart#createControl(org.eclipse.swt.widgets.Composite)
559: */
560: public void createControl(Composite parent) {
561: super .createControl(parent);
562:
563: //let the user drop files/editor input on the editor area
564: addDropSupport();
565: }
566:
567: private void addDropSupport() {
568: if (dropTarget == null) {
569: WorkbenchWindowConfigurer winConfigurer = ((WorkbenchWindow) page
570: .getWorkbenchWindow()).getWindowConfigurer();
571:
572: dropTarget = new DropTarget(getControl(), DND.DROP_DEFAULT
573: | DND.DROP_COPY | DND.DROP_LINK);
574: dropTarget.setTransfer(winConfigurer.getTransfers());
575: if (winConfigurer.getDropTargetListener() != null) {
576: dropTarget.addDropListener(winConfigurer
577: .getDropTargetListener());
578: }
579: }
580: }
581:
582: /* package */DropTarget getDropTarget() {
583: return dropTarget;
584: }
585:
586: /**
587: * @see org.eclipse.ui.internal.LayoutPart#getImportance()
588: */
589: public boolean isCompressible() {
590: //Added for bug 19524
591: return true;
592: }
593:
594: /* (non-Javadoc)
595: * @see org.eclipse.ui.internal.PartSashContainer#isStackType(org.eclipse.ui.internal.LayoutPart)
596: */
597: public boolean isStackType(LayoutPart toTest) {
598: return (toTest instanceof EditorStack);
599: }
600:
601: /* (non-Javadoc)
602: * @see org.eclipse.ui.internal.PartSashContainer#isPaneType(org.eclipse.ui.internal.LayoutPart)
603: */
604: public boolean isPaneType(LayoutPart toTest) {
605: return (toTest instanceof EditorPane);
606: }
607:
608: /* (non-Javadoc)
609: * @see org.eclipse.ui.internal.PartSashContainer#createStack(org.eclipse.ui.internal.LayoutPart)
610: */
611: protected PartStack createStack() {
612: EditorStack newWorkbook = EditorStack.newEditorWorkbook(this ,
613: page);
614:
615: return newWorkbook;
616: }
617:
618: /* (non-Javadoc)
619: * @see org.eclipse.ui.internal.PartSashContainer#setVisiblePart(org.eclipse.ui.internal.ILayoutContainer, org.eclipse.ui.internal.LayoutPart)
620: */
621: protected void setVisiblePart(ILayoutContainer container,
622: LayoutPart visiblePart) {
623: EditorStack refPart = (EditorStack) container;
624:
625: refPart.becomeActiveWorkbook(true);
626: refPart.setSelection(visiblePart);
627: }
628:
629: /* (non-Javadoc)
630: * @see org.eclipse.ui.internal.PartSashContainer#getVisiblePart(org.eclipse.ui.internal.ILayoutContainer)
631: */
632: protected LayoutPart getVisiblePart(ILayoutContainer container) {
633: EditorStack refPart = (EditorStack) container;
634:
635: return refPart.getSelection();
636: }
637:
638: /* (non-Javadoc)
639: * @see org.eclipse.ui.internal.PartSashContainer#pickPartToZoom()
640: */
641: public LayoutPart pickPartToZoom() {
642: return getActiveWorkbook();
643: }
644:
645: /**
646: * Restore the presentation state. Loop over the workbooks, create the appropriate serializer and pass to the presentation.
647: *
648: * @param areaMem the memento containing presentation
649: * @return the restoration status
650: */
651: public IStatus restorePresentationState(IMemento areaMem) {
652: for (Iterator i = getEditorWorkbooks().iterator(); i.hasNext();) {
653: final EditorStack workbook = (EditorStack) i.next();
654: final IMemento memento = workbook
655: .getSavedPresentationState();
656: if (memento == null) {
657: continue;
658: }
659: final PresentationSerializer serializer = new PresentationSerializer(
660: workbook.getPresentableParts());
661: StartupThreading
662: .runWithoutExceptions(new StartupRunnable() {
663:
664: public void runWithException() throws Throwable {
665: workbook.getPresentation().restoreState(
666: serializer, memento);
667: }
668: });
669:
670: }
671: return new Status(IStatus.OK, PlatformUI.PLUGIN_ID, 0, "", null); //$NON-NLS-1$
672: }
673: }
|