blob: 37569e2fabf26b57ab8c2513378af1148a0d7522 [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.editparts;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.IMemento;
import org.eclipse.draw2d.Border;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.MarginBorder;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.text.FlowPage;
import org.eclipse.draw2d.text.TextFlow;
import org.eclipse.gef.AccessibleEditPart;
import org.eclipse.gef.DragTracker;
import org.eclipse.gef.Request;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.gef.palette.PaletteContainer;
import org.eclipse.gef.palette.PaletteEntry;
import org.eclipse.gef.palette.PaletteSeparator;
import org.eclipse.gef.tools.SelectEditPartTracker;
import org.eclipse.gef.ui.palette.PaletteMessages;
import org.eclipse.gef.ui.palette.PaletteViewer;
import org.eclipse.gef.ui.palette.PaletteViewerPreferences;
/**
* The abstract implementation of palette edit parts. All edit parts used in the
* palette must extend this class.
*/
public abstract class PaletteEditPart extends AbstractGraphicalEditPart
implements PropertyChangeListener {
/**
* The name of each entry in the palette, used to restore the state.
*/
public static final String XML_NAME = "entry"; //$NON-NLS-1$
private static final Border TOOLTIP_BORDER = new MarginBorder(0, 2, 1, 0);
private ImageCache globalImageCache;
private AccessibleEditPart acc;
private PropertyChangeListener childListener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(PaletteEntry.PROPERTY_VISIBLE)) {
refreshChildren();
}
}
};
private Image image;
private ImageDescriptor imgDescriptor;
/**
* Constructor for the PaletteEditPart.
*
* @param model
* The model element for this edit part.
*/
public PaletteEditPart(PaletteEntry model) {
setModel(model);
}
/**
* @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#activate()
*/
public void activate() {
super.activate();
PaletteEntry model = (PaletteEntry) getModel();
model.addPropertyChangeListener(this);
traverseChildren(model, true);
}
/**
* returns the AccessibleEditPart for this EditPart. This method is called
* lazily from {@link #getAccessibleEditPart()}.
*
* @return the AccessibleEditPart.
*/
protected AccessibleEditPart createAccessible() {
return null;
}
/**
* @see org.eclipse.gef.editparts.AbstractEditPart#createEditPolicies()
*/
public void createEditPolicies() {
}
/**
* Create the tool tip for this palette edit part.
*
* @return the tool tip figure.
*/
protected IFigure createToolTip() {
String message = getToolTipText();
if (message == null || message.length() == 0)
return null;
FlowPage fp = new FlowPage() {
public Dimension getPreferredSize(int w, int h) {
Dimension d = super.getPreferredSize(-1, -1);
if (d.width > 150)
d = super.getPreferredSize(150, -1);
return d;
}
};
fp.setOpaque(true);
fp.setBorder(TOOLTIP_BORDER);
TextFlow tf = new TextFlow();
tf.setText(message);
fp.add(tf);
return fp;
}
/**
* @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#deactivate()
*/
public void deactivate() {
PaletteEntry model = (PaletteEntry) getModel();
model.removePropertyChangeListener(this);
traverseChildren(model, false);
if (image != null) {
image.dispose();
image = null;
}
super.deactivate();
}
/**
* @see org.eclipse.gef.editparts.AbstractEditPart#getAccessibleEditPart()
*/
protected AccessibleEditPart getAccessibleEditPart() {
if (acc == null)
acc = createAccessible();
return acc;
}
/**
* A selection tracker for the edit part.
*/
public class SingleSelectionTracker extends SelectEditPartTracker {
/**
* Constructor for a SingleSelectionTracker.
*/
public SingleSelectionTracker() {
super(PaletteEditPart.this);
}
/**
* @see org.eclipse.gef.tools.SelectEditPartTracker#performSelection()
*/
protected void performSelection() {
if (hasSelectionOccurred())
return;
setFlag(FLAG_SELECTION_PERFORMED, true);
getCurrentViewer().select(getSourceEditPart());
}
}
/**
* @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#getDragTracker(Request)
*/
public DragTracker getDragTracker(Request request) {
return new SingleSelectionTracker();
}
/**
* Returns the image cache. The cache is global, and is shared by all
* palette edit parts. This has the disadvantage that once an image is
* allocated, it is never freed until the display is disposed. However, it
* has the advantage that the same image in different palettes is only ever
* created once.
*
* @return the image cache.
*/
protected ImageCache getImageCache() {
ImageCache cache = globalImageCache;
if (cache == null) {
globalImageCache = cache = new ImageCache();
Display display = Display.getDefault();
if (display != null) {
display.disposeExec(new Runnable() {
public void run() {
if (globalImageCache != null) {
globalImageCache.dispose();
globalImageCache = null;
}
}
});
}
}
return cache;
}
/**
* @see org.eclipse.gef.editparts.AbstractEditPart#getModelChildren()
*/
public List getModelChildren() {
List modelChildren;
if (getModel() instanceof PaletteContainer)
modelChildren = new ArrayList(
((PaletteContainer) getModel()).getChildren());
else
return Collections.EMPTY_LIST;
PaletteEntry prevVisibleEntry = null;
for (Iterator iter = modelChildren.iterator(); iter.hasNext();) {
PaletteEntry entry = (PaletteEntry) iter.next();
if (!entry.isVisible())
// not visible
iter.remove();
else if (entry instanceof PaletteSeparator
&& prevVisibleEntry == null)
// first visible item in a group is a separator, don't need it
iter.remove();
else if (entry instanceof PaletteSeparator
&& prevVisibleEntry instanceof PaletteSeparator)
// previous visible entry was a separator, don't need it
iter.remove();
else
prevVisibleEntry = entry;
}
// check to see if last visible entry was a separator, and thus should
// be hidden
if (prevVisibleEntry instanceof PaletteSeparator)
modelChildren.remove(prevVisibleEntry);
return modelChildren;
}
/**
* Get the model element for this palette edit part.
*
* @return the model element.
*/
protected PaletteEntry getPaletteEntry() {
return (PaletteEntry) getModel();
}
/**
* Get the palette viewer for this palette edit part.
*
* @return the palette viewer.
*/
protected PaletteViewer getPaletteViewer() {
return (PaletteViewer) getViewer();
}
/**
* Get the palette viewer preferences for this palette edit part.
*
* @return the palette viewer preferences.
*/
protected PaletteViewerPreferences getPreferenceSource() {
return ((PaletteViewer) getViewer()).getPaletteViewerPreferences();
}
/**
* Get the tool tip figure for this palette edit part.
*
* @return the tool tip figure.
*/
protected IFigure getToolTipFigure() {
return getFigure();
}
/**
* Get the tool tip text for this palette edit part.
*
* @return the tool tip text.
*/
protected String getToolTipText() {
String text = null;
PaletteEntry entry = (PaletteEntry) getModel();
String desc = entry.getDescription();
boolean needName = nameNeededInToolTip();
if (desc == null || desc.trim().equals(entry.getLabel())
|| desc.trim().equals("")) { //$NON-NLS-1$
if (needName)
text = entry.getLabel();
} else {
if (needName)
text = entry.getLabel() + " " //$NON-NLS-1$
+ PaletteMessages.get().NAME_DESCRIPTION_SEPARATOR + " " //$NON-NLS-1$
+ desc;
else
text = desc;
}
if (text != null && text.trim().equals(""))//$NON-NLS-1$
return null;
return text;
}
// /**
// * Overwritten because palette edit parts are not bound to the constraint
// * that their figure has to be visible (they may get selected while being
// * stacked).
// *
// * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#isSelectable()
// */
// public boolean isSelectable() {
// return true;
// }
/**
* Determine if the name is needed in the tool tip.
*
* @return <code>true</code> if the name is needed in the tool tip.
* @since 3.2
*/
protected boolean nameNeededInToolTip() {
return getLayoutSetting() == PaletteViewerPreferences.LAYOUT_ICONS;
}
/**
* @see java.beans.PropertyChangeListener#propertyChange(PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent evt) {
String property = evt.getPropertyName();
if (property.equals(PaletteContainer.PROPERTY_CHILDREN)) {
traverseChildren((List) evt.getOldValue(), false);
refreshChildren();
traverseChildren((List) evt.getNewValue(), true);
} else if (property.equals(PaletteEntry.PROPERTY_LABEL)
|| property.equals(PaletteEntry.PROPERTY_SMALL_ICON)
|| property.equals(PaletteEntry.PROPERTY_LARGE_ICON)
|| property.equals(PaletteEntry.PROPERTY_DESCRIPTION))
refreshVisuals();
}
/**
* Restore the state of the palette entry.
*
* @param memento
* the saved state of the palette entry.
*/
public void restoreState(IMemento memento) {
Iterator iter = getChildren().iterator();
IMemento[] childMementos = memento.getChildren(XML_NAME);
int index = 0;
while (iter.hasNext())
((PaletteEditPart) iter.next())
.restoreState(childMementos[index++]);
}
/**
* Save the state of the palette entry.
*
* @param memento
* the saved state of the palette entry.
*/
public void saveState(IMemento memento) {
Iterator iter = getChildren().iterator();
while (iter.hasNext())
((PaletteEditPart) iter.next())
.saveState(memento.createChild(XML_NAME));
}
/**
* Set the image for this palette edit part.
*
* @param desc
* the image descriptor.
*/
protected void setImageDescriptor(ImageDescriptor desc) {
if (desc == imgDescriptor)
return;
imgDescriptor = desc;
setImageInFigure(getImageCache().getImage(imgDescriptor));
}
/**
* Set the image to be used in the figure for this edit edit.
*
* @param image
* the image
*/
protected void setImageInFigure(Image image) {
}
private void traverseChildren(PaletteEntry parent, boolean add) {
if (!(parent instanceof PaletteContainer))
return;
PaletteContainer container = (PaletteContainer) parent;
traverseChildren(container.getChildren(), add);
}
private void traverseChildren(List children, boolean add) {
for (Iterator iter = children.iterator(); iter.hasNext();) {
PaletteEntry entry = (PaletteEntry) iter.next();
if (add) {
entry.addPropertyChangeListener(childListener);
} else {
entry.removePropertyChangeListener(childListener);
}
}
}
/**
* The image cache for this edit part.
*/
protected static class ImageCache {
/** Map from ImageDescriptor to Image */
private Map images = new HashMap(11);
Image getImage(ImageDescriptor desc) {
if (desc == null) {
return null;
}
Image img = null;
Object obj = images.get(desc);
if (obj != null) {
img = (Image) obj;
} else {
img = desc.createImage();
images.put(desc, img);
}
return img;
}
Image getMissingImage() {
return getImage(ImageDescriptor.getMissingImageDescriptor());
}
void dispose() {
for (Iterator i = images.values().iterator(); i.hasNext();) {
Image img = (Image) i.next();
img.dispose();
}
images.clear();
}
}
/**
* Returns the current layout setting.
*
* @return the current layout setting.
* @see PaletteViewerPreferences#getLayoutSetting()
* @since 3.4
*/
protected int getLayoutSetting() {
if (getParent() instanceof PaletteEditPart) {
return ((PaletteEditPart) getParent()).getLayoutSetting();
}
return getPreferenceSource().getLayoutSetting();
}
/**
* Overwritten to ensure palette entries are always selectable, even if
* their figure is not showing).
*
* @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#isSelectable()
*/
public boolean isSelectable() {
// bug #349124
return true;
}
/**
* Returns true if this item is on the palette toolbar.
*
* @return true if this item is on the palette toolbar; false otherwise
* @since 3.4
*/
public boolean isToolbarItem() {
if (getParent() instanceof PaletteEditPart) {
return ((PaletteEditPart) getParent()).isToolbarItem();
}
return false;
}
}