/******************************************************************************* * Copyright (c) 2000, 2008 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 static 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 static 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.NAME_DESCRIPTION_SEPARATOR + " " + desc; //$NON-NLS-1$ else text = desc; } if (text != null && text.trim().equals(""))//$NON-NLS-1$ return null; return text; } /** * 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(); } /** * 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; } }