| /******************************************************************************* |
| * Copyright (c) 2000, 2010 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.gef.ui.palette; |
| |
| import java.beans.PropertyChangeEvent; |
| import java.beans.PropertyChangeListener; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.swt.events.DisposeEvent; |
| import org.eclipse.swt.events.FocusEvent; |
| import org.eclipse.swt.graphics.Font; |
| import org.eclipse.swt.widgets.Display; |
| |
| import org.eclipse.ui.IMemento; |
| |
| import org.eclipse.draw2d.FigureCanvas; |
| import org.eclipse.draw2d.IFigure; |
| |
| import org.eclipse.gef.EditDomain; |
| import org.eclipse.gef.EditPart; |
| import org.eclipse.gef.GraphicalEditPart; |
| import org.eclipse.gef.editparts.SimpleRootEditPart; |
| import org.eclipse.gef.internal.ui.palette.PaletteSelectionTool; |
| import org.eclipse.gef.internal.ui.palette.editparts.DrawerEditPart; |
| import org.eclipse.gef.internal.ui.palette.editparts.PaletteStackEditPart; |
| import org.eclipse.gef.internal.ui.palette.editparts.ToolEntryEditPart; |
| import org.eclipse.gef.palette.PaletteDrawer; |
| import org.eclipse.gef.palette.PaletteEntry; |
| import org.eclipse.gef.palette.PaletteListener; |
| import org.eclipse.gef.palette.PaletteRoot; |
| import org.eclipse.gef.palette.PaletteStack; |
| import org.eclipse.gef.palette.ToolEntry; |
| import org.eclipse.gef.ui.palette.customize.PaletteCustomizerDialog; |
| import org.eclipse.gef.ui.palette.editparts.PaletteEditPart; |
| import org.eclipse.gef.ui.parts.PaletteViewerKeyHandler; |
| import org.eclipse.gef.ui.parts.ScrollingGraphicalViewer; |
| |
| /** |
| * Graphical viewer for the GEF palette. |
| * |
| * @author Randy Hudson |
| * @author Pratik Shah |
| */ |
| public class PaletteViewer extends ScrollingGraphicalViewer { |
| |
| private class PreferenceListener implements PropertyChangeListener { |
| /** |
| * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent) |
| */ |
| public void propertyChange(PropertyChangeEvent evt) { |
| String property = evt.getPropertyName(); |
| EditPart root = getRootEditPart().getContents(); |
| if (property.equals(PaletteViewerPreferences.PREFERENCE_FONT)) { |
| updateFont(); |
| refreshAllEditParts(root); |
| } else if (property |
| .equals(PaletteViewerPreferences.PREFERENCE_LAYOUT) |
| || property |
| .equals(PaletteViewerPreferences.PREFERENCE_AUTO_COLLAPSE) |
| || property |
| .equals(DefaultPaletteViewerPreferences |
| .convertLayoutToPreferenceName(getPaletteViewerPreferences() |
| .getLayoutSetting()))) { |
| refreshAllEditParts(root); |
| } |
| } |
| |
| private void refreshAllEditParts(EditPart part) { |
| part.refresh(); |
| List children = part.getChildren(); |
| for (Iterator iter = children.iterator(); iter.hasNext();) { |
| EditPart child = (EditPart) iter.next(); |
| refreshAllEditParts(child); |
| } |
| } |
| } |
| |
| private static final PaletteViewerPreferences PREFERENCE_STORE = new DefaultPaletteViewerPreferences(); |
| private ToolEntry activeEntry = null; |
| private PaletteCustomizer customizer = null; |
| private PaletteCustomizerDialog customizerDialog = null; |
| private boolean globalScrollbar = false; |
| private List paletteListeners = new ArrayList(); |
| private PaletteRoot paletteRoot = null; |
| private PreferenceListener prefListener = new PreferenceListener(); |
| private PaletteViewerPreferences prefs = PREFERENCE_STORE; |
| private Font font = null; |
| |
| /** |
| * Constructor |
| */ |
| public PaletteViewer() { |
| EditDomain domain = new EditDomain(); |
| domain.setDefaultTool(new PaletteSelectionTool()); |
| domain.loadDefaultTool(); |
| setEditDomain(domain); |
| setKeyHandler(new PaletteViewerKeyHandler(this)); |
| setEditPartFactory(new PaletteEditPartFactory()); |
| } |
| |
| /** |
| * Adds the given PaletteListener as the one to be notified when the active |
| * tool on the palette changes. |
| * |
| * @param paletteListener |
| * The listener that needs to be notified of active tool changes |
| * on the palette |
| */ |
| public void addPaletteListener(PaletteListener paletteListener) { |
| if (paletteListeners != null) |
| paletteListeners.add(paletteListener); |
| } |
| |
| /** |
| * @see org.eclipse.gef.ui.parts.GraphicalViewerImpl#createDefaultRoot() |
| */ |
| protected void createDefaultRoot() { |
| setRootEditPart(new SimpleRootEditPart()); |
| } |
| |
| private void disposeFont() { |
| if (font != null) { |
| font.dispose(); |
| font = null; |
| } |
| } |
| |
| /** |
| * Indicates that the palette should scroll using a native vertical |
| * scrollbar as opposed to individual lightweight buttons that appear |
| * dynamically on each drawer. The default settings is <code>false</code>. |
| * Enabling this setting requires additional horizontal screen space for the |
| * scrollbar. Therefore, its use is discouraged. |
| * <p> |
| * This setting must be changed prior to calling |
| * {@link ScrollingGraphicalViewer#createControl(org.eclipse.swt.widgets.Composite)} |
| * . After the control is created, changing this setting will have no |
| * effect. |
| * </p> |
| * |
| * @param value |
| * <code>true</code> if a vertical scrollbar should be displayed |
| */ |
| public void enableVerticalScrollbar(boolean value) { |
| this.globalScrollbar = value; |
| } |
| |
| /** |
| * @return the DrawerEditPart that has the given part; part, if part is a |
| * drawer; null, if part is not in a drawer |
| */ |
| private DrawerEditPart findContainingDrawer(EditPart part) { |
| if (part == null) |
| return null; |
| if (part instanceof DrawerEditPart) |
| return (DrawerEditPart) part; |
| return findContainingDrawer(part.getParent()); |
| } |
| |
| /** |
| * Notifies registered listeners of change in the active tool on the palette |
| */ |
| protected void fireModeChanged() { |
| if (paletteListeners == null) |
| return; |
| for (int listener = 0; listener < paletteListeners.size(); listener++) |
| ((PaletteListener) paletteListeners.get(listener)) |
| .activeToolChanged(this, activeEntry); |
| } |
| |
| /** |
| * @return the customizer |
| */ |
| public PaletteCustomizer getCustomizer() { |
| return customizer; |
| } |
| |
| /** |
| * NOTE: A PaletteCustomizer must be set for this viewer using the |
| * {@link #setCustomizer(PaletteCustomizer)} method before this method is |
| * invoked. |
| * |
| * @return The dialog that can be used to customize entries on the palette |
| */ |
| public PaletteCustomizerDialog getCustomizerDialog() { |
| if (customizerDialog == null) { |
| customizerDialog = new PaletteCustomizerDialog(getControl() |
| .getShell(), getCustomizer(), getPaletteRoot()); |
| } |
| return customizerDialog; |
| } |
| |
| /** |
| * @return the entry for the currently active tool |
| */ |
| public ToolEntry getActiveTool() { |
| return activeEntry; |
| } |
| |
| /** |
| * Returns the palette's root model. |
| * |
| * @return the palette root |
| */ |
| public PaletteRoot getPaletteRoot() { |
| return paletteRoot; |
| } |
| |
| /** |
| * @return The PaletteViewerPreferences that this palette is using to store |
| * its preferences (if none has been set, it returns the default |
| * one, which uses the GEF preference store) |
| */ |
| public PaletteViewerPreferences getPaletteViewerPreferences() { |
| return prefs; |
| } |
| |
| private ToolEntryEditPart getToolEntryEditPart(ToolEntry entry) { |
| return (ToolEntryEditPart) getEditPartRegistry().get(entry); |
| } |
| |
| /** |
| * @see org.eclipse.gef.ui.parts.GraphicalViewerImpl#handleDispose(org.eclipse.swt.events.DisposeEvent) |
| */ |
| protected void handleDispose(DisposeEvent e) { |
| super.handleDispose(e); |
| disposeFont(); |
| } |
| |
| /** |
| * @see org.eclipse.gef.ui.parts.GraphicalViewerImpl#handleFocusGained(FocusEvent) |
| */ |
| protected void handleFocusGained(FocusEvent fe) { |
| super.handleFocusGained(fe); |
| /* |
| * Fix for Bug# 63297 When the palette gets focus, the LWS will take |
| * care of setting focus on the correct figure. However, when the user |
| * clicks on an entry, the focus is "thrown away." In that case, the LWS |
| * would set focus on the first focusable figure. We override that here |
| * and set focus on the correct/selected figure. Invoking |
| * getFocusEditPart().setFocus(true) does not work because that editpart |
| * thinks it already has focus (it's not aware of focus being thrown |
| * away) and does nothing. |
| */ |
| if (focusPart == null) { |
| IFigure fig = ((GraphicalEditPart) getFocusEditPart()).getFigure(); |
| fig.internalGetEventDispatcher().requestFocus(fig); |
| } |
| } |
| |
| /** |
| * @see org.eclipse.gef.ui.parts.GraphicalViewerImpl#hookControl() |
| */ |
| protected void hookControl() { |
| super.hookControl(); |
| FigureCanvas canvas = getFigureCanvas(); |
| canvas.getViewport().setContentsTracksWidth(true); |
| canvas.getViewport().setContentsTracksHeight(!globalScrollbar); |
| canvas.setHorizontalScrollBarVisibility(FigureCanvas.NEVER); |
| canvas.setVerticalScrollBarVisibility(globalScrollbar ? FigureCanvas.ALWAYS |
| : FigureCanvas.AUTOMATIC); |
| if (prefs != null) |
| prefs.addPropertyChangeListener(prefListener); |
| updateFont(); |
| } |
| |
| /** |
| * Returns true if the given PaletteDrawer is expanded |
| * |
| * @param drawer |
| * the PaletteDrawer |
| * @return true if expanded |
| */ |
| public boolean isExpanded(PaletteDrawer drawer) { |
| EditPart ep = (EditPart) getEditPartRegistry().get(drawer); |
| if (ep instanceof DrawerEditPart) |
| return ((DrawerEditPart) ep).isExpanded(); |
| return false; |
| } |
| |
| /** |
| * Returns true if the given PaletteDrawer is pinned |
| * |
| * @param drawer |
| * the PaletteDrawer |
| * @return true if pinned |
| */ |
| public boolean isPinned(PaletteDrawer drawer) { |
| EditPart ep = (EditPart) getEditPartRegistry().get(drawer); |
| if (ep instanceof DrawerEditPart) |
| return ((DrawerEditPart) ep).isPinnedOpen(); |
| return false; |
| } |
| |
| /** |
| * The given PaletteListener will not be notified of active tool changes in |
| * the palette. |
| * |
| * @param paletteListener |
| * the PaletteListener which doesn't want to be notified of |
| * active tool changes in the palette anymore |
| */ |
| public void removePaletteListener(PaletteListener paletteListener) { |
| paletteListeners.remove(paletteListener); |
| } |
| |
| /** |
| * Tries to apply the state of the given IMemento to the contents of this |
| * viewer. It fails silently, i.e. no exceptions are thrown if the given |
| * state could not be applied. |
| * |
| * @param memento |
| * The memento that has the state to be applied to the contents |
| * of this viewer |
| * @return a boolean indicating whether or not the given memento was |
| * successfully applied |
| * @since 3.0 |
| */ |
| public boolean restoreState(IMemento memento) { |
| try { |
| PaletteEditPart part = (PaletteEditPart) getEditPartRegistry().get( |
| getPaletteRoot()); |
| if (part != null) |
| part.restoreState(memento); |
| } catch (RuntimeException re) { |
| /* |
| * @TODO:Pratik Perhaps you should log this exception. Or not catch |
| * it at all. |
| */ |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * @see ScrollingGraphicalViewer#reveal(EditPart) |
| */ |
| public void reveal(EditPart part) { |
| // If the given part is a drawer, we don't need to expand it. Hence, |
| // when invoking |
| // findContainingDrawer(), we use part.getParent() |
| DrawerEditPart drawer = findContainingDrawer(part.getParent()); |
| if (drawer != null && !drawer.isExpanded()) |
| drawer.setExpanded(true); |
| // if the part is inside a stack, set it to be the top level item of the |
| // stack. |
| if (part.getParent() != null |
| && part.getParent() instanceof PaletteStackEditPart) |
| ((PaletteStack) part.getParent().getModel()) |
| .setActiveEntry((PaletteEntry) part.getModel()); |
| super.reveal(part); |
| } |
| |
| /** |
| * Captures the state of the contents of this viewer in the given memento |
| * |
| * @param memento |
| * the IMemento in which the state is to be saved |
| * @since 3.0 |
| */ |
| public void saveState(IMemento memento) { |
| // Bug# 69026 - The PaletteRoot can be null initially for VEP |
| PaletteEditPart base = (PaletteEditPart) getEditPartRegistry().get( |
| getPaletteRoot()); |
| if (base != null) |
| base.saveState(memento); |
| } |
| |
| /** |
| * Sets the customizer. |
| * |
| * @param customizer |
| * the customizer to be set |
| */ |
| public void setCustomizer(PaletteCustomizer customizer) { |
| this.customizer = customizer; |
| } |
| |
| /** |
| * Sets the active entry for this palette. The Editpart for the given entry |
| * will be activated (selected). |
| * |
| * @param newMode |
| * the ToolEntry whose EditPart has to be set as the active tool |
| * in this palette |
| */ |
| public void setActiveTool(ToolEntry newMode) { |
| if (newMode == null) |
| newMode = getPaletteRoot().getDefaultEntry(); |
| if (activeEntry != null) |
| getToolEntryEditPart(activeEntry).setToolSelected(false); |
| activeEntry = newMode; |
| if (activeEntry != null) { |
| ToolEntryEditPart editpart = getToolEntryEditPart(activeEntry); |
| if (editpart != null) { |
| editpart.setToolSelected(true); |
| } |
| } |
| fireModeChanged(); |
| } |
| |
| /** |
| * Sets the root for this palette. |
| * |
| * @param root |
| * the PaletteRoot for this palette |
| */ |
| public void setPaletteRoot(PaletteRoot root) { |
| if (root == paletteRoot) |
| return; |
| paletteRoot = root; |
| if (paletteRoot != null) { |
| EditPart palette = getEditPartFactory().createEditPart( |
| getRootEditPart(), root); |
| getRootEditPart().setContents(palette); |
| } |
| } |
| |
| /** |
| * This palette will use the given PaletteViewerPreferences to store all its |
| * preferences. |
| * <p> |
| * NOTE: This method should be invoked by a client only once (before the |
| * first time {@link #getPaletteViewerPreferences()} is invoked). Trying to |
| * invoke this method after that could lead to problems where some |
| * preferences would still be stored in the old preference store. |
| * </p> |
| * |
| * @param prefs |
| * the PaletteViewerPreferences that is to be used to store all |
| * the preferences for this palette |
| */ |
| public void setPaletteViewerPreferences(PaletteViewerPreferences prefs) { |
| if (this.prefs != null) |
| this.prefs.removePropertyChangeListener(prefListener); |
| this.prefs = prefs; |
| if (getControl() != null && !getControl().isDisposed()) |
| this.prefs.addPropertyChangeListener(prefListener); |
| } |
| |
| /** |
| * @see org.eclipse.gef.ui.parts.AbstractEditPartViewer#unhookControl() |
| */ |
| protected void unhookControl() { |
| super.unhookControl(); |
| disposeFont(); |
| if (prefs != null) |
| prefs.removePropertyChangeListener(prefListener); |
| } |
| |
| private void updateFont() { |
| disposeFont(); |
| |
| if (getControl() == null || getControl().isDisposed()) |
| return; |
| |
| font = new Font(Display.getCurrent(), getPaletteViewerPreferences() |
| .getFontData()); |
| getControl().setFont(font); |
| getFigureCanvas().getViewport().invalidateTree(); |
| getFigureCanvas().getViewport().revalidate(); |
| getFigureCanvas().redraw(); |
| } |
| |
| } |