blob: a9f72640939ddf5b55c038a6dd1411c187722dfb [file] [log] [blame]
/*******************************************************************************
* 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();
}
}