/******************************************************************************* * 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(); } }