/******************************************************************************* * Copyright (c) 2004, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.ui.internal.presentations; import java.util.ArrayList; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.util.Geometry; import org.eclipse.swt.SWT; 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.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; import org.eclipse.ui.IPropertyListener; import org.eclipse.ui.IWorkbenchPreferenceConstants; import org.eclipse.ui.internal.WorkbenchPlugin; import org.eclipse.ui.presentations.IPresentablePart; import org.eclipse.ui.presentations.IStackPresentationSite; import org.eclipse.ui.presentations.PresentationUtil; import org.eclipse.ui.presentations.StackDropResult; import org.eclipse.ui.presentations.StackPresentation; /** * A stack presentation using native widgets. * <p> * EXPERIMENTAL * </p> * * @since 3.0 */ public class NativeStackPresentation extends StackPresentation { private TabFolder tabFolder; private Listener dragListener; private IPresentablePart current; private MenuManager systemMenuManager = new MenuManager(); private static IPreferenceStore preferenceStore = WorkbenchPlugin.getDefault() .getPreferenceStore(); // don't reset this dynamically, so just keep the information static. // see bug: // 75422 [Presentations] Switching presentation to R21 switches immediately, but only partially private static int tabPos = preferenceStore.getInt(IWorkbenchPreferenceConstants.VIEW_TAB_POSITION); private final static String TAB_DATA = NativeStackPresentation.class .getName() + ".partId"; //$NON-NLS-1$ private MouseListener mouseListener = new MouseAdapter() { public void mouseDown(MouseEvent e) { // // PR#1GDEZ25 - If selection will change in mouse up ignore mouse down. // // Else, set focus. // TabItem newItem = tabFolder.getItem(new Point(e.x, e.y)); // if (newItem != null) { // TabItem oldItem = tabFolder.getSelection(); // if (newItem != oldItem) // return; // } if (current != null) { current.setFocus(); } } }; 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 pos = new Point(event.x, event.y); // TabItem item = tabFolder.getItem(pos); TabItem item = null; IPresentablePart part = null; if (item != null) { part = getPartForTab(item); } showPaneMenu(part, pos); } }; private Listener selectionListener = new Listener() { public void handleEvent(Event e) { IPresentablePart item = getPartForTab((TabItem) e.item); if (item != null) { getSite().selectPart(item); // item.setFocus(); } } }; private Listener resizeListener = new Listener() { public void handleEvent(Event e) { setControlSize(); } }; private IPropertyListener childPropertyChangeListener = new IPropertyListener() { public void propertyChanged(Object source, int property) { if (isDisposed()) { return; } if (source instanceof IPresentablePart) { IPresentablePart part = (IPresentablePart) source; childPropertyChanged(part, property); } } }; private DisposeListener tabDisposeListener = new DisposeListener() { public void widgetDisposed(DisposeEvent e) { if (e.widget instanceof TabItem) { TabItem item = (TabItem) e.widget; IPresentablePart part = getPartForTab(item); part.removePropertyListener(childPropertyChangeListener); } } }; public NativeStackPresentation(Composite parent, IStackPresentationSite stackSite) { super(stackSite); tabFolder = new TabFolder(parent, tabPos); // listener to switch between visible tabItems tabFolder.addListener(SWT.Selection, selectionListener); // listener to resize visible components tabFolder.addListener(SWT.Resize, resizeListener); // listen for mouse down on tab to set focus. tabFolder.addMouseListener(mouseListener); tabFolder.addListener(SWT.MenuDetect, menuListener); dragListener = new Listener() { public void handleEvent(Event event) { Point localPos = new Point(event.x, event.y); // TabItem tabUnderPointer = tabFolder.getItem(localPos); TabItem tabUnderPointer = null; if (tabUnderPointer == null) { return; } IPresentablePart part = getPartForTab(tabUnderPointer); if (getSite().isPartMoveable(part)) { getSite().dragStart(part, tabFolder.toDisplay(localPos), false); } } }; PresentationUtil.addDragListener(tabFolder, dragListener); } /** * Returns the index of the tab for the given part, or returns tabFolder.getItemCount() * if there is no such tab. * * @param part part being searched for * @return the index of the tab for the given part, or the number of tabs * if there is no such tab */ private final int indexOf(IPresentablePart part) { if (part == null) { return tabFolder.getItemCount(); } TabItem[] items = tabFolder.getItems(); for (int idx = 0; idx < items.length; idx++) { IPresentablePart tabPart = getPartForTab(items[idx]); if (part == tabPart) { return idx; } } return items.length; } /** * Returns the tab for the given part, or null if there is no such tab * * @param part the part being searched for * @return the tab for the given part, or null if there is no such tab */ protected final TabItem getTab(IPresentablePart part) { TabItem[] items = tabFolder.getItems(); int idx = indexOf(part); if (idx < items.length) { return items[idx]; } return null; } /** * @param part * @param property */ protected void childPropertyChanged(IPresentablePart part, int property) { TabItem tab = getTab(part); initTab(tab, part); } protected final IPresentablePart getPartForTab(TabItem item) { IPresentablePart part = (IPresentablePart) item.getData(TAB_DATA); return part; } protected TabFolder getTabFolder() { return tabFolder; } public boolean isDisposed() { return tabFolder == null || tabFolder.isDisposed(); } /** * Set the size of a page in the folder. */ private void setControlSize() { if (current == null || tabFolder == null) { return; } // Rectangle bounds; // @issue as above, the mere presence of a theme should not change the behaviour // if ((mapTabToPart.size() > 1) // || ((tabThemeDescriptor != null) && (mapTabToPart.size() >= 1))) // bounds = calculatePageBounds(tabFolder); // else // bounds = tabFolder.getBounds(); current.setBounds(calculatePageBounds(tabFolder)); //current.moveAbove(tabFolder); } public static Rectangle calculatePageBounds(TabFolder folder) { if (folder == null) { return new Rectangle(0, 0, 0, 0); } Rectangle bounds = folder.getBounds(); Rectangle offset = folder.getClientArea(); bounds.x += offset.x; bounds.y += offset.y; bounds.width = offset.width; bounds.height = offset.height; return bounds; } /* (non-Javadoc) * @see org.eclipse.ui.internal.skins.Presentation#dispose() */ public void dispose() { if (isDisposed()) { return; } PresentationUtil.removeDragListener(tabFolder, dragListener); //systemMenuManager.dispose(); tabFolder.dispose(); tabFolder = null; } private TabItem createPartTab(IPresentablePart part, int tabIndex) { TabItem tabItem = new TabItem(tabFolder, SWT.NONE, tabIndex); tabItem.setData(TAB_DATA, part); part.addPropertyListener(childPropertyChangeListener); tabItem.addDisposeListener(tabDisposeListener); initTab(tabItem, part); return tabItem; } /** * Initializes a tab for the given part. Sets the text, icon, tool tip, * etc. This will also be called whenever a relevant property changes * in the part to reflect those changes in the tab. Subclasses may override * to change the appearance of tabs for a particular part. * * @param tabItem tab for the part * @param part the part being displayed */ protected void initTab(TabItem tabItem, IPresentablePart part) { tabItem.setText(part.getName()); tabItem.setToolTipText(part.getTitleToolTip()); Image tabImage = part.getTitleImage(); if (tabImage != tabItem.getImage()) { tabItem.setImage(tabImage); } } /* (non-Javadoc) * @see org.eclipse.ui.internal.skins.StackPresentation#addPart(org.eclipse.ui.internal.skins.IPresentablePart, org.eclipse.ui.internal.skins.IPresentablePart) */ public void addPart(IPresentablePart newPart, Object cookie) { createPartTab(newPart, tabFolder.getItemCount()); } /* (non-Javadoc) * @see org.eclipse.ui.internal.skins.StackPresentation#removePart(org.eclipse.ui.internal.skins.IPresentablePart) */ public void removePart(IPresentablePart oldPart) { TabItem item = getTab(oldPart); if (item == null) { return; } oldPart.setVisible(false); item.dispose(); } /* (non-Javadoc) * @see org.eclipse.ui.internal.skins.StackPresentation#selectPart(org.eclipse.ui.internal.skins.IPresentablePart) */ public void selectPart(IPresentablePart toSelect) { if (toSelect == current) { return; } if (current != null) { current.setVisible(false); } current = toSelect; if (current != null) { tabFolder.setSelection(indexOf(current)); current.setVisible(true); setControlSize(); } } /* (non-Javadoc) * @see org.eclipse.ui.internal.skins.Presentation#setBounds(org.eclipse.swt.graphics.Rectangle) */ public void setBounds(Rectangle bounds) { tabFolder.setBounds(bounds); setControlSize(); } /* (non-Javadoc) * @see org.eclipse.ui.internal.skins.Presentation#computeMinimumSize() */ public Point computeMinimumSize() { return Geometry.getSize(tabFolder.computeTrim(0, 0, 0, 0)); } /* (non-Javadoc) * @see org.eclipse.ui.internal.skins.Presentation#setVisible(boolean) */ public void setVisible(boolean isVisible) { if (current != null) { current.setVisible(isVisible); } tabFolder.setVisible(isVisible); } /* (non-Javadoc) * @see org.eclipse.ui.internal.skins.Presentation#setState(int) */ public void setState(int state) { // tabFolder.setMinimized(state == IPresentationSite.STATE_MINIMIZED); // tabFolder.setMaximized(state == IPresentationSite.STATE_MAXIMIZED); } /* (non-Javadoc) * @see org.eclipse.ui.internal.skins.Presentation#getSystemMenuManager() */ public IMenuManager getSystemMenuManager() { return systemMenuManager; } /** * @param part * @param point */ protected void showPaneMenu(IPresentablePart part, Point point) { systemMenuManager.update(false); Menu aMenu = systemMenuManager.createContextMenu(tabFolder.getParent()); aMenu.setLocation(point.x, point.y); aMenu.setVisible(true); } /* (non-Javadoc) * @see org.eclipse.ui.internal.skins.Presentation#getControl() */ public Control getControl() { return tabFolder; } /* (non-Javadoc) * @see org.eclipse.ui.internal.skins.StackPresentation#dragOver(org.eclipse.swt.widgets.Control, org.eclipse.swt.graphics.Point) */ public StackDropResult dragOver(Control currentControl, Point location) { // Determine which tab we're currently dragging over // Point localPos = tabFolder.toControl(location); // final TabItem tabUnderPointer = tabFolder.getItem(localPos); final TabItem tabUnderPointer = null; // This drop target only deals with tabs... if we're not dragging over // a tab, exit. if (tabUnderPointer == null) { return null; } // return new StackDropResult(Geometry.toDisplay(tabFolder, tabUnderPointer.getBounds()), // tabFolder.indexOf(tabUnderPointer)); return null; } /* (non-Javadoc) * @see org.eclipse.ui.presentations.StackPresentation#showSystemMenu() */ public void showSystemMenu() { // TODO Auto-generated method stub } /* (non-Javadoc) * @see org.eclipse.ui.presentations.StackPresentation#showPaneMenu() */ public void showPaneMenu() { // TODO Auto-generated method stub } /* (non-Javadoc) * @see org.eclipse.ui.presentations.StackPresentation#getTabList(IPresentablePart) */ public Control[] getTabList(IPresentablePart part) { ArrayList list = new ArrayList(); if (getControl() != null) { list.add(getControl()); } if (part.getToolBar() != null) { list.add(part.getToolBar()); } if (part.getControl() != null) { list.add(part.getControl()); } return (Control[]) list.toArray(new Control[list.size()]); } /* (non-Javadoc) * @see org.eclipse.ui.presentations.StackPresentation#getCurrentPart() */ public IPresentablePart getCurrentPart() { return current; } /* (non-Javadoc) * @see org.eclipse.ui.presentations.StackPresentation#setActive(int) */ public void setActive(int newState) { } }