/******************************************************************************* * Copyright (c) 2004, 2006 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.util; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; 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.ui.presentations.IStackPresentationSite; import org.eclipse.ui.presentations.PresentationUtil; /** * @since 3.1 */ public abstract class AbstractTabFolder { private List listeners = new ArrayList(1); private Control toolbar; private int state; public abstract Point computeSize(int widthHint, int heightHint); public abstract AbstractTabItem add(int index, int flags); public abstract Composite getContentParent(); public abstract void setContent(Control newContent); public abstract AbstractTabItem[] getItems(); public abstract AbstractTabItem getSelection(); public abstract void setSelection(AbstractTabItem toSelect); public abstract void setSelectedInfo(PartInfo info); public abstract void enablePaneMenu(boolean enabled); private int activeState = IStackPresentationSite.STATE_RESTORED; 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); handleContextMenu(globalPos, event); } }; private Listener dragListener = new Listener() { public void handleEvent(Event e) { Point globalPos = ((Control)e.widget).toDisplay(e.x, e.y); handleDragStarted(globalPos, e); } }; 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 = ((Control)e.widget).toDisplay(e.x, e.y); handleMouseDown(p, e); } // If we double-click on the toolbar, maximize the presentation public void mouseDoubleClick(MouseEvent e) { Point p = ((Control)e.widget).toDisplay(e.x, e.y); handleDoubleClick(p, e); } }; public void setActive(int activeState) { this.activeState = activeState; } public int getActive() { return activeState; } /** * Returns the location where the pane menu should be opened when activated * by a keyboard shortcut (display coordinates) * * @return the location for the pane menu (display coordinates) * @since 3.1 */ public Point getPaneMenuLocation() { return getControl().toDisplay(new Point(0,0)); } /** * Returns the location where the part list should be opened when activated * by a keyboard shortcut (display coordinates) * * @return the location for the part list (display coordinates) * @since 3.1 */ public Point getPartListLocation() { return getSystemMenuLocation(); } /** * Returns the location where the pane menu should be opened when activated * by a keyboard shortcut (display coordinates) * * @return the location for the pane menu (display coordinates) * @since 3.1 */ public Point getSystemMenuLocation() { return getControl().toDisplay(new Point(0,0)); } /** * Returns the parent composite that should be used for creating the toolbar. * Any control passed into setToolbar must have this composite as its parent. * * @return the parent composite that should be used for creating the toolbar * * @since 3.1 */ public abstract Composite getToolbarParent(); /** * Returns the main control for this folder. * * @return the main control for the folder * @since 3.1 */ public abstract Control getControl(); public AbstractTabItem getItem(int idx) { return getItems()[idx]; } public AbstractTabItem getItem(Point toFind) { AbstractTabItem[] items = getItems(); for (int i = 0; i < items.length; i++) { AbstractTabItem item = items[i]; if (item.getBounds().contains(toFind)) { return item; } } return null; } public AbstractTabItem findItem(Object dataToFind) { AbstractTabItem[] items = getItems(); for (int i = 0; i < items.length; i++) { AbstractTabItem item = items[i]; if (item.getData() == dataToFind) { return item; } } return null; } /** * Returns the index of the given item, or -1 if the given item is * not found in this tab folder. Subclasses should override this if * the underlying SWT widget has an equivalent method * * @param item item to find * @return the index of the given item or -1 */ public int indexOf(AbstractTabItem item) { AbstractTabItem[] items = getItems(); for (int idx = 0; idx < items.length; idx++) { AbstractTabItem next = items[idx]; if (next == item) { return idx; } } return -1; } public int getItemCount() { return getItems().length; } public void setToolbar(Control toolbarControl) { this.toolbar = toolbarControl; } public final Control getToolbar() { return toolbar; } /** * Sets the current state for the folder * * @param state one of the IStackPresentationSite.STATE_* constants */ public void setState(int state) { this.state = state; } /** * Returns the title area for this control (in the control's coordinate system) * * @return */ public abstract Rectangle getTabArea(); /** * Called when the tab folder's shell becomes active or inactive. Subclasses * can override this to change the appearance of the tabs based on activation. * * @param isActive */ public void shellActive(boolean isActive) { } /** * Adds the given listener to this AbstractTabFolder * * @param newListener the listener to add */ public final void addListener(TabFolderListener newListener) { listeners.add(newListener); } /** * Removes the given listener from this AbstractTabFolder * * @param toRemove the listener to remove */ public final void removeListener(TabFolderListener toRemove) { listeners.remove(toRemove); } public void flushToolbarSize() { } protected final void fireEvent(TabFolderEvent e) { for (Iterator iter = listeners.iterator(); iter.hasNext();) { TabFolderListener next = (TabFolderListener)iter.next(); next.handleEvent(e); } } protected final void fireEvent(int id) { fireEvent(new TabFolderEvent(id)); } protected final void fireEvent(int id, AbstractTabItem w) { fireEvent(new TabFolderEvent(id, w, 0, 0)); } protected final void fireEvent(int id, AbstractTabItem w, Point pos) { fireEvent(new TabFolderEvent(id, w, pos)); } public void layout(boolean flushCache) { } public void setTabPosition(int tabPosition) { } public int getTabPosition() { return SWT.TOP; } public int getState() { return state; } protected void attachListeners(Control theControl, boolean recursive) { theControl.addListener(SWT.MenuDetect, menuListener); theControl.addMouseListener(mouseListener); PresentationUtil.addDragListener(theControl, dragListener); if (recursive && theControl instanceof Composite) { Composite composite = (Composite) theControl; Control[] children = composite.getChildren(); for (int i = 0; i < children.length; i++) { Control control = children[i]; attachListeners(control, recursive); } } } protected void detachListeners(Control theControl, boolean recursive) { theControl.removeListener(SWT.MenuDetect, menuListener); theControl.removeMouseListener(mouseListener); PresentationUtil.removeDragListener(theControl, dragListener); if (recursive && theControl instanceof Composite) { Composite composite = (Composite) theControl; Control[] children = composite.getChildren(); for (int i = 0; i < children.length; i++) { Control control = children[i]; detachListeners(control, recursive); } } } protected void handleContextMenu(Point displayPos, Event e) { if (isOnBorder(displayPos)) { return; } AbstractTabItem tab = getItem(displayPos); fireEvent(TabFolderEvent.EVENT_SYSTEM_MENU, tab, displayPos); } protected void handleMouseDown(Point displayPos, MouseEvent e) { fireEvent(TabFolderEvent.EVENT_GIVE_FOCUS_TO_PART); } protected void handleDoubleClick(Point displayPos, MouseEvent e) { if (isOnBorder(displayPos)) { return; } if (getState() == IStackPresentationSite.STATE_MAXIMIZED) { fireEvent(TabFolderEvent.EVENT_RESTORE); } else { fireEvent(TabFolderEvent.EVENT_MAXIMIZE); } } protected void handleDragStarted(Point displayPos, Event e) { if (isOnBorder(displayPos)) { return; } AbstractTabItem tab = getItem(displayPos); fireEvent(TabFolderEvent.EVENT_DRAG_START, tab, displayPos); } /** * Returns true iff the given point is on the border of the folder. * By default, double-clicking, context menus, and drag/drop are disabled * on the folder's border. * * @param toTest a point (display coordinates) * @return true iff the point is on the presentation border * @since 3.1 */ public boolean isOnBorder(Point toTest) { return false; } /** * Set the folder to visible. This can be extended to propogate the * visibility request to other components in the subclass. * * @param visible * <code>true</code> - the folder is visible. * @since 3.2 */ public void setVisible(boolean visible) { getControl().setVisible(visible); } /** * Cause the folder to hide or show its * Minimize and Maximize affordances. * * @param show * <code>true</code> - the min/max buttons are visible. * @since 3.3 */ public void showMinMax(boolean show) { } }