0001: /*******************************************************************************
0002: * Copyright (c) 2004 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Common Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/cpl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: *******************************************************************************/package org.eclipse.ui.examples.presentation.wrappedtabs;
0011:
0012: import org.eclipse.jface.action.MenuManager;
0013: import org.eclipse.jface.action.Separator;
0014: import org.eclipse.jface.util.Geometry;
0015: import org.eclipse.jface.util.IPropertyChangeListener;
0016: import org.eclipse.jface.util.PropertyChangeEvent;
0017: import org.eclipse.swt.SWT;
0018: import org.eclipse.swt.custom.ViewForm;
0019: import org.eclipse.swt.events.DisposeEvent;
0020: import org.eclipse.swt.events.DisposeListener;
0021: import org.eclipse.swt.events.MouseAdapter;
0022: import org.eclipse.swt.events.MouseEvent;
0023: import org.eclipse.swt.events.MouseListener;
0024: import org.eclipse.swt.events.PaintEvent;
0025: import org.eclipse.swt.events.PaintListener;
0026: import org.eclipse.swt.events.SelectionAdapter;
0027: import org.eclipse.swt.events.SelectionEvent;
0028: import org.eclipse.swt.graphics.Color;
0029: import org.eclipse.swt.graphics.Point;
0030: import org.eclipse.swt.graphics.Rectangle;
0031: import org.eclipse.swt.layout.GridData;
0032: import org.eclipse.swt.layout.GridLayout;
0033: import org.eclipse.swt.widgets.Composite;
0034: import org.eclipse.swt.widgets.Control;
0035: import org.eclipse.swt.widgets.Event;
0036: import org.eclipse.swt.widgets.Label;
0037: import org.eclipse.swt.widgets.Listener;
0038: import org.eclipse.swt.widgets.Menu;
0039: import org.eclipse.swt.widgets.ToolBar;
0040: import org.eclipse.swt.widgets.ToolItem;
0041: import org.eclipse.ui.IMemento;
0042: import org.eclipse.ui.IPropertyListener;
0043: import org.eclipse.ui.PlatformUI;
0044: import org.eclipse.ui.examples.presentation.PresentationImages;
0045: import org.eclipse.ui.presentations.IPartMenu;
0046: import org.eclipse.ui.presentations.IPresentablePart;
0047: import org.eclipse.ui.presentations.IPresentationSerializer;
0048: import org.eclipse.ui.presentations.IStackPresentationSite;
0049: import org.eclipse.ui.presentations.PresentationUtil;
0050: import org.eclipse.ui.presentations.StackDropResult;
0051: import org.eclipse.ui.presentations.StackPresentation;
0052: import org.eclipse.ui.themes.ITheme;
0053:
0054: /**
0055: * @since 3.0
0056: */
0057: public class WrappedTabsPartPresentation extends StackPresentation {
0058:
0059: private static class DropLocation {
0060: int insertionPosition = 0;
0061: IPresentablePart part;
0062: boolean before;
0063: }
0064:
0065: private static final String PART_DATA = "part";
0066:
0067: private boolean activeFocus = false;
0068:
0069: /**
0070: * Main widget for the presentation
0071: */
0072: private Composite presentationControl;
0073:
0074: /**
0075: * Currently selected part
0076: */
0077: private IPresentablePart current;
0078:
0079: /**
0080: * ToolBar that will be used to select the active presentable part
0081: */
0082: private ToolBar toolBar;
0083:
0084: /**
0085: * ToolBar that will contain close, minimize, etc.
0086: */
0087: private ToolBar upperRight;
0088:
0089: /**
0090: * close button
0091: */
0092: private ToolItem close;
0093:
0094: /**
0095: * View menu button
0096: */
0097: private ToolItem viewMenu;
0098:
0099: /**
0100: * Minimize button
0101: */
0102: private ToolItem minView;
0103:
0104: /**
0105: * Show/hide toolbar button
0106: */
0107: private ToolItem showToolbar;
0108:
0109: private ToolBar titleIconToolbar;
0110:
0111: /**
0112: * Title icon
0113: */
0114: private ToolItem titleIcon;
0115:
0116: private MenuManager systemMenuManager = new MenuManager();
0117: private ViewForm contentArea;
0118:
0119: private Label contentDescription;
0120: private Composite contentDescriptionWrapper;
0121:
0122: private Composite clientArea;
0123:
0124: private ProxyControl toolbarProxy;
0125:
0126: /**
0127: * Listener attached to all child parts. It responds to changes in part properties
0128: */
0129: private IPropertyListener childPropertyChangeListener = new IPropertyListener() {
0130: public void propertyChanged(Object source, int property) {
0131:
0132: if (source instanceof IPresentablePart) {
0133: IPresentablePart part = (IPresentablePart) source;
0134:
0135: childPropertyChanged(part, property);
0136: }
0137: }
0138: };
0139:
0140: /**
0141: * Drag listener for regions outside the toolbar
0142: */
0143: Listener dragListener = new Listener() {
0144: public void handleEvent(Event event) {
0145: Point loc = new Point(event.x, event.y);
0146: Control ctrl = (Control) event.widget;
0147:
0148: getSite().dragStart(ctrl.toDisplay(loc), false);
0149: }
0150: };
0151:
0152: /**
0153: * Listener attached to all tool items. It removes listeners from the associated
0154: * part when the tool item is destroyed. This is required to prevent memory leaks.
0155: */
0156: private DisposeListener tabDisposeListener = new DisposeListener() {
0157: public void widgetDisposed(DisposeEvent e) {
0158: if (e.widget instanceof ToolItem) {
0159: ToolItem item = (ToolItem) e.widget;
0160:
0161: IPresentablePart part = getPartForTab(item);
0162:
0163: part
0164: .removePropertyListener(childPropertyChangeListener);
0165: }
0166: }
0167: };
0168:
0169: /**
0170: * This listener responds to selection events in all tool items.
0171: */
0172: SelectionAdapter tabItemSelectionAdapter = new SelectionAdapter() {
0173: public void widgetSelected(SelectionEvent e) {
0174: ToolItem toolItem = (ToolItem) e.widget;
0175: IPresentablePart item = getPartForTab(toolItem);
0176: if (item != null) {
0177: // Clicking on the active tab should give focus to the current part
0178: if (item == current) {
0179: item.setFocus();
0180: }
0181: getSite().selectPart(item);
0182: }
0183: toolItem.setSelection(true);
0184: }
0185: };
0186:
0187: /**
0188: * Listener to changes made to the current theme. The presentation will
0189: * redraw when the theme changes.
0190: */
0191: private IPropertyChangeListener themeChangeListener = new IPropertyChangeListener() {
0192: public void propertyChange(PropertyChangeEvent event) {
0193: if (!presentationControl.isDisposed()) {
0194: toolBar.setFont(PlatformUI.getWorkbench()
0195: .getThemeManager().getCurrentTheme()
0196: .getFontRegistry().get(
0197: WrappedTabsThemeConstants.TAB_FONT));
0198: layout();
0199: presentationControl.redraw();
0200: }
0201: }
0202: };
0203:
0204: private Listener menuListener = new Listener() {
0205: /* (non-Javadoc)
0206: * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
0207: */
0208: public void handleEvent(Event event) {
0209: Point globalPos = new Point(event.x, event.y);
0210:
0211: if (event.widget == toolBar) {
0212: Point localPos = toolBar.toControl(globalPos);
0213: ToolItem item = toolBar.getItem(localPos);
0214:
0215: if (item != null) {
0216: IPresentablePart part = getPartForTab(item);
0217: getSite().selectPart(part);
0218: showSystemMenu(globalPos);
0219: return;
0220: }
0221: }
0222:
0223: IPresentablePart part = getCurrent();
0224: if (part != null) {
0225: showSystemMenu(globalPos);
0226: }
0227: }
0228: };
0229:
0230: private MouseListener mouseListener = new MouseAdapter() {
0231:
0232: // If we single-click on an empty space on the toolbar, move focus to the
0233: // active control
0234: public void mouseDown(MouseEvent e) {
0235: Point p = new Point(e.x, e.y);
0236:
0237: // Ignore double-clicks if we're currently over a toolbar item
0238: if (isOverToolItem(e)) {
0239: return;
0240: }
0241:
0242: if (current != null) {
0243: current.setFocus();
0244: }
0245: }
0246:
0247: public boolean isOverToolItem(MouseEvent e) {
0248: Point p = new Point(e.x, e.y);
0249: Control control = (Control) e.widget;
0250:
0251: if (control instanceof ToolBar) {
0252: ToolItem item = ((ToolBar) control).getItem(p);
0253:
0254: if (item != null) {
0255: return true;
0256: }
0257: }
0258:
0259: return false;
0260:
0261: }
0262:
0263: // If we double-click on the toolbar, maximize the presentation
0264: public void mouseDoubleClick(MouseEvent e) {
0265:
0266: // Ignore double-clicks if we're currently over a toolbar item
0267: if (isOverToolItem(e) && e.widget == upperRight) {
0268: return;
0269: }
0270:
0271: if (getSite().getState() == IStackPresentationSite.STATE_MAXIMIZED) {
0272: getSite().setState(
0273: IStackPresentationSite.STATE_RESTORED);
0274: } else {
0275: getSite().setState(
0276: IStackPresentationSite.STATE_MAXIMIZED);
0277: }
0278: }
0279: };
0280:
0281: private boolean showIconOnTabs;
0282: private static final int SPACING_WIDTH = 2;
0283:
0284: private static final String SHOWING_TOOLBAR = "showing_toolbar";
0285:
0286: private static final String TAG_PART = "part";
0287: private static final String TAG_ID = "id";
0288: private static final String TAG_TOOLBAR = "showing_toolbar";
0289:
0290: /**
0291: * Creates a new bare-bones part presentation, given the parent composite and
0292: * an IStackPresentationSite interface that will be used to communicate with
0293: * the workbench.
0294: *
0295: * @param stackSite interface to the workbench
0296: */
0297: public WrappedTabsPartPresentation(Composite parent,
0298: IStackPresentationSite stackSite, boolean showIconOnTabs) {
0299: super (stackSite);
0300:
0301: this .showIconOnTabs = showIconOnTabs;
0302:
0303: // Create a top-level control for the presentation.
0304: presentationControl = new Composite(parent, SWT.NONE);
0305:
0306: // Add a dispose listener. This will call the presentationDisposed()
0307: // method when the widget is destroyed.
0308: presentationControl.addDisposeListener(new DisposeListener() {
0309: public void widgetDisposed(DisposeEvent e) {
0310: presentationDisposed();
0311: }
0312: });
0313:
0314: upperRight = new ToolBar(presentationControl, SWT.RIGHT
0315: | SWT.FLAT);
0316: //initPresentationWidget(upperRight);
0317:
0318: titleIconToolbar = new ToolBar(presentationControl, SWT.RIGHT
0319: | SWT.FLAT);
0320: titleIcon = new ToolItem(titleIconToolbar, SWT.PUSH);
0321:
0322: titleIconToolbar.addListener(SWT.MouseDown, new Listener() {
0323: public void handleEvent(Event event) {
0324: showPaneMenu();
0325: }
0326: });
0327: titleIconToolbar.addListener(SWT.MenuDetect, menuListener);
0328:
0329: titleIconToolbar.setVisible(!showIconOnTabs);
0330:
0331: toolBar = new ToolBar(presentationControl, SWT.WRAP | SWT.RIGHT
0332: | SWT.FLAT);
0333: toolBar.addListener(SWT.MenuDetect, menuListener);
0334: toolBar.addMouseListener(mouseListener);
0335: toolBar.setFont(PlatformUI.getWorkbench().getThemeManager()
0336: .getCurrentTheme().getFontRegistry().get(
0337: WrappedTabsThemeConstants.TAB_FONT));
0338:
0339: // Add drag listener to the toolbar
0340: PresentationUtil.addDragListener(toolBar, new Listener() {
0341: public void handleEvent(Event event) {
0342: Point loc = new Point(event.x, event.y);
0343: ToolItem item = toolBar.getItem(loc);
0344:
0345: if (item != null) {
0346: // Move the current part
0347: IPresentablePart draggedItem = getPartForTab(item);
0348: draggedItem.setFocus();
0349: getSite().dragStart(draggedItem,
0350: toolBar.toDisplay(loc), false);
0351: } else {
0352: // Move the stack
0353: getSite().dragStart(toolBar.toDisplay(loc), false);
0354: }
0355: }
0356:
0357: });
0358:
0359: presentationControl.addPaintListener(new PaintListener() {
0360: public void paintControl(PaintEvent e) {
0361: Rectangle clientArea = presentationControl
0362: .getClientArea();
0363: e.gc.setLineWidth(getBorderWidth());
0364:
0365: e.gc.setForeground(getBorderColor());
0366: e.gc.drawRectangle(clientArea.x, clientArea.y,
0367: clientArea.width - 1, clientArea.height - 1);
0368: Rectangle contentAreaBounds = contentArea.getBounds();
0369: int ypos = contentAreaBounds.y - 1;
0370: e.gc.drawLine(clientArea.x, ypos, clientArea.x
0371: + clientArea.width - 1, ypos);
0372: }
0373:
0374: });
0375: initPresentationWidget(presentationControl);
0376:
0377: contentArea = new ViewForm(presentationControl, SWT.FLAT);
0378: initPresentationWidget(contentArea);
0379: contentDescriptionWrapper = new Composite(contentArea, SWT.NONE);
0380:
0381: GridLayout layout = new GridLayout();
0382: layout.marginWidth = 4;
0383: layout.marginHeight = 2;
0384: contentDescriptionWrapper.setLayout(layout);
0385:
0386: GridData data = new GridData(GridData.FILL_BOTH);
0387: data.verticalAlignment = GridData.VERTICAL_ALIGN_CENTER;
0388:
0389: contentDescription = new Label(contentDescriptionWrapper,
0390: SWT.NONE);
0391: initPresentationWidget(contentDescription);
0392: contentDescription.setLayoutData(data);
0393:
0394: clientArea = new Composite(contentArea, SWT.NONE);
0395: clientArea.setVisible(false);
0396:
0397: contentArea.setContent(clientArea);
0398: toolbarProxy = new ProxyControl(contentArea);
0399:
0400: createButtonBar();
0401:
0402: createSystemMenu();
0403:
0404: PlatformUI.getWorkbench().getThemeManager()
0405: .addPropertyChangeListener(themeChangeListener);
0406: }
0407:
0408: private void initPresentationWidget(Control toInitialize) {
0409: PresentationUtil.addDragListener(toInitialize, dragListener);
0410: toInitialize.addListener(SWT.MenuDetect, menuListener);
0411: toInitialize.addMouseListener(mouseListener);
0412: }
0413:
0414: /* (non-Javadoc)
0415: * @see org.eclipse.ui.presentations.StackPresentation#restoreState(org.eclipse.ui.presentations.IPresentationSerializer, org.eclipse.ui.IMemento)
0416: */
0417: public void restoreState(IPresentationSerializer serializer,
0418: IMemento savedState) {
0419: IMemento[] parts = savedState.getChildren(TAG_PART);
0420:
0421: for (int idx = 0; idx < parts.length; idx++) {
0422: String id = parts[idx].getString(TAG_ID);
0423:
0424: if (id != null) {
0425: IPresentablePart part = serializer.getPart(id);
0426:
0427: if (part != null) {
0428: addPart(part, null);
0429:
0430: Integer hasToolbar = parts[idx]
0431: .getInteger(TAG_TOOLBAR);
0432: showToolbar(part, hasToolbar != null
0433: && hasToolbar.intValue() != 0);
0434: }
0435: }
0436: }
0437: }
0438:
0439: /* (non-Javadoc)
0440: * @see org.eclipse.ui.presentations.StackPresentation#saveState(org.eclipse.ui.presentations.IPresentationSerializer, org.eclipse.ui.IMemento)
0441: */
0442: public void saveState(IPresentationSerializer context,
0443: IMemento memento) {
0444: super .saveState(context, memento);
0445:
0446: IPresentablePart[] parts = getParts();
0447:
0448: for (int i = 0; i < parts.length; i++) {
0449: IPresentablePart part = parts[i];
0450:
0451: IMemento childMem = memento.createChild(TAG_PART);
0452: childMem.putString(TAG_ID, context.getId(part));
0453: childMem.putInteger(TAG_TOOLBAR, isShowingToolbar(part) ? 1
0454: : 0);
0455: }
0456: }
0457:
0458: public IPresentablePart[] getParts() {
0459: ToolItem[] items = toolBar.getItems();
0460: IPresentablePart[] result = new IPresentablePart[items.length];
0461:
0462: for (int idx = 0; idx < items.length; idx++) {
0463: ToolItem item = items[idx];
0464:
0465: IPresentablePart next = getPartForTab(item);
0466:
0467: result[idx] = next;
0468: }
0469:
0470: return result;
0471: }
0472:
0473: private final void createSystemMenu() {
0474: getSite().addSystemActions(systemMenuManager);
0475: systemMenuManager.add(new ChangeStackStateContributionItem(
0476: getSite()));
0477: systemMenuManager.add(new ShowToolbarContributionItem(this ));
0478: // This example presentation includes the part list at the end of the system menu
0479: systemMenuManager.add(new Separator());
0480: systemMenuManager.add(new CloseContributionItem(this ));
0481: systemMenuManager.add(new CloseOthersContributionItem(this ));
0482: systemMenuManager.add(new CloseAllContributionItem(this ));
0483: systemMenuManager.add(new PartListContributionItem(this ,
0484: getSite()));
0485: }
0486:
0487: private void createButtonBar() {
0488: viewMenu = new ToolItem(upperRight, SWT.PUSH);
0489: upperRight.addListener(SWT.MouseDown, new Listener() {
0490: public void handleEvent(Event event) {
0491: Point p = new Point(event.x, event.y);
0492: Rectangle r = viewMenu.getBounds();
0493:
0494: if (r.contains(p)) {
0495: showSystemMenu();
0496: }
0497: }
0498: });
0499: viewMenu.setImage(PresentationImages
0500: .getImage(PresentationImages.VIEW_MENU));
0501:
0502: showToolbar = new ToolItem(upperRight, SWT.PUSH);
0503: showToolbar.addSelectionListener(new SelectionAdapter() {
0504: public void widgetSelected(SelectionEvent e) {
0505: showToolbar(!isShowingToolbar());
0506: }
0507: });
0508:
0509: if (getSite().supportsState(
0510: IStackPresentationSite.STATE_MINIMIZED)) {
0511: minView = new ToolItem(upperRight, SWT.PUSH);
0512: minView.addSelectionListener(new SelectionAdapter() {
0513: public void widgetSelected(SelectionEvent e) {
0514: if (current != null) {
0515: if (getSite().getState() == IStackPresentationSite.STATE_MINIMIZED) {
0516: getSite()
0517: .setState(
0518: IStackPresentationSite.STATE_RESTORED);
0519: } else {
0520: getSite()
0521: .setState(
0522: IStackPresentationSite.STATE_MINIMIZED);
0523: }
0524: }
0525: }
0526: });
0527: }
0528:
0529: close = new ToolItem(upperRight, SWT.PUSH);
0530: close.addSelectionListener(new SelectionAdapter() {
0531: public void widgetSelected(SelectionEvent e) {
0532: if (current != null) {
0533: getSite().close(new IPresentablePart[] { current });
0534: }
0535: }
0536:
0537: });
0538: close.setImage(PresentationImages
0539: .getImage(PresentationImages.CLOSE_VIEW));
0540:
0541: updateToolbarImages();
0542: }
0543:
0544: private void updateToolbarImages() {
0545: if (isShowingToolbar()) {
0546: showToolbar.setImage(PresentationImages
0547: .getImage(PresentationImages.HIDE_TOOLBAR));
0548: } else {
0549: showToolbar.setImage(PresentationImages
0550: .getImage(PresentationImages.SHOW_TOOLBAR));
0551: }
0552:
0553: if (minView != null) {
0554: String minImage = (getSite().getState() == IStackPresentationSite.STATE_MINIMIZED) ? PresentationImages.RESTORE_VIEW
0555: : PresentationImages.MIN_VIEW;
0556: minView.setImage(PresentationImages.getImage(minImage));
0557: }
0558:
0559: upperRight.pack(true);
0560: upperRight.redraw();
0561: }
0562:
0563: public void refreshButtonBarEnablement() {
0564: close.setEnabled(current != null
0565: && getSite().isCloseable(current));
0566: titleIcon.setEnabled(current != null
0567: && current.getMenu() != null);
0568: showToolbar.setEnabled(current != null
0569: && current.getToolBar() != null);
0570: }
0571:
0572: public void dispose() {
0573: // Dispose the main presentation widget. This will cause
0574: // presentationDisposed to be called, which will do the real cleanup.
0575: presentationControl.dispose();
0576: }
0577:
0578: /**
0579: * Perform any cleanup. This method should remove any listeners that were
0580: * attached to other objects. This gets called when the presentation
0581: * widget is disposed. This is safer than cleaning up in the dispose()
0582: * method, since this code will run even if some unusual circumstance
0583: * destroys the Shell without first calling dispose().
0584: */
0585: protected void presentationDisposed() {
0586: // Remove any listeners that were attached to any
0587: // global Eclipse resources. This is necessary in order to prevent
0588: // memory leaks.
0589: PlatformUI.getWorkbench().getThemeManager()
0590: .removePropertyChangeListener(themeChangeListener);
0591: }
0592:
0593: public void setBounds(Rectangle bounds) {
0594: Rectangle newBounds = Geometry.copy(bounds);
0595:
0596: if (newBounds.width == 0) {
0597: // Workaround a bug in the Eclipse 3.0 release: minimized presentations will be
0598: // given a width of 0.
0599: newBounds.width = presentationControl.getBounds().width;
0600: }
0601:
0602: if (getSite().getState() == IStackPresentationSite.STATE_MINIMIZED) {
0603: newBounds.height = computeMinimumSize().y;
0604: }
0605:
0606: // Set the bounds of the presentation widge
0607: presentationControl.setBounds(newBounds);
0608:
0609: // Update the bounds of the currently visible part
0610: layout();
0611: }
0612:
0613: /**
0614: * Lay out the presentation's widgets
0615: */
0616: private void layout() {
0617:
0618: // Determine the inner bounds of the presentation
0619: Rectangle presentationClientArea = presentationControl
0620: .getClientArea();
0621: presentationClientArea.x += getBorderWidth();
0622: presentationClientArea.width -= getBorderWidth() * 2;
0623: presentationClientArea.y += getBorderWidth();
0624: presentationClientArea.height -= getBorderWidth() * 2;
0625:
0626: // Position the upper-right toolbar
0627: Point upperRightSize = upperRight.getSize();
0628: int upperRightStartX = presentationClientArea.x
0629: + presentationClientArea.width - upperRightSize.x
0630: - SPACING_WIDTH;
0631:
0632: Rectangle upperRightBounds = new Rectangle(upperRightStartX,
0633: presentationClientArea.y + SPACING_WIDTH,
0634: upperRightSize.x, upperRightSize.y);
0635:
0636: upperRight.setBounds(upperRightBounds);
0637:
0638: int tabStart = presentationClientArea.x + SPACING_WIDTH + 1;
0639: int verticalSpaceRequired = 0;
0640: if (!showIconOnTabs) {
0641: Point upperLeftSize;
0642:
0643: upperLeftSize = titleIconToolbar.getSize();
0644: Rectangle upperLeftBounds = new Rectangle(
0645: presentationClientArea.x + SPACING_WIDTH,
0646: presentationClientArea.y + SPACING_WIDTH,
0647: upperLeftSize.x, upperLeftSize.y);
0648:
0649: titleIconToolbar.setBounds(upperLeftBounds);
0650:
0651: tabStart = upperLeftBounds.x + upperLeftBounds.width
0652: + SPACING_WIDTH;
0653: verticalSpaceRequired = upperLeftSize.y;
0654: }
0655:
0656: int availableTabWidth = upperRightStartX - tabStart
0657: - SPACING_WIDTH;
0658:
0659: Point toolbarSize = toolBar.computeSize(availableTabWidth,
0660: SWT.DEFAULT);
0661: int minToolbarWidth = WrappedTabsUtil
0662: .getMaximumItemWidth(toolBar);
0663:
0664: toolBar.setBounds(tabStart, presentationClientArea.y
0665: + SPACING_WIDTH, availableTabWidth, toolbarSize.y);
0666:
0667: verticalSpaceRequired = Math.max(verticalSpaceRequired,
0668: upperRightSize.y);
0669: verticalSpaceRequired = Math.max(verticalSpaceRequired,
0670: toolbarSize.y);
0671:
0672: int verticalOffset = presentationClientArea.y
0673: + verticalSpaceRequired + getBorderWidth() + 2
0674: * SPACING_WIDTH;
0675:
0676: contentArea.setBounds(presentationClientArea.x, verticalOffset,
0677: presentationClientArea.width,
0678: presentationClientArea.height - verticalOffset);
0679:
0680: if (isShowingToolbar()) {
0681: contentArea.setTopLeft(contentDescriptionWrapper);
0682: contentArea.setTopCenter(toolbarProxy.getControl());
0683: } else {
0684: contentArea.setTopLeft(null);
0685: contentArea.setTopCenter(null);
0686: }
0687:
0688: contentArea.layout();
0689:
0690: // Position the view's widgets
0691: if (current != null) {
0692: Rectangle clientRectangle = clientArea.getBounds();
0693: Point clientAreaStart = presentationControl.getParent()
0694: .toControl(
0695: contentArea.toDisplay(clientRectangle.x,
0696: clientRectangle.y));
0697:
0698: current.setBounds(new Rectangle(clientAreaStart.x,
0699: clientAreaStart.y, clientRectangle.width,
0700: clientRectangle.height));
0701: }
0702:
0703: }
0704:
0705: private int getBorderWidth() {
0706: return PlatformUI.getWorkbench().getThemeManager()
0707: .getCurrentTheme().getInt(
0708: WrappedTabsThemeConstants.BORDER_SIZE);
0709: }
0710:
0711: public Point computeMinimumSize() {
0712: Point minSize = new Point(100, 16);
0713: Point upperLeftSize = titleIconToolbar.getSize();
0714: Point toolBarSize = toolBar.computeSize(SWT.DEFAULT,
0715: SWT.DEFAULT, false);
0716:
0717: int BORDER_WIDTH = getBorderWidth();
0718: Point result = new Point(minSize.x + upperLeftSize.x + 3
0719: * SPACING_WIDTH + 2 * BORDER_WIDTH, Math.max(Math.max(
0720: upperLeftSize.y, minSize.y), toolBarSize.y)
0721: + 2 * SPACING_WIDTH + 2 * BORDER_WIDTH);
0722:
0723: return result;
0724: }
0725:
0726: public void setVisible(boolean isVisible) {
0727:
0728: // Make the presentation widget visible
0729: presentationControl.setVisible(isVisible);
0730:
0731: // Make the currently visible part visible
0732: if (current != null) {
0733: current.setVisible(isVisible);
0734: if (current.getToolBar() != null) {
0735: current.getToolBar().setVisible(
0736: isVisible && isShowingToolbar());
0737: }
0738: }
0739:
0740: if (isVisible) {
0741: // Restore the bounds of the currently visible part.
0742: // IPartPresentations can be used by multiple StackPresentations,
0743: // although only one such presentation is ever visible at a time.
0744: // It is possible that some other presentation has changed the
0745: // bounds of the part since it was last visible, so we need to
0746: // update the part's bounds when the presentation becomes visible.
0747: layout();
0748: }
0749: }
0750:
0751: private void clearSelection() {
0752: // If there was an existing part selected, make it invisible
0753: if (current != null) {
0754: current.setVisible(false);
0755: }
0756:
0757: current = null;
0758: }
0759:
0760: public void currentPartChanged() {
0761: boolean layoutNeeded = false;
0762:
0763: if (titleIcon.getImage() != current.getTitleImage()) {
0764: titleIcon.setImage(current.getTitleImage());
0765: titleIcon.setDisabledImage(current.getTitleImage());
0766: titleIconToolbar.pack(true);
0767: titleIconToolbar.redraw();
0768:
0769: layoutNeeded = true;
0770: }
0771:
0772: if (!contentDescription.getText().equals(
0773: current.getTitleStatus())) {
0774: contentDescription.setText(current.getTitleStatus());
0775:
0776: layoutNeeded = true;
0777: }
0778:
0779: if (current.getToolBar() != null) {
0780: if (isShowingToolbar()) {
0781: current.getToolBar().setVisible(true);
0782: layoutNeeded = true;
0783: } else {
0784: current.getToolBar().setVisible(false);
0785: }
0786:
0787: toolbarProxy.setTargetControl(current.getToolBar());
0788: }
0789:
0790: if (layoutNeeded) {
0791: layout();
0792: }
0793: }
0794:
0795: public void selectPart(IPresentablePart toSelect) {
0796: // Ignore redundant selections
0797: if (toSelect == current) {
0798: return;
0799: }
0800:
0801: clearSelection();
0802:
0803: // Select the new part
0804: current = toSelect;
0805:
0806: // Ordering is important here. We need to make the part
0807: // visible before updating its bounds, or the call to setBounds
0808: // may be ignored.
0809:
0810: if (current != null) {
0811: // Make the newly selected part visible
0812: current.setVisible(true);
0813:
0814: ToolItem[] items = toolBar.getItems();
0815:
0816: for (int idx = 0; idx < items.length; idx++) {
0817: ToolItem item = items[idx];
0818:
0819: item.setSelection(getPartForTab(item) == current);
0820: }
0821:
0822: currentPartChanged();
0823: }
0824:
0825: refreshButtonBarEnablement();
0826: updateToolbarImages();
0827:
0828: // Update the bounds of the newly selected part
0829: layout();
0830: }
0831:
0832: public Control[] getTabList(IPresentablePart part) {
0833: return new Control[] { part.getControl() };
0834: }
0835:
0836: public Control getControl() {
0837: return presentationControl;
0838: }
0839:
0840: private int indexOf(IPresentablePart part) {
0841: ToolItem item = getTab(part);
0842:
0843: if (item == null) {
0844: return -1;
0845: }
0846:
0847: return toolBar.indexOf(item);
0848: }
0849:
0850: public void addPart(IPresentablePart newPart, Object cookie) {
0851: if (getTab(newPart) != null) {
0852: return;
0853: }
0854:
0855: int position = toolBar.getItemCount();
0856:
0857: // If this part is being added due to a drag/drop operation,
0858: // determine the correct insertion position
0859: if (cookie instanceof DropLocation) {
0860: DropLocation location = (DropLocation) cookie;
0861:
0862: position = indexOf(location.part);
0863:
0864: // If we can't find the tab, then fall back to the
0865: // insertionPosition field
0866: if (position == -1) {
0867: position = location.insertionPosition;
0868: } else {
0869: if (!location.before) {
0870: position++;
0871: }
0872: }
0873: }
0874:
0875: // Ignore the cookie for now, since we don't support drag-and-drop yet.
0876: ToolItem toolItem = new ToolItem(toolBar, SWT.RADIO, position);
0877:
0878: // Attach the newPart pointer to the ToolItem. This is used for getPartForTab
0879: // to determine which part is associated with the tool item
0880: toolItem.setData(PART_DATA, newPart);
0881:
0882: // Attach a property change listener to the part. This will update the ToolItem
0883: // to reflect changes in the part.
0884: newPart.addPropertyListener(childPropertyChangeListener);
0885:
0886: // Attach a dispose listener to the item. This removes the above property
0887: // change listener from the part when the item is destroyed. This prevents
0888: // memory leaks.
0889: toolItem.addDisposeListener(tabDisposeListener);
0890:
0891: // Listen to selection events in the new tool item
0892: toolItem.addSelectionListener(tabItemSelectionAdapter);
0893:
0894: // Initialize the tab for this part
0895: initTab(toolItem, newPart);
0896:
0897: layout();
0898:
0899: toolBar.layout(true);
0900: presentationControl.redraw();
0901: }
0902:
0903: protected void initTab(ToolItem item, IPresentablePart part) {
0904: String tabName = getTabText(part);
0905:
0906: if (!tabName.equals(item.getText())) {
0907: item.setText(tabName);
0908: }
0909:
0910: if (!(part.getTitleToolTip().equals(item.getToolTipText()))) {
0911: item.setToolTipText(part.getTitleToolTip());
0912: }
0913:
0914: if (showIconOnTabs && part.getTitleImage() != item.getImage()) {
0915: item.setImage(part.getTitleImage());
0916: }
0917:
0918: }
0919:
0920: /**
0921: * Returns the decorated tab text for the given part. By default, we attach
0922: * a star to indicate dirty tabs.
0923: *
0924: * @param part part whose text is being computed
0925: * @return the decorated tab text for the given part
0926: */
0927: protected String getTabText(IPresentablePart part) {
0928: String result = part.getName();
0929:
0930: if (part.isDirty()) {
0931: result = "*" + result;
0932: }
0933:
0934: return result;
0935: }
0936:
0937: /**
0938: * Removes the given part from the stack.
0939: *
0940: * @param oldPart the part to remove (not null)
0941: */
0942: public void removePart(IPresentablePart oldPart) {
0943: // If we're removing the currently selected part, clear the selection
0944: if (oldPart == current) {
0945: clearSelection();
0946: refreshButtonBarEnablement();
0947: }
0948:
0949: ToolItem item = getTab(oldPart);
0950:
0951: // Don't need to do anything if the part has already been removed
0952: if (item == null) {
0953: return;
0954: }
0955:
0956: // Dispose the tab. The dispose listener on the item
0957: // will handle all the cleanup.
0958: item.dispose();
0959:
0960: layout();
0961:
0962: presentationControl.redraw();
0963: }
0964:
0965: /**
0966: * Called whenever a property changes for one of the parts in this
0967: * presentation.
0968: *
0969: * @param part
0970: * @param property
0971: */
0972: protected void childPropertyChanged(IPresentablePart part,
0973: int property) {
0974: ToolItem toolItem = getTab(part);
0975:
0976: // If there is no tab for this part, just ignore the property change
0977: if (toolItem == null) {
0978: return;
0979: }
0980:
0981: initTab(toolItem, part);
0982:
0983: if (part == current) {
0984: currentPartChanged();
0985: }
0986: }
0987:
0988: /**
0989: * Returns the tab associated with the given part or null if none
0990: *
0991: * @param part the part to check for
0992: * @return the tab associated with the given part or null if none
0993: */
0994: protected final ToolItem getTab(IPresentablePart part) {
0995: ToolItem[] items = toolBar.getItems();
0996:
0997: for (int idx = 0; idx < items.length; idx++) {
0998: ToolItem item = items[idx];
0999:
1000: if (getPartForTab(item) == part) {
1001: return item;
1002: }
1003: }
1004:
1005: return null;
1006: }
1007:
1008: /**
1009: * Returns the part associated with the given tab, or null if none.
1010: *
1011: * @param item the tab to query
1012: * @return the part associated with the given tab or null if none
1013: */
1014: protected final IPresentablePart getPartForTab(ToolItem item) {
1015: return (IPresentablePart) item.getData(PART_DATA);
1016: }
1017:
1018: public StackDropResult dragOver(Control currentControl,
1019: Point location) {
1020: Point localCoordinates = toolBar.toControl(location);
1021:
1022: // Ignore drag operations that aren't on top of the toolbar we're using
1023: // for tabs.
1024: if (toolBar.getClientArea().contains(localCoordinates)) {
1025: DropLocation dropLocation = new DropLocation();
1026:
1027: ToolItem item = toolBar.getItem(localCoordinates);
1028:
1029: if (item == null) {
1030: item = toolBar.getItem(toolBar.getItemCount() - 1);
1031: }
1032:
1033: Rectangle itemBounds = item.getBounds();
1034: dropLocation.before = (localCoordinates.x - itemBounds.x < itemBounds.width / 2);
1035: dropLocation.part = getPartForTab(item);
1036: // Also store the current index of the part we're dragging over. We will use
1037: // the index if the part no longer exists at the time the drop occurs (ie:
1038: // if we're dragging an item over itself)
1039: dropLocation.insertionPosition = toolBar.indexOf(item);
1040:
1041: Point displayCoordinates = toolBar.toDisplay(itemBounds.x,
1042: itemBounds.y);
1043:
1044: Rectangle bounds = new Rectangle(displayCoordinates.x,
1045: displayCoordinates.y, 4, itemBounds.height);
1046: if (!dropLocation.before) {
1047: bounds.x += itemBounds.width;
1048: }
1049:
1050: return new StackDropResult(bounds, dropLocation);
1051: }
1052:
1053: return null;
1054: }
1055:
1056: public void setActive(int newState) {
1057: activeFocus = (newState == AS_ACTIVE_FOCUS);
1058: presentationControl.redraw();
1059: }
1060:
1061: public void setState(int state) {
1062: updateToolbarImages();
1063: }
1064:
1065: public void showPaneMenu(Point location) {
1066: if (current == null) {
1067: return;
1068: }
1069:
1070: IPartMenu menu = current.getMenu();
1071:
1072: if (menu == null) {
1073: return;
1074: }
1075:
1076: menu.showMenu(location);
1077: }
1078:
1079: public void showPaneMenu() {
1080: Rectangle bounds = titleIconToolbar.getBounds();
1081: Point location = titleIconToolbar.getParent().toDisplay(
1082: bounds.x, bounds.y + bounds.height);
1083:
1084: showPaneMenu(location);
1085: }
1086:
1087: public void showSystemMenu() {
1088: Rectangle bounds = viewMenu.getBounds();
1089: Point displayPos = viewMenu.getParent().toDisplay(bounds.x,
1090: bounds.y + bounds.height);
1091:
1092: showSystemMenu(displayPos);
1093: }
1094:
1095: public void showSystemMenu(Point displayPos) {
1096: Menu aMenu = systemMenuManager
1097: .createContextMenu(presentationControl);
1098: systemMenuManager.update(true);
1099: aMenu.setLocation(displayPos.x, displayPos.y);
1100: aMenu.setVisible(true);
1101: }
1102:
1103: /* (non-Javadoc)
1104: * @see org.eclipse.ui.presentations.StackPresentation#showPartList()
1105: */
1106: public void showPartList() {
1107:
1108: // The part list opens when the user presses ctrl-e to open the list
1109: // of editors. In this presentation, the part list is part of the system menu,
1110: // so opening the part list is equivalent to opening the system menu.
1111: showSystemMenu();
1112: }
1113:
1114: protected void showToolbar(IPresentablePart part, boolean shouldShow) {
1115:
1116: if (shouldShow != isShowingToolbar(part)) {
1117: ToolItem tab = getTab(part);
1118: tab.setData(SHOWING_TOOLBAR, shouldShow ? SHOWING_TOOLBAR
1119: : null);
1120:
1121: if (part == current) {
1122: Control toolbar = part.getToolBar();
1123: if (toolbar != null) {
1124: toolbar.setVisible(shouldShow);
1125: }
1126:
1127: layout();
1128:
1129: updateToolbarImages();
1130:
1131: if (getSite().getState() == IStackPresentationSite.STATE_MINIMIZED) {
1132: getSite().setState(
1133: IStackPresentationSite.STATE_RESTORED);
1134: }
1135: }
1136: }
1137: }
1138:
1139: /**
1140: * @param selection
1141: */
1142: public void showToolbar(boolean selection) {
1143: if (current != null) {
1144: showToolbar(current, selection);
1145: }
1146: }
1147:
1148: public IPresentablePart getCurrent() {
1149: return current;
1150: }
1151:
1152: private boolean isShowingToolbar(IPresentablePart part) {
1153: ToolItem tab = getTab(part);
1154: return tab.getData(SHOWING_TOOLBAR) != null;
1155: }
1156:
1157: public boolean isShowingToolbar() {
1158: if (current == null) {
1159: return false;
1160: }
1161:
1162: return isShowingToolbar(current);
1163: }
1164:
1165: /**
1166: * @param parts
1167: */
1168: public void close(IPresentablePart[] parts) {
1169: getSite().close(parts);
1170: }
1171:
1172: private Color getBorderColor() {
1173: ITheme current = PlatformUI.getWorkbench().getThemeManager()
1174: .getCurrentTheme();
1175: if (activeFocus) {
1176: return current.getColorRegistry().get(
1177: WrappedTabsThemeConstants.BORDER_COLOR_FOCUS);
1178: } else {
1179: return current.getColorRegistry().get(
1180: WrappedTabsThemeConstants.BORDER_COLOR_NOFOCUS);
1181: }
1182: }
1183: }
|