| /******************************************************************************* |
| * Copyright (c) 2007 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.layout; |
| |
| import org.eclipse.jface.action.ContributionItem; |
| import org.eclipse.jface.action.MenuManager; |
| import org.eclipse.jface.action.ToolBarManager; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.events.SelectionListener; |
| import org.eclipse.swt.graphics.Cursor; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.CoolBar; |
| import org.eclipse.swt.widgets.CoolItem; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.swt.widgets.Listener; |
| import org.eclipse.swt.widgets.Menu; |
| import org.eclipse.swt.widgets.MenuItem; |
| import org.eclipse.swt.widgets.ToolBar; |
| import org.eclipse.swt.widgets.ToolItem; |
| import org.eclipse.ui.internal.IChangeListener; |
| import org.eclipse.ui.internal.IntModel; |
| import org.eclipse.ui.internal.RadioMenu; |
| import org.eclipse.ui.internal.TrimFrame; |
| import org.eclipse.ui.internal.WorkbenchMessages; |
| import org.eclipse.ui.internal.WorkbenchWindow; |
| |
| /** |
| * This control provides common UI functionality for trim elements |
| * that wish to use a ToolBarManager-based implementation. |
| * <p> |
| * It provides the following features: |
| * <p> |
| * Drag affordance and handling: |
| * <ol> |
| * <li>The ToolBar is contained within a CoolBar/Item to provide the same |
| * drag handle affordance as the rest of the trim |
| * <li>Drag handling is provided to allow rearrangement within a trim side or |
| * to other sides, depending on the values returned by <code>IWindowTrim.getValidSides</code></li> |
| * </ol> |
| * </p> |
| * <p> |
| * Context Menu: |
| * <ol> |
| * <li>A "Dock on" menu item is provided to allow changing the side, depending on the values returned by |
| * <code>IWindowTrim.getValidSides</code></li> |
| * <li>A "Close" menu item is provided to allow the User to close (hide) the trim element, |
| * based on the value returned by <code>IWindowTrim.isCloseable</code> |
| * </ol> |
| * </p> |
| * <p> |
| * @since 3.3 |
| * </p> |
| */ |
| public abstract class TrimToolBarBase implements IWindowTrim { |
| // Fields |
| protected String id; |
| protected int orientation; |
| protected WorkbenchWindow wbw; |
| protected TrimLayout layout; |
| protected ToolBarManager tbMgr = null; |
| protected ToolItem contextToolItem = null; |
| |
| // CoolBar handling |
| private TrimFrame frame = null; |
| private CoolBar cb = null; |
| private CoolItem ci = null; |
| |
| // Context Menu |
| private MenuManager dockMenuManager; |
| private ContributionItem dockContributionItem = null; |
| private Menu sidesMenu; |
| private MenuItem dockCascade; |
| private RadioMenu radioButtons; |
| private IntModel radioVal = new IntModel(0); |
| // private Menu showMenu; |
| // private MenuItem showCascade; |
| |
| /* |
| * Listeners... |
| */ |
| |
| private Listener tbListener = new Listener() { |
| public void handleEvent(Event event) { |
| Point loc = new Point(event.x, event.y); |
| if (event.type == SWT.MenuDetect) { |
| showToolBarPopup(loc); |
| } |
| } |
| }; |
| |
| /** |
| * This listener brings up the context menu |
| */ |
| private Listener cbListener = new Listener() { |
| public void handleEvent(Event event) { |
| Point loc = new Point(event.x, event.y); |
| if (event.type == SWT.MenuDetect) { |
| showDockTrimPopup(loc); |
| } |
| } |
| }; |
| |
| |
| /** |
| * Create a new trim UI handle for a particular IWindowTrim item |
| * |
| * @param layout the TrimLayout we're being used in |
| * @param trim the IWindowTrim we're acting on behalf of |
| * @param curSide the SWT side that the trim is currently on |
| */ |
| protected TrimToolBarBase(String id, int curSide, WorkbenchWindow wbw) { |
| this.id = id; |
| this.wbw = wbw; |
| this.layout = (TrimLayout) wbw.getTrimManager(); |
| } |
| |
| /** |
| * @param loc |
| */ |
| private void showToolBarPopup(Point loc) { |
| Point tbLoc = tbMgr.getControl().toControl(loc); |
| contextToolItem = tbMgr.getControl().getItem(tbLoc); |
| MenuManager mm = tbMgr.getContextMenuManager(); |
| if (mm != null) { |
| Menu menu = mm.createContextMenu(wbw.getShell()); |
| menu.setLocation(loc.x, loc.y); |
| menu.setVisible(true); |
| } |
| } |
| |
| /** |
| * Initialize the ToolBarManger for this instance. We create a |
| * new ToolBarManager whenever we need to and this gives the |
| * derived class a chance to define the ICI's and context |
| * menu... |
| * |
| * @param mgr The manager to initialize |
| */ |
| public abstract void initToolBarManager(ToolBarManager mgr); |
| |
| /** |
| * Hook any necessary listeners to the new ToolBar instance. |
| * <p> |
| * NOTE: Clients should add a dispose listener if necessary to |
| * unhook listeners added through this call. |
| * </p> |
| * @param mgr The ToolBarManager whose control is to be hooked |
| */ |
| public abstract void hookControl(ToolBarManager mgr); |
| |
| /** |
| * Set up the trim with its cursor, drag listener, context menu and menu listener. |
| * This method can also be used to 'recycle' a trim handle as long as the new handle |
| * is for trim under the same parent as it was originally used for. |
| */ |
| private void createControl(int curSide) { |
| // out with the old |
| dispose(); |
| |
| this.radioVal.set(curSide); |
| |
| // remember the orientation to use |
| orientation = (curSide == SWT.LEFT || curSide == SWT.RIGHT) ? SWT.VERTICAL : SWT.HORIZONTAL; |
| |
| frame = new TrimFrame(wbw.getShell()); |
| |
| // Create the necessary parts... |
| cb = new CoolBar(frame.getComposite(), orientation | SWT.FLAT); |
| ci = new CoolItem(cb, SWT.FLAT); |
| |
| // Create (and 'fill') the toolbar |
| tbMgr = new ToolBarManager(orientation | SWT.FLAT); |
| |
| // Have the subclass define any manager content |
| initToolBarManager(tbMgr); |
| |
| // Create the new ToolBar |
| ToolBar tb = tbMgr.createControl(cb); |
| ci.setControl(tb); |
| |
| // Have the subclass hook any listeners |
| hookControl(tbMgr); |
| |
| // set up the frame's layout |
| update(true); |
| |
| // Set the cursor affordance |
| Cursor dragCursor = getControl().getDisplay().getSystemCursor(SWT.CURSOR_SIZEALL); |
| cb.setCursor(dragCursor); |
| |
| // Now, we have to explicity set the arrow for the TB |
| Cursor tbCursor = getControl().getDisplay().getSystemCursor(SWT.CURSOR_ARROW); |
| tb.setCursor(tbCursor); |
| |
| //cb.setBackground(cb.getDisplay().getSystemColor(SWT.COLOR_RED)); |
| |
| // Set up the dragging behaviour |
| // PresentationUtil.addDragListener(cb, dragListener); |
| |
| // Create the docking context menu |
| dockMenuManager = new MenuManager(); |
| dockContributionItem = getDockingContribution(); |
| dockMenuManager.add(dockContributionItem); |
| |
| tb.addListener(SWT.MenuDetect, tbListener); |
| cb.addListener(SWT.MenuDetect, cbListener); |
| |
| //tbMgr.getControl().setBackground(cb.getDisplay().getSystemColor(SWT.COLOR_GREEN)); |
| //tbMgr.getControl().pack(true); |
| cb.pack(true); |
| cb.setVisible(true); |
| |
| tbMgr.getControl().setVisible(true); |
| cb.setVisible(true); |
| frame.getComposite().setVisible(true); |
| } |
| |
| /** |
| * Handle the event generated when a User selects a new side to |
| * dock this trim on using the context menu |
| */ |
| private void handleShowOnChange() { |
| if (getControl() == null) |
| return; |
| |
| layout.removeTrim(this); |
| dock(radioVal.get()); |
| layout.addTrim(radioVal.get(), this, null); |
| |
| // perform an optimized layout to show the trim in its new location |
| LayoutUtil.resize(getControl()); |
| } |
| |
| /** |
| * Force the toobar to re-synch to the model |
| * @param changed true if changes have occurred in the structure |
| */ |
| public void update(boolean changed) { |
| tbMgr.update(changed); |
| |
| // Force a resize |
| tbMgr.getControl().pack(); |
| Point size = tbMgr.getControl().getSize(); |
| //tbMgr.getControl().setBounds(0, 0, size.x, size.y); |
| Point ps = ci.computeSize (size.x, size.y); |
| ci.setPreferredSize (ps); |
| ci.setSize(ps); |
| cb.pack(); |
| cb.update(); |
| LayoutUtil.resize(getControl()); |
| } |
| |
| /** |
| * Construct (if necessary) a context menu contribution item and return it. This |
| * is explicitly <code>public</code> so that trim elements can retrieve the item |
| * and add it into their own context menus if desired. |
| * |
| * @return The contribution item for the handle's context menu. |
| */ |
| private ContributionItem getDockingContribution() { |
| if (dockContributionItem == null) { |
| dockContributionItem = new ContributionItem() { |
| public void fill(Menu menu, int index) { |
| // populate from superclass |
| super.fill(menu, index); |
| |
| // Add a 'Close' menu entry if the trim supports the operation |
| if (isCloseable()) { |
| MenuItem closeItem = new MenuItem(menu, SWT.PUSH, index++); |
| closeItem.setText(WorkbenchMessages.TrimCommon_Close); |
| |
| closeItem.addSelectionListener(new SelectionListener() { |
| public void widgetSelected(SelectionEvent e) { |
| handleCloseTrim(); |
| } |
| |
| public void widgetDefaultSelected(SelectionEvent e) { |
| } |
| }); |
| |
| new MenuItem(menu, SWT.SEPARATOR, index++); |
| } |
| |
| // Test Hook: add a menu entry that brings up a dialog to allow |
| // testing with various GUI prefs. |
| // MenuItem closeItem = new MenuItem(menu, SWT.PUSH, index++); |
| // closeItem.setText("Change Preferences"); //$NON-NLS-1$ |
| // |
| // closeItem.addSelectionListener(new SelectionListener() { |
| // public void widgetSelected(SelectionEvent e) { |
| // handleChangePreferences(); |
| // } |
| // |
| // public void widgetDefaultSelected(SelectionEvent e) { |
| // } |
| // }); |
| // |
| // new MenuItem(menu, SWT.SEPARATOR, index++); |
| |
| // Create a cascading menu to allow the user to dock the trim |
| dockCascade = new MenuItem(menu, SWT.CASCADE, index++); |
| { |
| dockCascade.setText(WorkbenchMessages.TrimCommon_DockOn); |
| |
| sidesMenu = new Menu(dockCascade); |
| radioButtons = new RadioMenu(sidesMenu, radioVal); |
| |
| radioButtons.addMenuItem(WorkbenchMessages.TrimCommon_Top, new Integer(SWT.TOP)); |
| radioButtons.addMenuItem(WorkbenchMessages.TrimCommon_Bottom, new Integer(SWT.BOTTOM)); |
| radioButtons.addMenuItem(WorkbenchMessages.TrimCommon_Left, new Integer(SWT.LEFT)); |
| radioButtons.addMenuItem(WorkbenchMessages.TrimCommon_Right, new Integer(SWT.RIGHT)); |
| |
| dockCascade.setMenu(sidesMenu); |
| } |
| |
| // if the radioVal changes it means that the User wants to change the docking location |
| radioVal.addChangeListener(new IChangeListener() { |
| public void update(boolean changed) { |
| if (changed) { |
| handleShowOnChange(); |
| } |
| } |
| }); |
| |
| // Provide Show / Hide trim capabilities |
| // showCascade = new MenuItem(menu, SWT.CASCADE, index++); |
| // { |
| // showCascade.setText(WorkbenchMessages.TrimCommon_ShowTrim); |
| // |
| // showMenu = new Menu(dockCascade); |
| // |
| // // Construct a 'hide/show' cascade from -all- the existing trim... |
| // List trimItems = layout.getAllTrim(); |
| // Iterator d = trimItems.iterator(); |
| // while (d.hasNext()) { |
| // IWindowTrim trimItem = (IWindowTrim) d.next(); |
| // MenuItem item = new MenuItem(showMenu, SWT.CHECK); |
| // item.setText(trimItem.getDisplayName()); |
| // item.setSelection(trimItem.getControl().getVisible()); |
| // item.setData(trimItem); |
| // |
| // // TODO: Make this work...wire it off for now |
| // item.setEnabled(false); |
| // |
| // item.addSelectionListener(new SelectionListener() { |
| // |
| // public void widgetSelected(SelectionEvent e) { |
| // IWindowTrim trim = (IWindowTrim) e.widget.getData(); |
| // layout.setTrimVisible(trim, !trim.getControl().getVisible()); |
| // } |
| // |
| // public void widgetDefaultSelected(SelectionEvent e) { |
| // } |
| // |
| // }); |
| // } |
| // |
| // showCascade.setMenu(showMenu); |
| // } |
| } |
| }; |
| } |
| return dockContributionItem; |
| } |
| |
| /** |
| * @return The side the trm is currently on |
| */ |
| public int getCurrentSide() { |
| return radioVal.get(); |
| } |
| |
| /** |
| * Test Hook: Bring up a dialog that allows the user to |
| * modify the trimdragging GUI preferences. |
| */ |
| // private void handleChangePreferences() { |
| // TrimDragPreferenceDialog dlg = new TrimDragPreferenceDialog(getShell()); |
| // dlg.open(); |
| // } |
| |
| /** |
| * Handle the event generated when the "Close" item is |
| * selected on the context menu. This removes the associated |
| * trim and calls back to the IWidnowTrim to inform it that |
| * the User has closed the trim. |
| */ |
| private void handleCloseTrim() { |
| handleClose(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.swt.widgets.Widget#dispose() |
| */ |
| public void dispose() { |
| if (getControl() == null || getControl().isDisposed()) |
| return; |
| |
| if (radioButtons != null) { |
| radioButtons.dispose(); |
| } |
| |
| // tidy up... |
| getControl().removeListener(SWT.MenuDetect, cbListener); |
| |
| tbMgr.dispose(); |
| tbMgr = null; |
| |
| getControl().dispose(); |
| frame = null; |
| } |
| |
| |
| /** |
| * Shows the popup menu for an item in the fast view bar. |
| */ |
| private void showDockTrimPopup(Point pt) { |
| Menu menu = dockMenuManager.createContextMenu(this.getControl()); |
| menu.setLocation(pt.x, pt.y); |
| menu.setVisible(true); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ui.internal.layout.IWindowTrim#dock(int) |
| */ |
| public void dock(int dropSide) { |
| createControl(dropSide); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ui.internal.layout.IWindowTrim#getControl() |
| */ |
| public Control getControl() { |
| if (frame == null) |
| return null; |
| |
| return frame.getComposite(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ui.internal.layout.IWindowTrim#getDisplayName() |
| */ |
| public String getDisplayName() { |
| return id; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ui.internal.layout.IWindowTrim#getHeightHint() |
| */ |
| public int getHeightHint() { |
| return getControl().computeSize(SWT.DEFAULT, SWT.DEFAULT, true).y; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ui.internal.layout.IWindowTrim#getId() |
| */ |
| public String getId() { |
| return id; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ui.internal.layout.IWindowTrim#getValidSides() |
| */ |
| public int getValidSides() { |
| return SWT.BOTTOM | SWT.TOP | SWT.LEFT | SWT.RIGHT; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ui.internal.layout.IWindowTrim#getWidthHint() |
| */ |
| public int getWidthHint() { |
| return getControl().computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ui.internal.layout.IWindowTrim#handleClose() |
| */ |
| public void handleClose() { |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ui.internal.layout.IWindowTrim#isCloseable() |
| */ |
| public boolean isCloseable() { |
| return false; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ui.internal.layout.IWindowTrim#isResizeable() |
| */ |
| public boolean isResizeable() { |
| return false; |
| } |
| } |