| /****************************************************************************** |
| * 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.gmf.runtime.diagram.ui.figures; |
| import java.util.List; |
| |
| import org.eclipse.draw2d.Figure; |
| import org.eclipse.draw2d.FreeformLayout; |
| import org.eclipse.draw2d.Graphics; |
| import org.eclipse.draw2d.IFigure; |
| import org.eclipse.draw2d.Label; |
| import org.eclipse.draw2d.LayoutManager; |
| import org.eclipse.draw2d.MarginBorder; |
| import org.eclipse.draw2d.PositionConstants; |
| import org.eclipse.draw2d.ScrollPane; |
| import org.eclipse.draw2d.geometry.Dimension; |
| import org.eclipse.draw2d.geometry.Point; |
| import org.eclipse.gmf.runtime.draw2d.ui.figures.ConstrainedToolbarLayout; |
| import org.eclipse.gmf.runtime.draw2d.ui.figures.OneLineBorder; |
| import org.eclipse.gmf.runtime.draw2d.ui.figures.WrappingLabel; |
| import org.eclipse.gmf.runtime.draw2d.ui.internal.figures.AnimatableScrollPane; |
| import org.eclipse.gmf.runtime.draw2d.ui.internal.figures.OverlayScrollPaneLayout; |
| import org.eclipse.gmf.runtime.draw2d.ui.mapmode.IMapMode; |
| import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil; |
| import org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.Font; |
| |
| |
| /** |
| * A figure to represent the resizable compartment There are two constructors |
| * available The one that takes a String:title consists of two childen: title |
| * label + animatable scroll pane. The other one just consists of an animatable |
| * scroll pane. |
| * |
| * <p> |
| * Code taken from Eclipse reference bugzilla #98820 |
| * |
| * @author melaasar |
| * @author choang |
| */ |
| /** |
| * @author Steve |
| * |
| */ |
| public class ResizableCompartmentFigure extends NodeFigure { |
| |
| private final static int FLAG__FIT_CONTENTS = MAX_FLAG << 1; |
| |
| /** |
| * @since 1.3 |
| */ |
| protected final static int FRAME_MAX_FLAG = FLAG__FIT_CONTENTS; |
| |
| private boolean _horizontal = false; |
| |
| /** |
| * The pane for all text compartment including the title |
| */ |
| private Figure textPane = null; |
| /** |
| * The compartment title label |
| */ |
| private WrappingLabel titleLabel; |
| |
| /** |
| * the minimum size the client area can occupy in logical coordinates |
| */ |
| private int minClientSize = 0; |
| |
| /** |
| * The compartment scroll pane |
| */ |
| protected ScrollPane scrollPane; |
| /** |
| * The selected state |
| */ |
| private boolean selected; |
| |
| /** |
| * Indicates if the scroll pane has been initialized. |
| */ |
| private boolean isScrollPaneInitialized = false; |
| |
| /** |
| * Specifies the default minimum client size of this figure in device coordinates. |
| * Clients should use their editors <code>IMapMode</code> to convert this to logical |
| * coordinates. |
| */ |
| public static final int MIN_CLIENT_DP = 11; |
| |
| /** |
| * A constructor for a top level resizable compartment figure |
| * |
| * @param compartmentTitle <code>String</code> that is the title that is |
| * displayed at the top of the compartment figure (optional). |
| * @param mm the <code>IMapMode</code> that is used to initialize the |
| * default values of of the scrollpane contained inside the figure. This is |
| * necessary since the figure is not attached at construction time and consequently |
| * can't get access to the owned IMapMode in the parent containment hierarchy. |
| */ |
| public ResizableCompartmentFigure(String compartmentTitle, IMapMode mm) { |
| this.minClientSize = mm.DPtoLP(MIN_CLIENT_DP); |
| setTextPane(new Figure() { |
| public Dimension getMaximumSize() { |
| return getPreferredSize(); |
| } |
| }); |
| getTextPane().setLayoutManager(new ConstrainedToolbarLayout()); |
| add(getTextPane()); |
| add(scrollPane = createScrollPane(mm)); |
| setLayoutManager(new ConstrainedToolbarLayout()); |
| setTitle(compartmentTitle); |
| setToolTip(compartmentTitle); |
| setBorder(new OneLineBorder(mm.DPtoLP(1), PositionConstants.TOP)); |
| } |
| |
| /** |
| * Creates the animatable scroll pane |
| * |
| * @return <code>AnimatableScrollPane</code> |
| * @deprecated use {@link ResizableCompartmentFigure#createScrollPane(IMapMode)} instead |
| */ |
| protected AnimatableScrollPane createScrollpane() { |
| return createScrollpane(MapModeUtil.getMapMode(this)); |
| } |
| |
| /** |
| * Creates the animatable scroll pane |
| * |
| * @param mm the <code>IMapMode</code> that is used to initialize the |
| * default values of of the scrollpane contained inside the figure. This is |
| * necessary since the figure is not attached at construction time and consequently |
| * can't get access to the owned IMapMode in the parent containment hierarchy. |
| * @return <code>AnimatableScrollPane</code> |
| * @deprecated use {@link ResizableCompartmentFigure#createScrollPane(IMapMode)} instead |
| */ |
| protected AnimatableScrollPane createScrollpane(IMapMode mm) { |
| scrollPane = new AnimatableScrollPane(); |
| scrollPane.getViewport().setContentsTracksWidth(true); |
| scrollPane.getViewport().setContentsTracksHeight(false); |
| scrollPane.setLayoutManager(new OverlayScrollPaneLayout()); |
| scrollPane.setVerticalScrollBarVisibility(ScrollPane.AUTOMATIC); |
| scrollPane.setHorizontalScrollBarVisibility(ScrollPane.NEVER); |
| scrollPane.setContents(new Figure()); |
| int half_minClient = getMinClientSize()/2; |
| scrollPane.getContents().setBorder( |
| new MarginBorder(1, half_minClient, 1, half_minClient)); |
| return (AnimatableScrollPane)scrollPane; |
| } |
| |
| /** |
| * Creates the animatable scroll pane |
| * |
| * @param mm the <code>IMapMode</code> that is used to initialize the |
| * default values of of the scrollpane contained inside the figure. This is |
| * necessary since the figure is not attached at construction time and consequently |
| * can't get access to the owned IMapMode in the parent containment hierarchy. |
| * @return <code>ScrollPane</code> |
| */ |
| protected ScrollPane createScrollPane(IMapMode mm) { |
| return createScrollpane(mm); |
| } |
| |
| /** |
| * @return that is the minimum size the client area can occupy in |
| * logical coordinates. |
| */ |
| final protected int getMinClientSize() { |
| return minClientSize; |
| } |
| |
| /** |
| * Sets the compartment title visibility |
| * |
| * @param visibility |
| */ |
| public void setTitleVisibility(boolean visibility) { |
| getTextPane().setVisible(visibility); |
| } |
| /** |
| * Expands the compartment figure |
| */ |
| public void expand() { |
| scrollPane.getViewport().setVisible(true); |
| scrollPane.setHorizontalScrollBarVisibility(ScrollPane.AUTOMATIC); |
| scrollPane.setVerticalScrollBarVisibility(ScrollPane.AUTOMATIC); |
| if (scrollPane instanceof AnimatableScrollPane) { |
| ((AnimatableScrollPane)scrollPane).expand(); |
| } |
| } |
| /** |
| * Collapses the compartment figure |
| */ |
| public void collapse() { |
| scrollPane.setVerticalScrollBarVisibility(ScrollPane.NEVER); |
| scrollPane.setHorizontalScrollBarVisibility(ScrollPane.NEVER); |
| if (scrollPane instanceof AnimatableScrollPane) { |
| ((AnimatableScrollPane)scrollPane).collapse(); |
| } |
| scrollPane.getViewport().setVisible(false); |
| } |
| /** |
| * Expands the compartment figure |
| */ |
| public void setExpanded() { |
| scrollPane.getViewport().setVisible(true); |
| if (scrollPane instanceof AnimatableScrollPane) { |
| ((AnimatableScrollPane)scrollPane).setExpanded(true); |
| } |
| scrollPane.setHorizontalScrollBarVisibility(ScrollPane.AUTOMATIC); |
| scrollPane.setVerticalScrollBarVisibility(ScrollPane.AUTOMATIC); |
| } |
| /** |
| * Collapses the compartment figure |
| */ |
| public void setCollapsed() { |
| scrollPane.setVerticalScrollBarVisibility(ScrollPane.NEVER); |
| scrollPane.setHorizontalScrollBarVisibility(ScrollPane.NEVER); |
| if (scrollPane instanceof AnimatableScrollPane) { |
| ((AnimatableScrollPane)scrollPane).setExpanded(false); |
| } |
| scrollPane.getViewport().setVisible(false); |
| } |
| |
| /** |
| * @return The contents pane of this compartment figure |
| */ |
| public IFigure getContentPane() { |
| return scrollPane.getContents(); |
| } |
| |
| |
| public void setFont(Font f) { |
| textPane.setFont(f); |
| } |
| /** |
| * Sets the font color of the compartment title label |
| * |
| * @param c |
| * The new color |
| */ |
| public void setFontColor(Color c) { |
| textPane.setForegroundColor(c); |
| } |
| |
| /** |
| * Set the compartment title to the supplied text. |
| * @param title this figure title |
| */ |
| public void setTitle(String title) { |
| if (title == null) { |
| if (titleLabel != null) |
| getTextPane().remove(titleLabel); |
| } else if (titleLabel == null) { |
| getTextPane().add(titleLabel = new WrappingLabel(title)); |
| } else |
| titleLabel.setText(title); |
| } |
| |
| /** |
| * Set the tooltip to the supplied text. |
| * @param tooltip this figure tooltip |
| */ |
| public void setToolTip(String tooltip) { |
| if (tooltip == null) |
| setToolTip((IFigure) null); |
| else if (getToolTip() instanceof Label) |
| ((Label) getToolTip()).setText(tooltip); |
| else |
| setToolTip(new Label(tooltip)); |
| } |
| |
| /** |
| * scrollpane accessor |
| * |
| * @return the scrollpane figure. |
| */ |
| public final ScrollPane getScrollPane() { |
| return scrollPane; |
| } |
| |
| /** |
| * Accessor for the expanded property |
| * |
| * @return boolean expanded |
| */ |
| public final boolean isExpanded() { |
| if (scrollPane instanceof AnimatableScrollPane) { |
| return ((AnimatableScrollPane)scrollPane).isExpanded(); |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Return this figure's compartment title. |
| * @return <code>String</code> |
| */ |
| public final String getCompartmentTitle() { |
| return titleLabel == null ? null : titleLabel.getText(); |
| } |
| |
| /** |
| * Gets the adjacent visible sibling before (or after) the figure |
| * @param before flag to identify the before or after, <code>true</code> |
| * means before, <code>false</code> means after |
| * @return <code>IFigure</code> |
| */ |
| public final IFigure getAdjacentSibling(boolean before) { |
| List siblings = getParent().getChildren(); |
| int index = siblings.indexOf(this); |
| if (before) { |
| for (int i = index - 1; i >= 0; i--) { |
| IFigure sibling = (IFigure) siblings.get(i); |
| if (sibling instanceof ResizableCompartmentFigure |
| && sibling.isVisible()) |
| return sibling; |
| } |
| } else { |
| for (int i = index + 1; i < siblings.size(); i++) { |
| IFigure sibling = (IFigure) siblings.get(i); |
| if (sibling instanceof ResizableCompartmentFigure |
| && sibling.isVisible()) |
| return sibling; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Sets the selection state of this label |
| * |
| * @param b |
| * true will cause the label to appear selected |
| */ |
| public void setSelected(boolean b) { |
| if (this.selected == b) |
| return; |
| selected = b; |
| repaint(); |
| } |
| |
| /** |
| * @see org.eclipse.draw2d.Figure#paintFigure(org.eclipse.draw2d.Graphics) |
| */ |
| protected void paintFigure(Graphics graphics) { |
| super.paintFigure(graphics); |
| if (selected) { |
| graphics.setLineWidth(2); |
| int shrink = MapModeUtil.getMapMode(this).DPtoLP(1); |
| graphics.drawRectangle(getClientArea().shrink(shrink, shrink)); |
| } |
| } |
| |
| /** |
| * @see org.eclipse.draw2d.IFigure#getPreferredSize(int, int) |
| */ |
| public Dimension getPreferredSize(int wHint, int hHint) { |
| Dimension p = super.getPreferredSize(wHint, hHint); |
| return p.getUnioned(minSize != null ? minSize : getMinClientDimension() |
| .getExpanded(getInsets().getWidth(), getInsets().getHeight())); |
| } |
| |
| /** |
| * @return makes sure that we can fit the collapse handles and the |
| * contents of the scroll pane. |
| * @see org.eclipse.draw2d.IFigure#getMinimumSize(int, int) |
| */ |
| public Dimension getMinimumSize(int w, int h) { |
| if (isFitContents()) { |
| return getPreferredSize(w, h); |
| } |
| |
| if (minSize != null) |
| return minSize; |
| |
| minSize = new Dimension(); |
| |
| if (getLayoutManager() != null) { |
| minSize = getLayoutManager().getMinimumSize(this, w, h); |
| } |
| |
| int minHeight = getMinClientDimension().height+getInsets().getHeight(); |
| minSize.height = Math.max(minHeight, minSize.height); |
| if (h >= 0) |
| minSize.height = Math.min(minSize.height, h); |
| |
| int minWidth = getMinClientDimension().width+getInsets().getWidth(); |
| minSize.width = Math.max(minWidth, minSize.width); |
| if (w >= 0) |
| minSize.width = Math.min(minSize.width, w); |
| |
| return minSize; |
| } |
| |
| /** |
| * getter for the horizontal flag |
| * @return the horizontal flag |
| */ |
| public final boolean isHorizontal() { |
| return _horizontal; |
| } |
| |
| /** |
| * setter for the horizontal flag |
| * @param horizontal the new value of the horizontal flag |
| */ |
| public final void setHorizontal(boolean horizontal) { |
| _horizontal = horizontal; |
| } |
| |
| /** |
| * @see org.eclipse.draw2d.IFigure#getMaximumSize() |
| */ |
| public Dimension getMaximumSize() { |
| Dimension d = super.getMaximumSize().getCopy(); |
| if (!isExpanded()) |
| if ( isHorizontal() ) { |
| d.width = getPreferredSize().width; |
| } |
| else { |
| d.height = getPreferredSize().height; |
| } |
| return d; |
| } |
| /** |
| * @see IFigure#invalidate() |
| */ |
| public void invalidate() { |
| prefSize = null; |
| minSize = null; |
| super.invalidate(); |
| } |
| /** |
| * @return Returns the textPane. |
| */ |
| public Figure getTextPane() { |
| return textPane; |
| } |
| /** |
| * @param textPane |
| * The textPane to set. |
| */ |
| private void setTextPane(Figure textPane) { |
| this.textPane = textPane; |
| } |
| |
| /** |
| * For this compartment we need it to be a min size so to fit the |
| * collapse handles and to give the user an area they |
| * can drag and drop into the list compartment |
| * even if there is nothing in the compartment |
| * @return <code>Dimension</code> |
| */ |
| public Dimension getMinClientDimension(){ |
| return new Dimension(getMinClientSize(), getMinClientSize()); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.draw2d.IFigure#validate() |
| */ |
| public void validate() { |
| super.validate(); |
| |
| // Need a place to do this after the child figures have all been |
| // created. |
| initializeScrollPane(); |
| } |
| |
| /** |
| * Initializes the scroll to x and y locations on the scroll pane to |
| * accomodate children figures with negative locations. See RATLC00142157. |
| */ |
| private void initializeScrollPane() { |
| if (!isScrollPaneInitialized) { |
| if (getScrollPane() != null) { |
| Point topLeft = getScrollPane().getContents().getBounds() |
| .getTopLeft(); |
| if (topLeft.x < 0) { |
| getScrollPane().getViewport().getHorizontalRangeModel() |
| .setValue(topLeft.x); |
| } |
| if (topLeft.y < 0) { |
| getScrollPane().getViewport().getVerticalRangeModel() |
| .setValue(topLeft.y); |
| } |
| } |
| isScrollPaneInitialized = true; |
| } |
| } |
| |
| /** |
| * Checks whether the "fit contents" flag is set |
| * @return <code>true</code> if fit contents flag is set |
| * @since 1.3 |
| */ |
| public boolean isFitContents() { |
| return (this.flags & FLAG__FIT_CONTENTS) != 0; |
| } |
| |
| /** |
| * Sets the "fit contents" flag and updates the figure accordingly |
| * @param fitContents |
| * @since 1.3 |
| */ |
| public void setFitContents(boolean fitContents) { |
| if (fitContents != isFitContents()) { |
| LayoutManager lm = getContentPane().getLayoutManager(); |
| if (fitContents) { |
| this.flags |= FLAG__FIT_CONTENTS; |
| if (lm instanceof FreeformLayout) { |
| ((FreeformLayout)lm).setPositiveCoordinates(true); |
| } |
| } else { |
| this.flags &= ~FLAG__FIT_CONTENTS; |
| if (lm instanceof FreeformLayout) { |
| ((FreeformLayout)lm).setPositiveCoordinates(false); |
| } |
| } |
| getContentPane().revalidate(); |
| } |
| } |
| |
| } |