/******************************************************************************* * Copyright (c) 2000, 2009 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(); } }