/******************************************************************************* * Copyright (c) 2004 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package eu.jucy.gui.representation; import java.util.HashMap; import java.util.Map; import org.eclipse.jface.util.Geometry; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.ViewForm; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.ToolItem; import org.eclipse.ui.IMemento; import org.eclipse.ui.IPropertyListener; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.internal.presentations.util.ISystemMenu; import org.eclipse.ui.presentations.IPartMenu; import org.eclipse.ui.presentations.IPresentablePart; import org.eclipse.ui.presentations.IPresentationSerializer; import org.eclipse.ui.presentations.IStackPresentationSite; import org.eclipse.ui.presentations.PresentationUtil; import org.eclipse.ui.presentations.StackDropResult; import org.eclipse.ui.presentations.StackPresentation; import org.eclipse.ui.themes.ITheme; import eu.jucy.gui.representation.UCEditorContributionItem.UCEditorSystemMenu; /** * @since 3.0 */ @SuppressWarnings("restriction") public class WrappedTabsPartPresentation extends StackPresentation { // private static final Logger logger = LoggerFactory.make(); // public static final String MENU_ID = "eu.jucy.presentation"; private final Map<Image,Image> correctlySizedImage = new HashMap<Image,Image>(); private static final int CorrectSize = 22; private static class DropLocation { int insertionPosition = 0; IPresentablePart part; boolean before; } private static final String PART_DATA = "part"; private boolean activeFocus = false; /** * Main widget for the presentation */ private Composite presentationControl; /** * Currently selected part */ private IPresentablePart current; /** * ToolBar that will be used to select the active presentable part */ private ToolBar toolBar; // private CoolBar coolBar; /** * ToolBar that will contain close, minimize, etc. */ private ToolBar upperRight; /** * close button */ private ToolItem close; /** * View menu button */ private ToolItem viewMenu; /** * Minimize button */ private ToolItem minView; /** * Show/hide toolbar button */ private ToolItem showToolbar; private ToolBar titleIconToolbar; /** * Title icon */ private ToolItem titleIcon; private ISystemMenu systemMenuManager = new UCEditorSystemMenu(); private ViewForm contentArea; private Label contentDescription; private Composite contentDescriptionWrapper; private Composite clientArea; private ProxyControl toolbarProxy; /** * Listener attached to all child parts. It responds to changes in part properties */ private IPropertyListener childPropertyChangeListener = new IPropertyListener() { public void propertyChanged(Object source, int property) { if (source instanceof IPresentablePart) { IPresentablePart part = (IPresentablePart) source; childPropertyChanged(part, property); } } }; /** * Drag listener for regions outside the toolbar */ Listener dragListener = new Listener() { public void handleEvent(Event event) { Point loc = new Point(event.x, event.y); Control ctrl = (Control)event.widget; getSite().dragStart(ctrl.toDisplay(loc), false); } }; /** * Listener attached to all tool items. It removes listeners from the associated * part when the tool item is destroyed. This is required to prevent memory leaks. */ private DisposeListener tabDisposeListener = new DisposeListener() { public void widgetDisposed(DisposeEvent e) { if (e.widget instanceof ToolItem) { ToolItem item = (ToolItem)e.widget; IPresentablePart part = getPartForTab(item); part.removePropertyListener(childPropertyChangeListener); } } }; /** * This listener responds to selection events in all tool items. */ SelectionAdapter tabItemSelectionAdapter = new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { ToolItem toolItem = (ToolItem) e.widget; IPresentablePart item = getPartForTab(toolItem); if (item != null) { // Clicking on the active tab should give focus to the current part if (item == current) { item.setFocus(); } getSite().selectPart(item); } toolItem.setSelection(true); } }; /** * Listener to changes made to the current theme. The presentation will * redraw when the theme changes. */ private IPropertyChangeListener themeChangeListener = new IPropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { if(! presentationControl.isDisposed()) { // toolBar.setFont(PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getFontRegistry().get(WrappedTabsThemeConstants.TAB_FONT)); layout(); presentationControl.redraw(); } } }; private Listener menuListener = new Listener() { /* (non-Javadoc) * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event) */ public void handleEvent(Event event) { Point globalPos = new Point(event.x, event.y); if (event.widget == toolBar) { Point localPos = toolBar.toControl(globalPos); ToolItem item = toolBar.getItem(localPos); if (item != null) { IPresentablePart part = getPartForTab(item); getSite().selectPart(part); showSystemMenu(globalPos); return; } } IPresentablePart part = getCurrent(); if (part != null) { showSystemMenu(globalPos); } } }; private MouseListener mouseListener = new MouseAdapter() { // If we single-click on an empty space on the toolbar, move focus to the // active control public void mouseDown(MouseEvent e) { //Point p = new Point(e.x, e.y); // Ignore double-clicks if we're currently over a toolbar item if (isOverToolItem(e)) { return; } if (current != null) { current.setFocus(); } } public boolean isOverToolItem(MouseEvent e) { Point p = new Point(e.x, e.y); Control control = (Control)e.widget; if (control instanceof ToolBar) { ToolItem item = ((ToolBar)control).getItem(p); if (item != null) { return true; } } return false; } // If we double-click on the toolbar, maximize the presentation public void mouseDoubleClick(MouseEvent e) { // Ignore double-clicks if we're currently over a toolbar item if (isOverToolItem(e) && e.widget == upperRight) { return; } if (getSite().getState() == IStackPresentationSite.STATE_MAXIMIZED) { getSite().setState(IStackPresentationSite.STATE_RESTORED); } else { getSite().setState(IStackPresentationSite.STATE_MAXIMIZED); } } }; private boolean showIconOnTabs; private static final int SPACING_WIDTH = 2; private static final String SHOWING_TOOLBAR = "showing_toolbar"; private static final String TAG_PART = "part"; private static final String TAG_ID = "id"; private static final String TAG_TOOLBAR = "showing_toolbar"; /** * Creates a new bare-bones part presentation, given the parent composite and * an IStackPresentationSite interface that will be used to communicate with * the workbench. * * @param stackSite interface to the workbench */ public WrappedTabsPartPresentation(Composite parent, IStackPresentationSite stackSite, boolean showIconOnTabs) { super(stackSite); this.showIconOnTabs = showIconOnTabs; // Create a top-level control for the presentation. presentationControl = new Composite(parent, SWT.NONE); // Add a dispose listener. This will call the presentationDisposed() // method when the widget is destroyed. presentationControl.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { presentationDisposed(); } }); upperRight = new ToolBar(presentationControl, SWT.RIGHT | SWT.FLAT); //initPresentationWidget(upperRight); titleIconToolbar = new ToolBar(presentationControl, SWT.RIGHT | SWT.FLAT); titleIcon = new ToolItem(titleIconToolbar, SWT.PUSH); titleIconToolbar.addListener(SWT.MouseDown, new Listener() { public void handleEvent(Event event) { showPaneMenu(); } }); titleIconToolbar.addListener(SWT.MenuDetect, menuListener); titleIconToolbar.setVisible(!showIconOnTabs); toolBar = new ToolBar(presentationControl, SWT.WRAP | SWT.RIGHT | SWT.FLAT); toolBar.addListener(SWT.MenuDetect, menuListener); toolBar.addMouseListener(mouseListener); //toolBar.setFont(PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getFontRegistry().get(WrappedTabsThemeConstants.TAB_FONT)); // Add drag listener to the toolbar PresentationUtil.addDragListener(toolBar, new Listener() { public void handleEvent(Event event) { Point loc = new Point(event.x, event.y); ToolItem item = toolBar.getItem(loc); if (item != null) { // Move the current part IPresentablePart draggedItem = getPartForTab(item); draggedItem.setFocus(); getSite().dragStart(draggedItem, toolBar.toDisplay(loc), false); } else { // Move the stack getSite().dragStart(toolBar.toDisplay(loc), false); } } }); presentationControl.addPaintListener(new PaintListener() { public void paintControl(PaintEvent e) { Rectangle clientArea = presentationControl.getClientArea(); e.gc.setLineWidth(getBorderWidth()); e.gc.setForeground(getBorderColor()); e.gc.drawRectangle(clientArea.x, clientArea.y, clientArea.width-1, clientArea.height-1); Rectangle contentAreaBounds = contentArea.getBounds(); int ypos = contentAreaBounds.y - 1; e.gc.drawLine(clientArea.x, ypos, clientArea.x + clientArea.width - 1, ypos); } }); initPresentationWidget(presentationControl); contentArea = new ViewForm(presentationControl, SWT.FLAT); initPresentationWidget(contentArea); contentDescriptionWrapper = new Composite(contentArea, SWT.NONE); GridLayout layout = new GridLayout(); layout.marginWidth = 4; layout.marginHeight = 2; contentDescriptionWrapper.setLayout(layout); GridData data = new GridData(GridData.FILL_BOTH); data.verticalAlignment = GridData.VERTICAL_ALIGN_CENTER; contentDescription = new Label(contentDescriptionWrapper, SWT.NONE); initPresentationWidget(contentDescription); contentDescription.setLayoutData(data); clientArea = new Composite(contentArea, SWT.NONE); clientArea.setVisible(false); contentArea.setContent(clientArea); toolbarProxy = new ProxyControl(contentArea); createButtonBar(); //createSystemMenu(); PlatformUI.getWorkbench().getThemeManager().addPropertyChangeListener(themeChangeListener); } private void initPresentationWidget(Control toInitialize) { PresentationUtil.addDragListener(toInitialize, dragListener); toInitialize.addListener(SWT.MenuDetect, menuListener); toInitialize.addMouseListener(mouseListener); } /* (non-Javadoc) * @see org.eclipse.ui.presentations.StackPresentation#restoreState(org.eclipse.ui.presentations.IPresentationSerializer, org.eclipse.ui.IMemento) */ public void restoreState(IPresentationSerializer serializer, IMemento savedState) { IMemento[] parts = savedState.getChildren(TAG_PART); for (int idx = 0; idx < parts.length; idx++) { String id = parts[idx].getString(TAG_ID); if (id != null) { IPresentablePart part = serializer.getPart(id); if (part != null) { addPart(part, null); Integer hasToolbar = parts[idx].getInteger(TAG_TOOLBAR); showToolbar(part, hasToolbar != null && hasToolbar.intValue() != 0); } } } } /* (non-Javadoc) * @see org.eclipse.ui.presentations.StackPresentation#saveState(org.eclipse.ui.presentations.IPresentationSerializer, org.eclipse.ui.IMemento) */ public void saveState(IPresentationSerializer context, IMemento memento) { super.saveState(context, memento); IPresentablePart[] parts = getParts(); for (int i = 0; i < parts.length; i++) { IPresentablePart part = parts[i]; IMemento childMem = memento.createChild(TAG_PART); childMem.putString(TAG_ID, context.getId(part)); childMem.putInteger(TAG_TOOLBAR, isShowingToolbar(part) ? 1 : 0); } } public IPresentablePart[] getParts() { ToolItem[] items = toolBar.getItems(); IPresentablePart[] result = new IPresentablePart[items.length]; for (int idx = 0; idx < items.length; idx++) { ToolItem item = items[idx]; IPresentablePart next = getPartForTab(item); result[idx] = next; } return result; } // private final void createSystemMenu() { // // getSite().addSystemActions(systemMenuManager); // // systemMenuManager.add(new ChangeStackStateContributionItem(getSite())); // // systemMenuManager.add(new ShowToolbarContributionItem(this)); // // This example presentation includes the part list at the end of the system menu // // systemMenuManager.add(new Separator()); // //systemMenuManager.add(new CloseContributionItem(this)); // //systemMenuManager.add(new Separator()); // //HubContributionItem hci = new HubContributionItem(); // // systemMenuManager.add(new UCEditorContributionItem()); // // //UCEditor.createContextPopups(getSite(), MENUID, null, null); // //hci.initialize(PlatformUI.getWorkbench().getActiveWorkbenchWindow()); // //systemMenuManager.add(hci); // // // // systemMenuManager.add(new CloseOthersContributionItem(this)); // // systemMenuManager.add(new CloseAllContributionItem(this)); // // systemMenuManager.add(new PartListContributionItem(this, getSite())); // // // } private void createButtonBar() { viewMenu = new ToolItem(upperRight, SWT.PUSH); upperRight.addListener(SWT.MouseDown, new Listener() { public void handleEvent(Event event) { Point p = new Point(event.x, event.y); Rectangle r = viewMenu.getBounds(); if (r.contains(p)) { showSystemMenu(); } } }); viewMenu.setImage(PresentationImages.getImage(PresentationImages.VIEW_MENU)); showToolbar = new ToolItem(upperRight, SWT.PUSH); showToolbar.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { showToolbar(!isShowingToolbar()); } }); if (getSite().supportsState(IStackPresentationSite.STATE_MINIMIZED)) { minView = new ToolItem(upperRight, SWT.PUSH); minView.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { if (current != null) { if (getSite().getState() == IStackPresentationSite.STATE_MINIMIZED) { getSite().setState(IStackPresentationSite.STATE_RESTORED); } else { getSite().setState(IStackPresentationSite.STATE_MINIMIZED); } } } }); } close = new ToolItem(upperRight, SWT.PUSH); close.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { if (current != null) { getSite().close(new IPresentablePart[] {current}); } } }); close.setImage(PresentationImages.getImage(PresentationImages.CLOSE_VIEW)); updateToolbarImages(); } private void updateToolbarImages() { if (isShowingToolbar()) { showToolbar.setImage(PresentationImages.getImage(PresentationImages.HIDE_TOOLBAR)); } else { showToolbar.setImage(PresentationImages.getImage(PresentationImages.SHOW_TOOLBAR)); } if (minView != null) { String minImage = (getSite().getState() == IStackPresentationSite.STATE_MINIMIZED) ? PresentationImages.RESTORE_VIEW : PresentationImages.MIN_VIEW; minView.setImage(PresentationImages.getImage(minImage)); } upperRight.pack(true); upperRight.redraw(); } public void refreshButtonBarEnablement() { close.setEnabled(current != null && getSite().isCloseable(current)); titleIcon.setEnabled(current != null && current.getMenu() != null); showToolbar.setEnabled(current != null && current.getToolBar() != null); } public void dispose() { // Dispose the main presentation widget. This will cause // presentationDisposed to be called, which will do the real cleanup. presentationControl.dispose(); } /** * Perform any cleanup. This method should remove any listeners that were * attached to other objects. This gets called when the presentation * widget is disposed. This is safer than cleaning up in the dispose() * method, since this code will run even if some unusual circumstance * destroys the Shell without first calling dispose(). */ protected void presentationDisposed() { // Remove any listeners that were attached to any // global Eclipse resources. This is necessary in order to prevent // memory leaks. PlatformUI.getWorkbench().getThemeManager().removePropertyChangeListener(themeChangeListener); } public void setBounds(Rectangle bounds) { Rectangle newBounds = Geometry.copy(bounds); if (newBounds.width == 0) { // Workaround a bug in the Eclipse 3.0 release: minimized presentations will be // given a width of 0. newBounds.width = presentationControl.getBounds().width; } if (getSite().getState() == IStackPresentationSite.STATE_MINIMIZED) { newBounds.height = computeMinimumSize().y; } // Set the bounds of the presentation widge presentationControl.setBounds(newBounds); // Update the bounds of the currently visible part layout(); } /** * Lay out the presentation's widgets */ private void layout() { // Determine the inner bounds of the presentation Rectangle presentationClientArea = presentationControl.getClientArea(); presentationClientArea.x += getBorderWidth(); presentationClientArea.width -= getBorderWidth() * 2; presentationClientArea.y += getBorderWidth(); presentationClientArea.height -= getBorderWidth() * 2; // Position the upper-right toolbar Point upperRightSize = upperRight.getSize(); int upperRightStartX = presentationClientArea.x + presentationClientArea.width - upperRightSize.x - SPACING_WIDTH; Rectangle upperRightBounds = new Rectangle(upperRightStartX, presentationClientArea.y + SPACING_WIDTH, upperRightSize.x, upperRightSize.y); upperRight.setBounds(upperRightBounds); int tabStart = presentationClientArea.x + SPACING_WIDTH + 1; int verticalSpaceRequired = 0; if (!showIconOnTabs) { Point upperLeftSize; upperLeftSize = titleIconToolbar.getSize(); Rectangle upperLeftBounds = new Rectangle(presentationClientArea.x + SPACING_WIDTH, presentationClientArea.y + SPACING_WIDTH, upperLeftSize.x, upperLeftSize.y); titleIconToolbar.setBounds(upperLeftBounds); tabStart = upperLeftBounds.x + upperLeftBounds.width + SPACING_WIDTH; verticalSpaceRequired = upperLeftSize.y; } int availableTabWidth = upperRightStartX - tabStart - SPACING_WIDTH; Point toolbarSize = toolBar.computeSize(availableTabWidth, SWT.DEFAULT); /*int minToolbarWidth = */ WrappedTabsUtil.getMaximumItemWidth(toolBar); // int mul = WrappedTabsUtil.calculateNumberOfRows(toolBar, availableTabWidth); // logger.info("calculated Lines: "+mul); // if (Platform.OS_LINUX.equals(Platform.getOS())) { // int mul = WrappedTabsUtil.calculateNumberOfRows(toolBar, availableTabWidth); // logger.info("calculated Lines: "+mul + " original.y:"+toolbarSize.y); // toolbarSize.y = toolbarSize.y * mul; // } toolBar.setBounds(tabStart, presentationClientArea.y + SPACING_WIDTH, availableTabWidth, toolbarSize.y); verticalSpaceRequired = Math.max(verticalSpaceRequired, upperRightSize.y); verticalSpaceRequired = Math.max(verticalSpaceRequired, toolbarSize.y); int verticalOffset = presentationClientArea.y + verticalSpaceRequired + getBorderWidth() + 2 * SPACING_WIDTH; contentArea.setBounds(presentationClientArea.x, verticalOffset, presentationClientArea.width, presentationClientArea.height - verticalOffset); // logger.info("toolbar.y= "+toolbarSize.y); // logger.info("verticalOffset= "+verticalOffset); if (isShowingToolbar()) { contentArea.setTopLeft(contentDescriptionWrapper); contentArea.setTopCenter(toolbarProxy.getControl()); } else { contentArea.setTopLeft(null); contentArea.setTopCenter(null); } contentArea.layout(); // Position the view's widgets if (current != null) { Rectangle clientRectangle = clientArea.getBounds(); Point clientAreaStart = presentationControl.getParent().toControl( contentArea.toDisplay(clientRectangle.x, clientRectangle.y)); Rectangle partRect = new Rectangle(clientAreaStart.x, clientAreaStart.y, clientRectangle.width, clientRectangle.height); current.setBounds(partRect); // logger.info("clientareal= "+partRect); } } private int getBorderWidth() { return PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getInt(WrappedTabsThemeConstants.BORDER_SIZE); } public Point computeMinimumSize() { Point minSize = new Point(100, 16); Point upperLeftSize = titleIconToolbar.getSize(); Point toolBarSize = toolBar.computeSize(SWT.DEFAULT, SWT.DEFAULT, false); int BORDER_WIDTH = getBorderWidth(); Point result = new Point(minSize.x + upperLeftSize.x + 3 * SPACING_WIDTH + 2 * BORDER_WIDTH, Math.max(Math.max(upperLeftSize.y, minSize.y), toolBarSize.y) + 2 * SPACING_WIDTH + 2 * BORDER_WIDTH); return result; } public void setVisible(boolean isVisible) { // Make the presentation widget visible presentationControl.setVisible(isVisible); // Make the currently visible part visible if (current != null) { current.setVisible(isVisible); if (current.getToolBar() != null) { current.getToolBar().setVisible(isVisible && isShowingToolbar()); } } if (isVisible) { // Restore the bounds of the currently visible part. // IPartPresentations can be used by multiple StackPresentations, // although only one such presentation is ever visible at a time. // It is possible that some other presentation has changed the // bounds of the part since it was last visible, so we need to // update the part's bounds when the presentation becomes visible. layout(); } } private void clearSelection() { // If there was an existing part selected, make it invisible if (current != null) { current.setVisible(false); } current = null; } public void currentPartChanged() { boolean layoutNeeded = false; if (titleIcon.getImage() != current.getTitleImage()) { titleIcon.setImage(current.getTitleImage()); titleIcon.setDisabledImage(current.getTitleImage()); titleIconToolbar.pack(true); titleIconToolbar.redraw(); layoutNeeded = true; } if (!contentDescription.getText().equals(current.getTitleStatus())) { contentDescription.setText(current.getTitleStatus()); layoutNeeded = true; } if (current.getToolBar() != null) { if (isShowingToolbar()) { current.getToolBar().setVisible(true); layoutNeeded = true; } else { current.getToolBar().setVisible(false); } toolbarProxy.setTargetControl(current.getToolBar()); } if (layoutNeeded) { layout(); } } public void selectPart(IPresentablePart toSelect) { // Ignore redundant selections if (toSelect == current) { return; } clearSelection(); // Select the new part current = toSelect; // Ordering is important here. We need to make the part // visible before updating its bounds, or the call to setBounds // may be ignored. if (current != null) { // Make the newly selected part visible current.setVisible(true); ToolItem[] items = toolBar.getItems(); for (int idx = 0; idx < items.length; idx++) { ToolItem item = items[idx]; item.setSelection(getPartForTab(item) == current); } currentPartChanged(); } refreshButtonBarEnablement(); updateToolbarImages(); // Update the bounds of the newly selected part layout(); } public Control[] getTabList(IPresentablePart part) { return new Control[] {part.getControl()}; } public Control getControl() { return presentationControl; } private int indexOf(IPresentablePart part) { ToolItem item = getTab(part); if (item == null) { return -1; } return toolBar.indexOf(item); } public void addPart(IPresentablePart newPart, Object cookie) { if (getTab(newPart) != null) { return; } int position = toolBar.getItemCount(); // If this part is being added due to a drag/drop operation, // determine the correct insertion position if (cookie instanceof DropLocation) { DropLocation location = (DropLocation)cookie; position = indexOf(location.part); // If we can't find the tab, then fall back to the // insertionPosition field if (position == -1) { position = location.insertionPosition; } else { if (!location.before) { position++; } } } // Ignore the cookie for now, since we don't support drag-and-drop yet. ToolItem toolItem = new ToolItem(toolBar, SWT.RADIO, position); // Attach the newPart pointer to the ToolItem. This is used for getPartForTab // to determine which part is associated with the tool item toolItem.setData(PART_DATA, newPart); // Attach a property change listener to the part. This will update the ToolItem // to reflect changes in the part. newPart.addPropertyListener(childPropertyChangeListener); // Attach a dispose listener to the item. This removes the above property // change listener from the part when the item is destroyed. This prevents // memory leaks. toolItem.addDisposeListener(tabDisposeListener); // Listen to selection events in the new tool item toolItem.addSelectionListener(tabItemSelectionAdapter); // Initialize the tab for this part initTab(toolItem, newPart); layout(); toolBar.layout(true); presentationControl.redraw(); } protected void initTab(ToolItem item, IPresentablePart part) { String tabName = getTabText(part); if (!tabName.equals(item.getText())) { item.setText(tabName); } if (!(part.getTitleToolTip().equals(item.getToolTipText()))) { item.setToolTipText(part.getTitleToolTip()); } if (showIconOnTabs && getMatchingImage(part.getTitleImage(),item) != item.getImage()) { item.setImage(getMatchingImage(part.getTitleImage(),item)); } } private Image getMatchingImage(Image originalImage,ToolItem item) { Image replacement = correctlySizedImage.get(originalImage); if (replacement == null) { Rectangle rect = originalImage.getBounds(); if (rect.width == CorrectSize && rect.height == CorrectSize) { replacement = originalImage; } else { Image newImage = new Image(originalImage.getDevice(),CorrectSize,CorrectSize); GC gc = new GC(newImage); gc.setAdvanced(true); gc.setInterpolation(SWT.HIGH); gc.setAntialias(SWT.ON); gc.drawImage(originalImage, 0, 0, rect.width,rect.height,0, 0, CorrectSize, CorrectSize); gc.dispose(); ImageData id = newImage.getImageData(); id.transparentPixel = id.getPixel(0, 0); Image transp = new Image(originalImage.getDevice(), id); newImage.dispose(); replacement = transp; } correctlySizedImage.put(originalImage, replacement); } return replacement; } /** * Returns the decorated tab text for the given part. By default, we attach * a star to indicate dirty tabs. * * @param part part whose text is being computed * @return the decorated tab text for the given part */ protected String getTabText(IPresentablePart part) { String result = part.getName(); if (part.isDirty()) { result = "*" + result; } return result; } /** * Removes the given part from the stack. * * @param oldPart the part to remove (not null) */ public void removePart(IPresentablePart oldPart) { // If we're removing the currently selected part, clear the selection if (oldPart == current) { clearSelection(); refreshButtonBarEnablement(); } ToolItem item = getTab(oldPart); // Don't need to do anything if the part has already been removed if (item == null) { return; } // Dispose the tab. The dispose listener on the item // will handle all the cleanup. item.dispose(); layout(); presentationControl.redraw(); } /** * Called whenever a property changes for one of the parts in this * presentation. * * @param part * @param property */ protected void childPropertyChanged(IPresentablePart part, int property) { ToolItem toolItem = getTab(part); // If there is no tab for this part, just ignore the property change if (toolItem == null) { return; } initTab(toolItem, part); if (part == current) { currentPartChanged(); } } /** * Returns the tab associated with the given part or null if none * * @param part the part to check for * @return the tab associated with the given part or null if none */ protected final ToolItem getTab(IPresentablePart part) { ToolItem[] items = toolBar.getItems(); for (int idx = 0; idx < items.length; idx++) { ToolItem item = items[idx]; if (getPartForTab(item) == part) { return item; } } return null; } /** * Returns the part associated with the given tab, or null if none. * * @param item the tab to query * @return the part associated with the given tab or null if none */ protected final IPresentablePart getPartForTab(ToolItem item) { return (IPresentablePart)item.getData(PART_DATA); } public StackDropResult dragOver(Control currentControl, Point location) { Point localCoordinates = toolBar.toControl(location); // Ignore drag operations that aren't on top of the toolbar we're using // for tabs. if (toolBar.getClientArea().contains(localCoordinates)) { DropLocation dropLocation = new DropLocation(); ToolItem item = toolBar.getItem(localCoordinates); if (item == null) { item = toolBar.getItem(toolBar.getItemCount() - 1); } Rectangle itemBounds = item.getBounds(); dropLocation.before = (localCoordinates.x - itemBounds.x < itemBounds.width / 2); dropLocation.part = getPartForTab(item); // Also store the current index of the part we're dragging over. We will use // the index if the part no longer exists at the time the drop occurs (ie: // if we're dragging an item over itself) dropLocation.insertionPosition = toolBar.indexOf(item); Point displayCoordinates = toolBar.toDisplay(itemBounds.x, itemBounds.y); Rectangle bounds = new Rectangle(displayCoordinates.x, displayCoordinates.y, 4, itemBounds.height); if (!dropLocation.before) { bounds.x += itemBounds.width; } return new StackDropResult(bounds, dropLocation); } return null; } public void setActive(int newState) { activeFocus = (newState == AS_ACTIVE_FOCUS); presentationControl.redraw(); } public void setState(int state) { updateToolbarImages(); } public void showPaneMenu(Point location) { if (current == null) { return; } IPartMenu menu = current.getMenu(); if (menu == null) { return; } menu.showMenu(location); } public void showPaneMenu() { Rectangle bounds = titleIconToolbar.getBounds(); Point location = titleIconToolbar.getParent().toDisplay(bounds.x, bounds.y + bounds.height); showPaneMenu(location); } public void showSystemMenu() { Rectangle bounds = viewMenu.getBounds(); Point displayPos = viewMenu.getParent().toDisplay(bounds.x, bounds.y + bounds.height); showSystemMenu(displayPos); } public void showSystemMenu(Point displayPos) { systemMenuManager.show(getControl(), displayPos, getCurrent()); // Menu aMenu = systemMenuManager.createContextMenu(presentationControl); // systemMenuManager.update(true); // aMenu.setLocation(displayPos.x, displayPos.y); // aMenu.setVisible(true); } /* (non-Javadoc) * @see org.eclipse.ui.presentations.StackPresentation#showPartList() */ public void showPartList() { // The part list opens when the user presses ctrl-e to open the list // of editors. In this presentation, the part list is part of the system menu, // so opening the part list is equivalent to opening the system menu. showSystemMenu(); } protected void showToolbar(IPresentablePart part, boolean shouldShow) { if (shouldShow != isShowingToolbar(part)) { ToolItem tab = getTab(part); tab.setData(SHOWING_TOOLBAR, shouldShow ? SHOWING_TOOLBAR : null); if (part == current) { Control toolbar = part.getToolBar(); if (toolbar != null) { toolbar.setVisible(shouldShow); } layout(); updateToolbarImages(); if (getSite().getState() == IStackPresentationSite.STATE_MINIMIZED) { getSite().setState(IStackPresentationSite.STATE_RESTORED); } } } } /** * @param selection */ public void showToolbar(boolean selection) { if (current != null) { showToolbar(current, selection); } } public IPresentablePart getCurrent() { return current; } private boolean isShowingToolbar(IPresentablePart part) { ToolItem tab = getTab(part); return tab.getData(SHOWING_TOOLBAR) != null; } public boolean isShowingToolbar() { if (current == null) { return false; } return isShowingToolbar(current); } /** * @param parts */ public void close(IPresentablePart[] parts) { getSite().close(parts); } private Color getBorderColor() { ITheme current = PlatformUI.getWorkbench().getThemeManager().getCurrentTheme(); if(activeFocus) { return current.getColorRegistry().get(WrappedTabsThemeConstants.BORDER_COLOR_FOCUS); } else { return current.getColorRegistry().get(WrappedTabsThemeConstants.BORDER_COLOR_NOFOCUS); } } }