### Eclipse Workspace Patch 1.0
#P org.eclipse.gmf.runtime.draw2d.ui
Index: src/org/eclipse/gmf/runtime/draw2d/ui/figures/WrapLabel.java
===================================================================
RCS file: /cvsroot/technology/org.eclipse.gmf/plugins/org.eclipse.gmf.runtime.draw2d.ui/src/org/eclipse/gmf/runtime/draw2d/ui/figures/WrapLabel.java,v
retrieving revision 1.9.2.3
diff -u -r1.9.2.3 WrapLabel.java
--- src/org/eclipse/gmf/runtime/draw2d/ui/figures/WrapLabel.java 19 Sep 2006 19:09:21 -0000 1.9.2.3
+++ src/org/eclipse/gmf/runtime/draw2d/ui/figures/WrapLabel.java 15 Dec 2006 21:34:22 -0000
@@ -8,1707 +8,127 @@
* Contributors:
* IBM Corporation - initial API and implementation
****************************************************************************/
-
package org.eclipse.gmf.runtime.draw2d.ui.figures;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Map;
-import java.util.WeakHashMap;
-
-import org.eclipse.draw2d.ColorConstants;
-import org.eclipse.draw2d.Figure;
-import org.eclipse.draw2d.FigureUtilities;
-import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.LayoutManager;
-import org.eclipse.draw2d.PositionConstants;
-import org.eclipse.draw2d.geometry.Dimension;
-import org.eclipse.draw2d.geometry.Insets;
-import org.eclipse.draw2d.geometry.Point;
-import org.eclipse.draw2d.geometry.Rectangle;
-
-import org.eclipse.gmf.runtime.draw2d.ui.internal.mapmode.IMapModeHolder;
-import org.eclipse.gmf.runtime.draw2d.ui.mapmode.IMapMode;
-import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil;
-import org.eclipse.swt.graphics.Font;
-import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.Image;
-import com.ibm.icu.text.BreakIterator;
-import com.ibm.icu.util.StringTokenizer;
-
/**
- * An extended label that has the following extra features:
- *
- * 1- It is capable of showing selection and focus feedback (primary or
- * secondary) 2- It is capable of optionally underlining the label's text 3- It
- * is capable of wrapping the label's text at a given width with a given
- * alignment 4- It is capable of supporting multiple label icons (temporary
- * feature)
- *
- * This class was originally deriving off Draw2d's Label
class
- * but with the introduction of the auto-wrapping feature, a copy had to be made
- * overriding was not straightforward. Hopefully, this extended version can be
- * pushed to opensource
+ * This is a legacy wrapper of the originial WrapLabel
+ * for the new LabelWithTextLayout. Since the way the layout
+ * is done in LabelWithTextLayout is different than the way it was
+ * in the original WrapLabel, this class tends to obtain the original
+ * functionality.
* - *
- * Code taken from Eclipse reference bugzilla #98820
- *
- * @author melaasar
+ * @author satif
+ *
*/
public class WrapLabel
- extends Figure
- implements PositionConstants {
-
- private static final String _ellipse = "..."; //$NON-NLS-1$
-
- private static final Dimension EMPTY_DIMENSION = new Dimension(0, 0);
-
- private static final Map mapModeConstantsMap = new WeakHashMap();
-
- private static class MapModeConstants {
-
- private static final int MAX_IMAGE_INFO = 12;
-
- public final WeakReference mapModeRef;
-
- public final int nDPtoLP_3;
-
- public final int nDPtoLP_2;
-
- public final int nDPtoLP_0;
-
- public final Dimension dimension_nDPtoLP_0;
-
- public final WeakHashMap fontToEllipseTextSize = new WeakHashMap();
-
- public final SingleIconInfo[] singleIconInfos = new SingleIconInfo[MAX_IMAGE_INFO];
-
- public MapModeConstants(IMapMode mapMode) {
- this.mapModeRef = new WeakReference(mapMode);
- nDPtoLP_2 = mapMode.DPtoLP(2);
- nDPtoLP_3 = mapMode.DPtoLP(3);
- nDPtoLP_0 = mapMode.DPtoLP(0);
- dimension_nDPtoLP_0 = new Dimension(nDPtoLP_0, nDPtoLP_0);
- }
-
- public Dimension getEllipseTextSize(Font f) {
- Dimension d = (Dimension) fontToEllipseTextSize.get(f);
- if (d == null) {
- IMapMode mapMode = (IMapMode) mapModeRef.get();
- d = FigureUtilities.getTextExtents(_ellipse, f);
- d.height = FigureUtilities.getFontMetrics(f).getHeight();
- d = new Dimension(mapMode.DPtoLP(d.width), mapMode
- .DPtoLP(d.height));
- fontToEllipseTextSize.put(f, d);
- }
- return d;
- }
-
- public SingleIconInfo getSingleIconInfo(Image image) {
- if (image == null) {
- return SingleIconInfo.NULL_INFO;
- }
- SingleIconInfo info;
- for (int i = 0; i < MAX_IMAGE_INFO; ++i) {
- info = singleIconInfos[i];
- if (info == null) {
- info = new SingleIconInfo(image);
- singleIconInfos[i] = info;
- return info;
- }
- if (info.icon == image) {
- return info;
- }
- }
- int index = SingleIconInfo.count % MAX_IMAGE_INFO;
- info = new SingleIconInfo(image);
- singleIconInfos[index] = info;
- return info;
- }
- }
-
- // reserve 1 bit
- private static int FLAG_SELECTED = MAX_FLAG << 1;
-
- private static int FLAG_HASFOCUS = MAX_FLAG << 2;
-
- private static int FLAG_UNDERLINED = MAX_FLAG << 3;
-
- private static int FLAG_STRIKEDTHROUGH = MAX_FLAG << 4;
-
- private static int FLAG_WRAP = MAX_FLAG << 5;
-
- // reserve 3 bits
- private static int FLAG_TEXT_ALIGN = MAX_FLAG << 6;
-
- private static int FLAG_WRAP_ALIGN = MAX_FLAG << 9;
-
- private static int FLAG_ICON_ALIGN = MAX_FLAG << 12;
-
- private static int FLAG_LABEL_ALIGN = MAX_FLAG << 15;
-
- private static int FLAG_TEXT_PLACEMENT = MAX_FLAG << 18;
-
- private MapModeConstants mapModeConstants;
-
- /** the original label's text */
- private String text;
-
- /** the label's text used in painting after applying required styles */
- private String subStringText;
-
- /** the size of text */
- private Dimension textSize;
-
- private Dimension ellipseTextSize;
-
- /** the location of text */
- private Point textLocation;
-
- /** the cached hint used to calculate text size */
- private int cachedPrefSizeHint_width;
-
- private int cachedPrefSizeHint_height;
-
- /** the icon location */
- private Point iconLocation;
-
- private static abstract class IconInfo {
- /**
- * Gets the icon at the index location.
- *
- * @param i
- * the index to retrieve the icon of
- * @return Image
that corresponds to the given index.
- */
- public abstract Image getIcon(int i);
-
- /**
- * Gets the icon size of the icon at the given index.
- *
- * @param i
- * @return the Dimension
that is the size of the icon at
- * the given index.
- */
- public abstract Dimension getIconSize(IMapMode mapMode, int i);
-
- /**
- * @return the number of icons
- */
- public abstract int getNumberofIcons();
-
- /**
- * @return the Dimension
that is the total size of all
- * the icons.
- */
- public abstract Dimension getTotalIconSize(IMapMode mapMode);
-
- public abstract void invalidate();
-
- /**
- * Sets the icon at the index location.
- *
- * @param icon
- * @param i
- */
- public abstract void setIcon(Image icon, int i);
-
- /**
- *
- */
- public abstract int getMaxIcons();
-
- }
-
- private static class SingleIconInfo
- extends IconInfo {
-
- static int count;
-
- public static final SingleIconInfo NULL_INFO = new SingleIconInfo(){
- public int getNumberofIcons() {
- return 0;
- }
- };
-
- final Image icon;
-
- /** total icon size */
- private Dimension totalIconSize;
-
- private SingleIconInfo() {
- icon = null;//don't increment count, used only for NULL_INFO
- }
-
- public SingleIconInfo(Image icon) {
- this.icon = icon;
- ++count;
- }
-
- public final int getMaxIcons() {
- return 1;
- }
-
-
- public Image getIcon(int i) {
- if (i == 0) {
- return icon;
- } else if (i > 0) {
- return null;
- }
- throw new IndexOutOfBoundsException();
- }
-
-
- public void setIcon(Image img, int i) {
- throw new UnsupportedOperationException();
- }
-
-
- public Dimension getIconSize(IMapMode mapMode, int i) {
- if (i == 0) {
- return getTotalIconSize(mapMode);
- }
-
- throw new IndexOutOfBoundsException();
- }
-
-
- public int getNumberofIcons() {
- return 1;
- }
-
-
- public Dimension getTotalIconSize(IMapMode mapMode) {
- if (totalIconSize != null)
- return totalIconSize;
-
- if (icon != null && !icon.isDisposed()) {
- org.eclipse.swt.graphics.Rectangle imgBounds = icon.getBounds();
- totalIconSize = new Dimension(mapMode.DPtoLP(imgBounds.width),
- mapMode.DPtoLP(imgBounds.height));
- } else {
- totalIconSize = EMPTY_DIMENSION;
- }
-
- return totalIconSize;
- }
-
-
- public void invalidate() {
- totalIconSize = null;
- }
-
- }
-
- private static class MultiIconInfo
- extends IconInfo {
-
- /** the label icons */
- private ArrayList icons = new ArrayList(2);
-
- /** total icon size */
- private Dimension totalIconSize;
-
- public MultiIconInfo() {
- super();
- }
-
- public int getMaxIcons() {
- return -1;
- }
-
- /**
- * Gets the icon at the index location.
- *
- * @param i
- * the index to retrieve the icon of
- * @return Image
that corresponds to the given index.
- */
- public Image getIcon(int i) {
- if (i >= icons.size())
- return null;
-
- return (Image) icons.get(i);
- }
-
- /**
- * Sets the icon at the index location.
- *
- * @param icon
- * @param i
- */
- public void setIcon(Image icon, int i) {
- int size = icons.size();
- if (i >= size) {
- for (int j = size; j < i; j++)
- icons.add(null);
- icons.add(icon);
- icons.trimToSize();
- } else
- icons.set(i, icon);
- }
-
- /**
- * Gets the icon size of the icon at the given index.
- *
- * @param i
- * @return the Dimension
that is the size of the icon at
- * the given index.
- */
- public Dimension getIconSize(IMapMode mapMode, int i) {
- Image img = getIcon(i);
- if (img != null && !img.isDisposed()) {
- org.eclipse.swt.graphics.Rectangle imgBounds = img.getBounds();
- return new Dimension(mapMode.DPtoLP(imgBounds.width), mapMode
- .DPtoLP(imgBounds.height));
- }
- return EMPTY_DIMENSION;
- }
-
- /**
- * @return the number of icons
- */
- public int getNumberofIcons() {
- return icons.size();
- }
-
- /**
- * @return the Dimension
that is the total size of all
- * the icons.
- */
- public Dimension getTotalIconSize(IMapMode mapMode) {
- if (totalIconSize != null)
- return totalIconSize;
- int iconNum = getNumberofIcons();
- if (iconNum == 0) {
- return totalIconSize = EMPTY_DIMENSION;
- }
-
- totalIconSize = new Dimension();
- for (int i = 0; i < iconNum; i++) {
- Dimension iconSize = getIconSize(mapMode, i);
- totalIconSize.width += iconSize.width;
- if (iconSize.height > totalIconSize.height)
- totalIconSize.height = iconSize.height;
- }
-
- return totalIconSize;
- }
-
- /**
- *
- */
- public void invalidate() {
- totalIconSize = null;
- }
- }
-
- private IconInfo iconInfo;
-
- /** the cached hint used to calculate text size */
- private int cachedTextSizeHint_width;
-
- private int cachedTextSizeHint_height;
-
-
-
- /**
- * Construct an empty Label.
- *
- * @since 2.0
- */
- public WrapLabel() {
- text = "";//$NON-NLS-1$
- // set defaults
- setAlignmentFlags(CENTER, FLAG_TEXT_ALIGN);
- setAlignmentFlags(CENTER, FLAG_ICON_ALIGN);
- setAlignmentFlags(CENTER, FLAG_LABEL_ALIGN);
- setAlignmentFlags(LEFT, FLAG_WRAP_ALIGN);
- setPlacementFlags(EAST, FLAG_TEXT_PLACEMENT);
- }
-
- /**
- * Construct a Label with passed String as its text.
- *
- * @param s the label text
- * @since 2.0
- */
- public WrapLabel(String s) {
- if (s != null) {
- text = s;
- } else {
- text = "";//$NON-NLS-1$
- }
-// setBorder(new LineBorderEx(ColorConstants.red,3));
- }
-
- /**
- * Construct a Label with passed Image as its icon.
- *
- * @param i the label image
- * @since 2.0
- */
- public WrapLabel(Image i) {
- text = "";//$NON-NLS-1$
- iconInfo = new SingleIconInfo(i);
- }
-
- /**
- * Construct a Label with passed String as text and passed Image as its
- * icon.
- *
- * @param s the label text
- * @param i the label image
- * @since 2.0
- */
- public WrapLabel(String s, Image i) {
- if (s != null) {
- text = s;
- } else {
- text = "";//$NON-NLS-1$
- }
- iconInfo = new SingleIconInfo(i);
- }
-
- /**
- * @return IMapMode
used by this figure.
- * IMapMode
that allows for the coordinate mapping
- * from device to logical units.
- */
- private IMapMode getMapMode() {
- return (IMapMode) getMapModeConstants().mapModeRef.get();
- }
-
- private MapModeConstants getMapModeConstants() {
- if (mapModeConstants == null) {
- IMapMode mapMode = MapModeUtil.getMapMode(this);
- while (mapMode instanceof IMapModeHolder) {
- mapMode = ((IMapModeHolder) mapMode).getMapMode();
- }
- mapModeConstants = (MapModeConstants) mapModeConstantsMap
- .get(mapMode);
- if (mapModeConstants == null) {
- mapModeConstants = new MapModeConstants(mapMode);
- mapModeConstantsMap.put(mapMode, mapModeConstants);
- }
- }
- return mapModeConstants;
- }
-
- private void alignOnHeight(Point loc, Dimension size, int alignment) {
- switch (alignment) {
- case TOP:
- loc.y = getInsets().top;
- break;
- case BOTTOM:
- loc.y = bounds.height - size.height - getInsets().bottom;
- break;
- default:
- loc.y = (bounds.height - size.height) / 2;
- }
- }
-
- private void alignOnWidth(Point loc, Dimension size, int alignment) {
- switch (alignment) {
- case LEFT:
- loc.x = getInsets().left;
- break;
- case RIGHT:
- loc.x = bounds.width - size.width - getInsets().right;
- break;
- default:
- loc.x = (bounds.width - size.width) / 2;
- }
- }
-
- private void calculateAlignment(Dimension iconSize, int textPlacement) {
- switch (textPlacement) {
- case EAST:
- case WEST:
- alignOnHeight(textLocation, getTextSize(), getTextAlignment());
- alignOnHeight(getIconLocation(), iconSize, getIconAlignment());
- break;
- case NORTH:
- case SOUTH:
- alignOnWidth(textLocation, getSubStringTextSize(),
- getTextAlignment());
- alignOnWidth(getIconLocation(), iconSize, getIconAlignment());
- break;
- }
- }
-
- /**
- * Calculates the size of the Label using the passed Dimension as the size
- * of the Label's text.
- *
- * @param txtSize the precalculated size of the label's text
- * @return the label's size
- * @since 2.0
- */
- protected Dimension calculateLabelSize(Dimension txtSize) {
- Dimension iconSize = getTotalIconSize();
- boolean isEmpty = (iconSize.width == 0 && iconSize.height == 0);
- int len = getText().length();
- if (len == 0 && isEmpty) {
- return new Dimension(txtSize.width, txtSize.height);
- }
- int gap = (len == 0 || isEmpty) ? 0
- : getIconTextGap();
- int placement = getTextPlacement();
- if (placement == WEST || placement == EAST) {
- return new Dimension(iconSize.width + gap + txtSize.width, Math
- .max(iconSize.height, txtSize.height));
- } else {
- return new Dimension(Math.max(iconSize.width, txtSize.width),
- iconSize.height + gap + txtSize.height);
- }
- }
-
- private void calculateLocations() {
- textLocation = new Point();
- iconLocation = new Point();
- Dimension iconSize = getTotalIconSize();
- int textPlacement = getTextPlacement();
- calculatePlacement(iconSize, textPlacement);
- calculateAlignment(iconSize, textPlacement);
- Rectangle r = getBounds();
- Dimension ps = getPreferredSize(r.width, r.height);
- int w = (r.width - ps.width)
- + (getTextSize().width - getSubStringTextSize().width);
- int h = r.height - ps.height;
- if (w == 0 && h == 0) {
- return;
- }
-
- Dimension offset = new Dimension(w, h);
- switch (getLabelAlignment()) {
- case CENTER:
- offset.scale(0.5f);
- break;
- case LEFT:
- offset.scale(0.0f);
- break;
- case RIGHT:
- offset.scale(1.0f);
- break;
- case TOP:
- offset.height = 0;
- offset.scale(0.5f);
- break;
- case BOTTOM:
- offset.height = offset.height * 2;
- offset.scale(0.5f);
- break;
- default:
- offset.scale(0.5f);
- break;
- }
-
- switch (textPlacement) {
- case EAST:
- case WEST:
- offset.height = 0;
- break;
- case NORTH:
- case SOUTH:
- offset.width = 0;
- break;
- }
-
- textLocation.translate(offset);
- iconLocation.translate(offset);
- }
-
- private void calculatePlacement(Dimension iconSize, int textPlacement) {
- int gap = (getText().length() == 0 || (iconSize.width == 0 && iconSize.height == 0)) ? 0
- : getIconTextGap();
- Insets insets = getInsets();
- switch (textPlacement) {
- case EAST:
- iconLocation.x = insets.left;
- textLocation.x = iconSize.width + gap + insets.left;
- break;
- case WEST:
- textLocation.x = insets.left;
- iconLocation.x = getSubStringTextSize().width + gap
- + insets.left;
- break;
- case NORTH:
- textLocation.y = insets.top;
- iconLocation.y = getTextSize().height + gap + insets.top;
- break;
- case SOUTH:
- textLocation.y = iconSize.height + gap + insets.top;
- iconLocation.y = insets.top;
- }
- }
- /**
- * Calculates the size of the Label's text size. The text size calculated
- * takes into consideration if the Label's text is currently truncated. If
- * text size without considering current truncation is desired, use
- * {@link #calculateTextSize(int, int)}.
- *
- * @return the size of the label's text, taking into account truncation
- * @since 2.0
- */
- protected Dimension calculateSubStringTextSize() {
- Font f = getFont();
- return getTextExtents(getSubStringText(), f, getMapMode().DPtoLP(FigureUtilities.getFontMetrics(f).getHeight()));
- }
-
- /**
- * Calculates and returns the size of the Label's text. Note that this
- * Dimension is calculated using the Label's full text, regardless of
- * whether or not its text is currently truncated. If text size considering
- * current truncation is desired, use {@link #calculateSubStringTextSize()}.
- *
- * @param wHint a width hint
- * @param hHint a height hint
- * @return the size of the label's text, ignoring truncation
- * @since 2.0
- */
- protected Dimension calculateTextSize(int wHint, int hHint) {
- Font f = getFont();
- return getTextExtents(getWrappedText(wHint, hHint), f,getMapMode().DPtoLP(FigureUtilities.getFontMetrics(f).getHeight()));
- }
-
- private void clearLocations() {
- iconLocation = textLocation = null;
- }
-
- /**
- * Returns the Label's icon.
- *
- * @return the label icon
- * @since 2.0
- */
- public Image getIcon() {
- return getIcon(0);
- }
-
- /**
- * Gets the label's icon at the given index
- *
- * @param index The icon index
- * @return the Image
that is the icon for the given index.
- */
- public Image getIcon(int index) {
- if (iconInfo == null)
- return null;
- return iconInfo.getIcon(index);
- }
-
- /**
- * Determines if there is any icons by checking if icon size is zeros.
- *
- * @return true if icons are present, false otherwise
- */
- protected boolean hasIcons() {
- return (getNumberofIcons() > 0);
- }
-
- /**
- * Returns the current alignment of the Label's icon. The default is
- * {@link PositionConstants#CENTER}.
- *
- * @return the icon alignment
- * @since 2.0
- */
- public int getIconAlignment() {
- return getAlignment(FLAG_ICON_ALIGN);
- }
-
- /**
- * Returns the bounds of the Label's icon.
- *
- * @return the icon's bounds
- * @since 2.0
- */
- public Rectangle getIconBounds() {
- return new Rectangle(getBounds().getLocation().translate(
- getIconLocation()), getTotalIconSize());
- }
-
- /**
- * Returns the location of the Label's icon relative to the Label.
- *
- * @return the icon's location
- * @since 2.0
- */
- protected Point getIconLocation() {
- if (iconLocation == null)
- calculateLocations();
- return iconLocation;
- }
-
- /**
- * Returns the gap in pixels between the Label's icon and its text.
- *
- * @return the gap
- * @since 2.0
- */
- public int getIconTextGap() {
- return getMapModeConstants().nDPtoLP_3;
- }
-
- /**
- * @see IFigure#getMinimumSize(int, int)
- */
- public Dimension getMinimumSize(int w, int h) {
- if (minSize != null)
- return minSize;
- minSize = new Dimension();
- LayoutManager layoutManager = getLayoutManager();
- if (layoutManager != null)
- minSize.setSize(layoutManager.getMinimumSize(this, w, h));
- Font f = getFont();
- Dimension d = getEllipseTextSize().getIntersected(
- getTextExtents(getText(), f, getMapMode().DPtoLP(FigureUtilities.getFontMetrics(f).getHeight())));
-
- Dimension labelSize = calculateLabelSize(d);
- Insets insets = getInsets();
- labelSize.expand(insets.getWidth(), insets.getHeight());
- minSize.union(labelSize);
- return minSize;
- }
-
- /*
- * (non-Javadoc)
- * @see org.eclipse.draw2d.IFigure#getPreferredSize(int, int)
- */
- public Dimension getPreferredSize(int wHint, int hHint) {
- if (prefSize == null || wHint != cachedPrefSizeHint_width || hHint != cachedPrefSizeHint_height) {
- prefSize = calculateLabelSize(getTextSize(wHint, hHint));
- Insets insets = getInsets();
- prefSize.expand(insets.getWidth(), insets.getHeight());
- LayoutManager layoutManager = getLayoutManager();
- if (layoutManager != null) {
- prefSize.union(layoutManager.getPreferredSize(this, wHint,
- hHint));
- }
- prefSize.union(getMinimumSize(wHint, hHint));
- cachedPrefSizeHint_width = wHint;
- cachedPrefSizeHint_height = hHint;
- }
- return prefSize;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.draw2d.IFigure#getMaximumSize()
- */
- public Dimension getMaximumSize() {
- // this assumes that getPreferredSize(wHint, hHint) is called before
- return prefSize;
- }
-
- /**
- * Calculates the amount of the Label's current text will fit in the Label,
- * including an elipsis "..." if truncation is required.
- *
- * @return the substring
- * @since 2.0
- */
- public String getSubStringText() {
- if (subStringText != null)
- return subStringText;
-
- String theText = getText();
- int textLen = theText.length();
- if (textLen == 0) {
- return subStringText = "";//$NON-NLS-1$;;
- }
- Dimension size = getSize();
- Dimension shrink = getPreferredSize(size.width, size.height).getDifference(size);
- Dimension effectiveSize = getTextSize().getExpanded(-shrink.width, -shrink.height);
-
- if (effectiveSize.height == 0) {
- return subStringText = "";//$NON-NLS-1$;
- }
-
- Font f = getFont();
- FontMetrics metrics = FigureUtilities.getFontMetrics(f);
- IMapMode mm = getMapMode();
- int fontHeight = mm.DPtoLP(metrics.getHeight());
- int charAverageWidth = mm.DPtoLP(metrics.getAverageCharWidth());
- int maxLines = (int) (effectiveSize.height / (double) fontHeight);
- if (maxLines == 0) {
- return subStringText = "";//$NON-NLS-1$
- }
-
- StringBuffer accumlatedText = new StringBuffer();
- StringBuffer remainingText = new StringBuffer(theText);
-
- int effectiveSizeWidth = effectiveSize.width;
- int widthHint = Math.max(effectiveSizeWidth
- - getEllipseTextSize().width, 0);
- int i = 0, j = 0;
- while (remainingText.length() > 0 && j++ < maxLines) {
- i = getLineWrapPosition(remainingText.toString(), f, effectiveSizeWidth, fontHeight);
-
- if (accumlatedText.length() > 0)
- accumlatedText.append('\n');
-
- if (i == 0 || (remainingText.length() > i && j == maxLines)) {
- i = getLargestSubstringConfinedTo(remainingText.toString(), f, widthHint, fontHeight, charAverageWidth);
- accumlatedText.append(remainingText.substring(0, i));
- accumlatedText.append(getEllipse());
- } else
- accumlatedText.append(remainingText.substring(0, i));
- remainingText.delete(0, i);
- }
- return subStringText = accumlatedText.toString();
- }
-
-
-
-
- /**
- * Creates an equivalent text to that of the label's but with "\n"(s)
- * inserted at the wrapping positions. This method assumes unlimited
- * bounding box and is used by calculateTextSize()
to
- * calculate the perfect size of the text with wrapping
- *
- * @return the wrapped text
- */
- private String getWrappedText(int wHint, int hHint) {
- String theText = getText();
- if (wHint == -1 || theText.length() == 0 || !isTextWrapped())
- return theText;
-
- Dimension iconSize = getTotalIconSize();
- if (!(iconSize.width == 0 && iconSize.height == 0)) {
- switch(getTextPlacement()) {
- case EAST:
- case WEST:
- wHint -= iconSize.width + getIconTextGap();
- break;
- case NORTH:
- case SOUTH:
- if (hHint != -1)
- hHint -= iconSize.height + getIconTextGap();
- break;
- }
- }
-
-
- if ((hHint == 0)||(wHint == 0)) {
- return "";//$NON-NLS-1$;
- }
-
- Font f = getFont();
- int fontHeight = getMapMode().DPtoLP(FigureUtilities.getFontMetrics(f).getHeight());
- int maxLines = Integer.MAX_VALUE;
- if (hHint != -1) {
- maxLines = (int) (hHint / (double) fontHeight);
- if (maxLines == 0) {
- return "";//$NON-NLS-1$;;
- }
- }
-
- StringBuffer accumlatedText = new StringBuffer();
- StringBuffer remainingText = new StringBuffer(theText);
- int i = 0, j = 0;
-
- while (remainingText.length() > 0 && j++ < maxLines) {
- if ((i = getLineWrapPosition(remainingText.toString(), f, wHint, fontHeight)) == 0)
- break;
-
- if (accumlatedText.length() > 0)
- accumlatedText.append('\n');
- accumlatedText.append(remainingText.substring(0, i));
- remainingText.delete(0, i);
- }
- return accumlatedText.toString();
- }
-
- /**
- * Returns the size of the Label's current text. If the text is currently
- * truncated, the truncated text with its ellipsis is used to calculate the
- * size.
- *
- * @return the size of this label's text, taking into account truncation
- * @since 2.0
- */
- protected Dimension getSubStringTextSize() {
- return calculateSubStringTextSize();
- }
-
- /**
- * Returns the size of the String constant "..." the ellipse based on
- * the currently used Map mode
- * size.
- *
- * @return the size of ellipse text
- *
- */
- private Dimension getEllipseTextSize() {
- if (ellipseTextSize == null) {
- ellipseTextSize = getMapModeConstants().getEllipseTextSize(
- getFont());
- }
- return ellipseTextSize;
- }
-
- /**
- * Returns the text of the label. Note that this is the complete text of the
- * label, regardless of whether it is currently being truncated. Call
- * {@link #getSubStringText()}to return the label's current text contents
- * with truncation considered.
- *
- * @return the complete text of this label
- * @since 2.0
- */
- public String getText() {
- return text;
- }
-
- /**
- * Returns the current alignment of the Label's text. The default text
- * alignment is {@link PositionConstants#CENTER}.
- *
- * @return the text alignment
- */
- public int getTextAlignment() {
- return getAlignment(FLAG_TEXT_ALIGN);
- }
-
- /**
- * Returns the current alignment of the entire Label. The default label
- * alignment is {@link PositionConstants#LEFT}.
- *
- * @return the label alignment
- */
- private int getLabelAlignment() {
- return getAlignment(FLAG_LABEL_ALIGN);
- }
-
- /**
- * Returns the bounds of the label's text. Note that the bounds are
- * calculated using the label's complete text regardless of whether the
- * label's text is currently truncated.
- *
- * @return the bounds of this label's complete text
- * @since 2.0
- */
- public Rectangle getTextBounds() {
- return new Rectangle(getBounds().getLocation().translate(
- getTextLocation()), getTextSize());
- }
-
- /**
- * Returns the location of the label's text relative to the label.
- *
- * @return the text location
- * @since 2.0
- */
- protected Point getTextLocation() {
- if (textLocation != null)
- return textLocation;
- calculateLocations();
- return textLocation;
- }
-
- /**
- * Returns the current placement of the label's text relative to its icon.
- * The default text placement is {@link PositionConstants#EAST}.
- *
- * @return the text placement
- * @since 2.0
- */
- public int getTextPlacement() {
- return getPlacement(FLAG_TEXT_PLACEMENT);
- }
-
- /**
- * Returns the size of the label's complete text. Note that the text used to
- * make this calculation is the label's full text, regardless of whether the
- * label's text is currently being truncated and is displaying an ellipsis.
- * If the size considering current truncation is desired, call
- * {@link #getSubStringTextSize()}.
- *
- * @param wHint a width hint
- * @param hHint a height hint
- * @return the size of this label's complete text
- * @since 2.0
- */
- protected Dimension getTextSize(int wHint, int hHint) {
- if (textSize == null || wHint != cachedTextSizeHint_width || hHint != cachedTextSizeHint_height) {
- textSize = calculateTextSize(wHint, hHint);
- cachedTextSizeHint_width = wHint;
- cachedTextSizeHint_height= hHint;
- }
- return textSize;
- }
-
- /**
- * Gets the text size given the current size as a width hint
- */
- private final Dimension getTextSize() {
- Rectangle r = getBounds();
- return getTextSize(r.width, r.height);
- }
-
- /**
- * @see IFigure#invalidate()
- */
- public void invalidate() {
- prefSize = null;
- minSize = null;
- clearLocations();
- ellipseTextSize = null;
- textSize = null;
- subStringText = null;
- if (iconInfo != null)
- iconInfo.invalidate();
- super.invalidate();
- }
-
- /**
- * Returns true
if the label's text is currently truncated
- * and is displaying an ellipsis, false
otherwise.
- *
- * @return true
if the label's text is truncated
- * @since 2.0
- */
- public boolean isTextTruncated() {
- return !getSubStringTextSize().equals(getTextSize());
- }
-
- /**
- * @see org.eclipse.draw2d.Figure#paintFigure(org.eclipse.draw2d.Graphics)
- */
- public void paintFigure(Graphics graphics) {
- if (isSelected()) {
- graphics.pushState();
- graphics.setBackgroundColor(ColorConstants.menuBackgroundSelected);
- graphics.fillRectangle(getSelectionRectangle());
- graphics.popState();
- graphics.setForegroundColor(ColorConstants.white);
- }
- if (hasFocus()) {
- graphics.pushState();
- graphics.setXORMode(true);
- graphics.setForegroundColor(ColorConstants.menuBackgroundSelected);
- graphics.setBackgroundColor(ColorConstants.white);
- graphics.drawFocus(getSelectionRectangle().resize(-1, -1));
- graphics.popState();
- }
- if (isOpaque())
- super.paintFigure(graphics);
- Rectangle figBounds = getBounds();
-
- graphics.translate(figBounds.x, figBounds.y);
- if (hasIcons())
- paintIcons(graphics);
-
- String subString = getSubStringText();
- if (subString.length() > 0) {
- if (!isEnabled()) {
- graphics.translate(1, 1);
- graphics.setForegroundColor(ColorConstants.buttonLightest);
- paintText(graphics, subString);
- graphics.translate(-1, -1);
- graphics.setForegroundColor(ColorConstants.buttonDarker);
- } else {
- paintText(graphics, subString);
- }
- }
- graphics.translate(-figBounds.x, -figBounds.y);
- }
-
- /**
- * Paints the text and optioanally underlines it
- *
- * @param graphics The graphics context
- * @param subString The string to draw
- */
- private void paintText(Graphics graphics, String subString) {
- StringTokenizer tokenizer = new StringTokenizer(subString, "\n"); //$NON-NLS-1$
- Font f = getFont();
- FontMetrics fontMetrics = FigureUtilities.getFontMetrics(f);
- int fontHeight = getMapMode().DPtoLP(fontMetrics.getHeight());
- int fontHeightHalf = fontHeight / 2;
- int textWidth = getTextExtents(subString, f, fontHeight).width;
- Point p = getTextLocation();
- int y = p.y;
- int x = p.x;
- final int wrapAlignment = getTextWrapAlignment();
- boolean isUnderlined = isTextUnderlined();
- boolean isStrikedThrough = isTextStrikedThrough();
- Rectangle clipRect = new Rectangle();
- graphics.getClip(clipRect);
- int clipRectTopRight_x = clipRect.getTopRight().x;
- // If the font's leading area is 0 then we need to add an offset to
- // avoid truncating at the top (e.g. Korean fonts)
- if (0 == fontMetrics.getLeading()) {
- y += getMapModeConstants().nDPtoLP_2; // 2 is the leading area for default English
- }
-
- while (tokenizer.hasMoreTokens()) {
- String token = tokenizer.nextToken();
- int tokenWidth = getTextExtents(token, f, fontHeight).width;
-
- switch (wrapAlignment) {
- case CENTER:
- x += (textWidth - tokenWidth) / 2;
- break;
- case RIGHT:
- x += textWidth - tokenWidth;
- break;
- }
-
- // increase the clipping rectangle by a small amount to account for font overhang
- // from italic / irregular characters etc.
-
-
- if (tokenWidth + x <= clipRectTopRight_x) {
- Rectangle newClipRect = new Rectangle(clipRect);
- newClipRect.width += (tokenWidth / token.length()) / 2;
- graphics.setClip(newClipRect);
- }
-
- graphics.drawText(token, x, y);
- graphics.setClip(clipRect);
-
- y += fontHeight;
-
- if (isUnderlined)
- graphics.drawLine(x, y - 1, x + tokenWidth, y - 1);
- if (isStrikedThrough)
- graphics.drawLine(x, y - fontHeightHalf + 1, x + tokenWidth, y
- - fontHeightHalf + 1);
- }
- }
-
- /**
- * Paints the icon(s)
- *
- * @param graphics The graphics context
- */
- private void paintIcons(Graphics graphics) {
- Point p = Point.SINGLETON;
- p.setLocation(getIconLocation());
-
- int num = getNumberofIcons();
- for (int i = 0; i < num; i++) {
- Image icon = getIcon(i);
- if (icon != null) {
- graphics.drawImage(icon, p);
- p.x += getIconSize(i).width;
- }
- }
- }
-
- /**
- * Sets the label's icon to the passed image.
- *
- * @param image the new label image
- * @since 2.0
- */
- public void setIcon(Image image) {
- setIcon(image, 0);
- }
-
- /**
- * Sets the label's icon at given index
- *
- * @param image The icon image or null to remove the icon
- * @param index The icon index
- */
- public void setIcon(Image image, int index) {
- if (iconInfo == null) {
- if (index == 0) {
- iconInfo = getMapModeConstants().getSingleIconInfo(image);
- } else {
- iconInfo = new MultiIconInfo();
- iconInfo.setIcon(image, index);
- }
- revalidate();
- repaint();// Call repaint, in case the image dimensions are the same.
- } else if (iconInfo.getIcon(index) != image) {
- if (iconInfo.getMaxIcons() == 1) {
- if (index == 0) {
- iconInfo = getMapModeConstants().getSingleIconInfo(image);
- revalidate();
- repaint();// Call repaint, in case the image dimensions are the same.
- return;
- }
- IconInfo oldIconInfo = iconInfo;
- iconInfo = new MultiIconInfo();
- iconInfo.setIcon(oldIconInfo.getIcon(0), 0);
- }
- iconInfo.setIcon(image, index);
- revalidate();
- repaint();// Call repaint, in case the image dimensions are the same.
- }
- }
-
-
- /**
- * Sets the icon alignment relative to the .abel's alignment to the passed
- * value. The default is {@link PositionConstants#CENTER}. Other possible
- * values are {@link PositionConstants#TOP},
- * {@link PositionConstants#BOTTOM},{@link PositionConstants#LEFT}and
- * {@link PositionConstants#RIGHT}.
- *
- * @param align the icon alignment
- * @since 2.0
- */
- public void setIconAlignment(int align) {
- if (getIconAlignment() == align)
- return;
- setAlignmentFlags(align, FLAG_ICON_ALIGN);
- clearLocations();
- repaint();
- }
-
- /**
- * getIconSize
- * @param index of icon to retrieve size of.
- * @return Dimension representing the icon size.
- */
- protected Dimension getIconSize(int index) {
- if (iconInfo == null)
- return EMPTY_DIMENSION;
- return iconInfo.getIconSize(getMapMode(), index);
- }
-
- /**
- * getIconNumber
- * @return int number of icons in the wrap label
- */
- protected int getNumberofIcons() {
- if (iconInfo == null)
- return 0;
- return iconInfo.getNumberofIcons();
- }
-
- /**
- * getTotalIconSize
- * Calculates the total union of icon sizes
- * @return Dimension that is the union of icon sizes
- */
- protected Dimension getTotalIconSize() {
- if (iconInfo == null)
- return EMPTY_DIMENSION;
- return iconInfo.getTotalIconSize(getMapMode());
- }
-
- /**
- * Sets the Label's alignment to the passed value. The default is
- * {@link PositionConstants#CENTER}. Other possible values are
- * {@link PositionConstants#TOP},{@link PositionConstants#BOTTOM},
- * {@link PositionConstants#LEFT}and {@link PositionConstants#RIGHT}.
- *
- * @param align label alignment
- */
- public void setLabelAlignment(int align) {
- if (getLabelAlignment() == align)
- return;
- setAlignmentFlags(align, FLAG_LABEL_ALIGN);
- clearLocations();
- repaint();
- }
-
- /**
- * Return the ellipse string.
- *
- * @return the String
that represents the fact that the
- * text has been truncated and that more text is available but hidden.
- * Usually this is represented by "...".
- */
- protected String getEllipse() {
- return _ellipse;
- }
-
- /**
- * Sets the label's text.
- *
- * @param s the new label text
- * @since 2.0
- */
- public void setText(String s) {
- //"text" will never be null.
- if (s == null)
- s = "";//$NON-NLS-1$
- if (text.equals(s))
- return;
- text = s;
- revalidate();
- repaint(); //If the new text does not cause a new size, we still need
- // to paint.
- }
-
- /**
- * Sets the text alignment of the Label relative to the label alignment. The
- * default is {@link PositionConstants#CENTER}. Other possible values are
- * {@link PositionConstants#TOP},{@link PositionConstants#BOTTOM},
- * {@link PositionConstants#LEFT}and {@link PositionConstants#RIGHT}.
- *
- * @param align the text alignment
- * @since 2.0
- */
- public void setTextAlignment(int align) {
- if (getTextAlignment() == align)
- return;
- setAlignmentFlags(align, FLAG_TEXT_ALIGN);
- clearLocations();
- repaint();
- }
-
- /**
- * Sets the text placement of the label relative to its icon. The default is
- * {@link PositionConstants#EAST}. Other possible values are
- * {@link PositionConstants#NORTH},{@link PositionConstants#SOUTH}and
- * {@link PositionConstants#WEST}.
- *
- * @param where the text placement
- * @since 2.0
- */
- public void setTextPlacement(int where) {
- if (getTextPlacement() == where)
- return;
- setPlacementFlags(where, FLAG_TEXT_PLACEMENT);
- revalidate();
- repaint();
- }
-
- /**
- * Sets whether the label text should be underlined
- *
- * @param b Wether the label text should be underlined
- */
- public void setTextUnderline(boolean b) {
- if (isTextUnderlined() == b)
- return;
- setFlag(FLAG_UNDERLINED, b);
- repaint();
- }
-
- /**
- * @return whether the label text is underlined
- */
- public boolean isTextUnderlined() {
- return (flags & FLAG_UNDERLINED) != 0;
- }
-
- /**
- * Sets whether the label text should be striked-through
- *
- * @param b Wether the label text should be stricked-through
- */
- public void setTextStrikeThrough(boolean b) {
- if (isTextStrikedThrough() == b)
- return;
- setFlag(FLAG_STRIKEDTHROUGH, b);
- repaint();
- }
-
- /**
- * @return wether the label text is stricked-through
- */
- public boolean isTextStrikedThrough() {
- return (flags & FLAG_STRIKEDTHROUGH) != 0;
- }
-
- /**
- * Sets whether the label text should wrap
- *
- * @param b whether the label text should wrap
- */
- public void setTextWrap(boolean b) {
- if (isTextWrapped() == b)
- return;
- setFlag(FLAG_WRAP, b);
- revalidate();
- repaint();
- }
-
- /**
- * @return wether the label text wrap is on
- */
- public boolean isTextWrapped() {
- return (flags & FLAG_WRAP) != 0;
- }
-
- /**
- * Sets the wrapping width of the label text. This is only valid if text
- * wrapping is turned on
- *
- * @param i The label text wrapping width
- */
- public void setTextWrapWidth(int i) {
- /*
- * if (this.wrapWidth == i) return; this.wrapWidth = i; revalidate();
- * repaint();
- */
- }
-
- /**
- * Sets the wrapping width of the label text. This is only valid if text
- * wrapping is turned on
- *
- * @param i The label text wrapping width
- */
- public void setTextWrapAlignment(int i) {
- if (getTextWrapAlignment() == i)
- return;
-
- setAlignmentFlags(i, FLAG_WRAP_ALIGN);
- repaint();
- }
-
- /**
- * @return the label text wrapping width
- */
- public int getTextWrapAlignment() {
- return getAlignment(FLAG_WRAP_ALIGN);
- }
-
- /**
- * setPlacementFlags
- * @param align
- * @param flagOffset
- */
- private void setPlacementFlags(int align, int flagOffset) {
- flags &= ~(0x7 * flagOffset);
- switch (align) {
- case EAST:
- flags |= 0x1 * flagOffset;
- break;
- case WEST:
- flags |= 0x2 * flagOffset;
- break;
- case NORTH:
- flags |= 0x3 * flagOffset;
- break;
- case SOUTH:
- flags |= 0x4 * flagOffset;
- break;
- }
- }
-
- /**
- * getPlacement
- *
- * @param flagOffset
- * @return PositionConstant representing the placement
- */
- private int getPlacement(int flagOffset) {
- int wrapValue = flags & (0x7 * flagOffset);
- if (wrapValue == 0x1 * flagOffset)
- return EAST;
- else if (wrapValue == 0x2 * flagOffset)
- return WEST;
- else if (wrapValue == 0x3 * flagOffset)
- return NORTH;
- else if (wrapValue == 0x4 * flagOffset)
- return SOUTH;
-
- return EAST;
- }
-
- /**
- * setAlignmentFlags
- * @param align
- * @param flagOffset
- */
- private void setAlignmentFlags(int align, int flagOffset) {
- flags &= ~(0x7 * flagOffset);
- switch (align) {
- case CENTER:
- flags |= 0x1 * flagOffset;
- break;
- case TOP:
- flags |= 0x2 * flagOffset;
- break;
- case LEFT:
- flags |= 0x3 * flagOffset;
- break;
- case RIGHT:
- flags |= 0x4 * flagOffset;
- break;
- case BOTTOM:
- flags |= 0x5 * flagOffset;
- break;
- }
- }
-
- /**
- * Retrieves the alignment value from the flags member.
- *
- * @param flagOffset that is the bitwise value representing the offset.
- * @return PositionConstant representing the alignment
- */
- private int getAlignment(int flagOffset) {
- int wrapValue = flags & (0x7 * flagOffset);
- if (wrapValue == 0x1 * flagOffset)
- return CENTER;
- else if (wrapValue == 0x2 * flagOffset)
- return TOP;
- else if (wrapValue == 0x3 * flagOffset)
- return LEFT;
- else if (wrapValue == 0x4 * flagOffset)
- return RIGHT;
- else if (wrapValue == 0x5 * flagOffset)
- return BOTTOM;
-
- return CENTER;
- }
-
-
- /**
- * Sets the selection state of this label
- *
- * @param b true will cause the label to appear selected
- */
- public void setSelected(boolean b) {
- if (isSelected() == b)
- return;
- setFlag(FLAG_SELECTED, b);
- repaint();
- }
-
- /**
- * @return the selection state of this label
- */
- public boolean isSelected() {
- return (flags & FLAG_SELECTED) != 0;
- }
-
- /**
- * Sets the focus state of this label
- *
- * @param b true will cause a focus rectangle to be drawn around the text
- * of the Label
- */
- public void setFocus(boolean b) {
- if (hasFocus() == b)
- return;
- setFlag(FLAG_HASFOCUS, b);
- repaint();
- }
-
- /**
- * @return the focus state of this label
- */
- public boolean hasFocus() {
- return (flags & FLAG_HASFOCUS) != 0;
- }
-
- /**
- * Returns the bounds of the text selection
- *
- * @return The bounds of the text selection
- */
- private Rectangle getSelectionRectangle() {
- Rectangle figBounds = getTextBounds();
- int expansion = getMapModeConstants().nDPtoLP_2;
- figBounds.resize(expansion, expansion);
- translateToParent(figBounds);
- figBounds.intersect(getBounds());
- return figBounds;
- }
-
- /**
- * returns the position of last character within the supplied text that will
- * fit within the supplied width.
- *
- * @param s a text string
- * @param f font used to draw the text string
- * @param w width in pixles.
- * @param fontHeight int mapped already to logical units.
- */
- private int getLineWrapPosition(String s, Font f, int w, int fontHeight) {
- if (getTextExtents(s, f, fontHeight).width <= w) {
- return s.length();
- }
- // create an iterator for line breaking positions
- BreakIterator iter = BreakIterator.getLineInstance();
- iter.setText(s);
- int start = iter.first();
- int end = iter.next();
-
- // if the first line segment does not fit in the width,
- // determine the position within it where we need to cut
- if (getTextExtents(s.substring(start, end), f, fontHeight).width > w) {
- iter = BreakIterator.getCharacterInstance();
- iter.setText(s);
- start = iter.first();
- }
-
- // keep iterating as long as width permits
- do
- end = iter.next();
- while (end != BreakIterator.DONE
- && getTextExtents(s.substring(start, end), f, fontHeight).width <= w);
- return (end == BreakIterator.DONE) ? iter.last()
- : iter.previous();
- }
-
- /**
- * Returns the largest substring of s in Font f that can be
- * confined to the number of pixels in availableWidth .
- *
- * @param s the original string
- * @param f the font
- * @param w the available width
- * @param fontHeight int mapped already to logical units.
- * @param charAverageWidth int mapped already to logical units.
- * @return the largest substring that fits in the given width
- * @since 2.0
- */
- private int getLargestSubstringConfinedTo(String s, Font f, int w, int fontHeight, int charAverageWidth) {
- float avg = charAverageWidth;
- int min = 0;
- int max = s.length() + 1;
-
- //The size of the current guess
- int guess = 0, guessSize = 0;
- while ((max - min) > 1) {
- //Pick a new guess size
- // New guess is the last guess plus the missing width in pixels
- // divided by the average character size in pixels
- guess = guess + (int) ((w - guessSize) / avg);
-
- if (guess >= max)
- guess = max - 1;
- if (guess <= min)
- guess = min + 1;
-
- //Measure the current guess
- guessSize = getTextExtents(s.substring(0, guess), f, fontHeight).width;
-
- if (guessSize < w)
- //We did not use the available width
- min = guess;
- else
- //We exceeded the available width
- max = guess;
- }
- return min;
- }
-
- /**
- * Gets the tex extent scaled to the mapping mode
- */
- private Dimension getTextExtents(String s, Font f, int fontHeight) {
- if (s.length() == 0) {
- return getMapModeConstants().dimension_nDPtoLP_0;
- } else {
- // height should be set using the font height and the number of
- // lines in the string
- Dimension d = FigureUtilities.getTextExtents(s, f);
- IMapMode mapMode = getMapMode();
- d.width = mapMode.DPtoLP(d.width);
- d.height = fontHeight * new StringTokenizer(s, "\n").countTokens();//$NON-NLS-1$
- return d;
- }
- }
-
+ extends LabelWithTextLayout {
+
+ /**
+ * Construct a Label with no text and no icon.
+ *
+ */
+ public WrapLabel() {
+ super();
+ }
+
+ /**
+ * Construct a Label with passed Image as its icon.
+ *
+ * @param i
+ * the label image
+ */
+ public WrapLabel(Image i) {
+ super(i);
+ setTextHorizontalAlignment(CENTER);
+ }
+
+ /**
+ * Construct a Label with passed String as the Label's text.
+ * @param s the String to set as the Label's text.
+ */
+ public WrapLabel(String s) {
+ super(s);
+ setTextHorizontalAlignment(CENTER);
+ }
+
+ /**
+ * Construct a Label with passed String as text and passed Image as its
+ * icon.
+ *
+ * @param s
+ * the label text
+ * @param i
+ * the label image
+ */
+ public WrapLabel(String s, Image i) {
+ super(s,i);
+ super.setTextHorizontalAlignment(CENTER);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.gmf.runtime.draw2d.ui.figures.LabelWithTextLayout#setLabelAlignment(int)
+ */
+ public void setLabelAlignment(int align) {
+ if ((align & (LEFT_CENTER_RIGHT)) != 0) {
+ super.setLabelAlignment(CENTER);
+ setTextHorizontalAlignment(align);
+ }
+ else
+ super.setLabelAlignment(align);
+ }
+
+ /**
+ * @param i
+ * The label text horizontal alignment
+ */
+ public void setTextWrapAlignment(int i) {
+ if ((getLabelAlignment() & (TOP | BOTTOM)) != 0) {
+ if ((i & (RIGHT | CENTER)) != 0)
+ setTextHorizontalAlignment(i);
+ else
+ setTextHorizontalAlignment(LEFT);
+ }
+ else if ((i == CENTER) &&
+ (getLabelAlignment() == CENTER) &&
+ (super.getTextHorizontalAlignment() != CENTER)) {
+ setTextHorizontalAlignment(i);
+ }
+ }
+
+ /**
+ * The horizontal orientation of the text.
+ *
+ * @see WrapLabel#getTextHorizontalAlignment()
+ */
+ public int getTextWrapAlignment() {
+ return getTextHorizontalAlignment();
+ }
+
+ /**
+ * We do not want to allow anyone else to control the layout of the
+ * WrapLabel, which is why the manager parameter can only be
+ * of the type OffsetLayout that is defined within WrapLabel
+ *
+ * @see org.eclipse.draw2d.Figure#setLayoutManager(org.eclipse.draw2d.LayoutManager)
+ */
+ public void setLayoutManager(LayoutManager manager) {
+ // we want to use the OffsetLayout only within WrapLabel.
+ // This will prevent any client from trying to change
+ // the layout of the contents within WrapLabel.
+ if (manager instanceof OffsetLayout)
+ super.setLayoutManager(manager);
+ }
-
-}
\ No newline at end of file
+ /**
+ * Not supported.
+ * @deprecated
+ *
+ */
+ public void setTextWrapWidth() {
+ // deprecated method.
+ }
+}
Index: src/org/eclipse/gmf/runtime/draw2d/ui/figures/LabelWithTextLayout.java
===================================================================
RCS file: src/org/eclipse/gmf/runtime/draw2d/ui/figures/LabelWithTextLayout.java
diff -N src/org/eclipse/gmf/runtime/draw2d/ui/figures/LabelWithTextLayout.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/gmf/runtime/draw2d/ui/figures/LabelWithTextLayout.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,1924 @@
+/******************************************************************************
+ * Copyright (c) 2006 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.draw2d.ui.figures;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.eclipse.draw2d.Figure;
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.Label;
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.StackLayout;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.draw2d.text.BlockFlow;
+import org.eclipse.draw2d.text.BlockFlowLayout;
+import org.eclipse.draw2d.text.FlowPage;
+import org.eclipse.draw2d.text.PageFlowLayout;
+import org.eclipse.draw2d.text.TextFragmentBox;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.mapmode.IMapModeHolder;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.text.FlowUtilitiesEx;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.text.ParagraphTextLayoutEx;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.text.SelectableTextFlow;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.text.SingleLineTextLayoutWithEllipses;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.text.TextLayoutManagerWithMapMode;
+import org.eclipse.gmf.runtime.draw2d.ui.mapmode.IMapMode;
+import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * An extended label that has the following extra features:
+ * 1. Allows selection, focus feedback, underlined
+ * and striked-through text.
+ * 2. Supports multiple icons.
+ * 3. Enhanced layout functionality for placing icon(s) and text.
+ * 4. Text can be word-wrapped or be truncated with ellipses.
+ *
+ *
+ * EXPLANATION OF LAYOUTS
+ *
+ * This WrapLabel contains functionality to display many icons alongside text.
+ * The following will describe how the layout of these icons and text
+ * are done.
+ *
+ *
+ * Using {@link #setTextPlacement(int)}:
+ * + * All icons that are set using {@link #setIcon(Image)} are placed horizontally + * one after the other. The position of the text relative to icons + * depends on {@link #setTextPlacement(int)}. If text placement is set to + * {@link PositionConstants#EAST}, then the icon(s) would be placed on the left + * of the text. Similarly, if text placement is set to + * {@link PositionConstants#WEST}, the icon(s) will be placed on the right of the + * text; {@link PositionConstants#NORTH} would put the icons below the text; and + * {@link PositionConstants#SOUTH} would place the icons above the text.
+ *
+ * Using {@link #setTextAlignment(int)} and {@link #setIconAlignment(int)}:
+ * + * Use {@link #setTextAlignment(int)} and {@link #setIconAlignment(int)} to + * align the text and icons relative to each other for more dynamic control. + * If the text placement is on the east or west of the icon(s) + * (i.e. the icon(s) on the left or right of the text respectively), then only + * {@link PositionConstants#TOP}, {@link PositionConstants#CENTER}, and + * {@link PositionConstants#BOTTOM} can be used when calling + * {@link #setTextAlignment(int)} and {@link #setIconAlignment(int)}. In this case, + * setting the text alignment to {@link PositionConstants#TOP} will make sure + * that the top of the text is aligned horizontally with the top of the icon(s) if + * the height of the total size of icon(s) is greater than the height of the text. Similarly, + * setting the text alignment to {@link PositionConstants#CENTER} will make sure + * that the top of the text is aligned horizontally with the vertical center of the total + * size of icon(s) if the height of the total size of icon(s) is greater than + * the height of the text. Also, setting the text alignment to + * {@link PositionConstants#BOTTOM} will make sure + * that the bottom of the text is aligned horizontally with the bottom of the total + * size of icon(s) if the height of the total size of icon(s) is greater than + * the height of the text.
+ * + * The other scenario is when the text placement is on the south or north of the icon(s) + * (i.e. the icon(s) above or below the text respectively). If this is true, only + * {@link PositionConstants#LEFT}, {@link PositionConstants#CENTER}, and + * {@link PositionConstants#RIGHT} can be used when calling + * {@link #setTextAlignment(int)} and {@link #setIconAlignment(int)}. In this case, + * setting the text alignment to {@link PositionConstants#LEFT} will make sure + * that the left of the text is aligned vertically with the left of the icon(s) if + * the width of the total size of icon(s) is greater than the width of the text. Similarly, + * setting the text alignment to {@link PositionConstants#CENTER} will make sure + * that the left of the text is aligned vertically with the horizontal center of the total + * size of icon(s) if the width of the total size of icon(s) is greater than + * the width of the text. Also, setting the text alignment to + * {@link PositionConstants#RIGHT} will make sure + * that the right of the text is aligned vertically with the right of the total + * size of icon(s) if the width of the total size of icon(s) is greater than + * the width of the text.
+ * + * {@link #setIconAlignment(int)} works identically as {@link #setTextAlignment(int)}, + * except the roles of text and icon(s) are switched in the above descriptions.
+ *
+ *
+ * Using {@link #setLabelAlignment(int)}:
+ * + * The entire label, text and icons, can moved into different positions vertically. + * {@link PositionConstants#TOP}, {@link PositionConstants#CENTER}, and + * {@link PositionConstants#BOTTOM} places the text and icons (no matter how they are arranged + * relatively to each other) on the top, center, or bottom of the bounds of + * LabelWithTextLayout.
+ *
+ *
+ * Using {@link #setTextHorizontalAlignment(int)}:
+ * + * Use {@link #setTextHorizontalAlignment(int)} with {@link PositionConstants#LEFT}, + * {@link PositionConstants#CENTER}, or {@link PositionConstants#RIGHT} to justify + * the text accordingly. The icon(s) will move with the text, so this can be + * considered a horizontal label alignment equivalent for + * {@link #setLabelAlignment(int)}.
+ *
+ *
+ * WARNING: User-nested figures are not expected within this WrapLabel.
+ * + * Some code taken from the original WrapLabel by melaasar + *
+ * + * @author satif
+ */
+public class LabelWithTextLayout
+ extends Label
+ implements PositionConstants {
+
+ private static final Map mapModeConstantsMap = new WeakHashMap();
+
+ private static class MapModeConstants {
+
+ private static final int MAX_IMAGE_INFO = 12;
+
+ public final WeakReference mapModeRef;
+
+ public final int nDPtoLP_3;
+
+ public final int nDPtoLP_2;
+
+ public final SingleIconInfo[] singleIconInfos = new SingleIconInfo[MAX_IMAGE_INFO];
+
+ public MapModeConstants(IMapMode mapMode) {
+ this.mapModeRef = new WeakReference(mapMode);
+ nDPtoLP_2 = mapMode.DPtoLP(2);
+ nDPtoLP_3 = mapMode.DPtoLP(3);
+ }
+
+ public SingleIconInfo getSingleIconInfo(Image image) {
+ if (image == null) {
+ return SingleIconInfo.NULL_INFO;
+ }
+ SingleIconInfo info;
+ for (int i = 0; i < MAX_IMAGE_INFO; ++i) {
+ info = singleIconInfos[i];
+ if (info == null) {
+ info = new SingleIconInfo(image);
+ singleIconInfos[i] = info;
+ return info;
+ }
+ if (info.icon == image) {
+ return info;
+ }
+ }
+ int index = SingleIconInfo.count % MAX_IMAGE_INFO;
+ info = new SingleIconInfo(image);
+ singleIconInfos[index] = info;
+ return info;
+ }
+ }
+
+ private static abstract class IconInfo {
+ /**
+ * Gets the icon at the index location.
+ *
+ * @param i
+ * the index to retrieve the icon of
+ * @return Image
that corresponds to the given index.
+ */
+ public abstract Image getIcon(int i);
+
+ /**
+ * Gets the icon size of the icon at the given index.
+ *
+ * @param i
+ * @return the Dimension
that is the size of the icon at
+ * the given index.
+ */
+ public abstract Dimension getIconSize(IMapMode mapMode, int i);
+
+ /**
+ * @return the number of icons
+ */
+ public abstract int getNumberofIcons();
+
+ /**
+ * @return the Dimension
that is the total size of all
+ * the icons.
+ */
+ public abstract Dimension getTotalIconSize(IMapMode mapMode);
+
+ public abstract void invalidate();
+
+ /**
+ * Sets the icon at the index location.
+ *
+ * @param icon
+ * @param i
+ */
+ public abstract void setIcon(Image icon, int i);
+
+ /**
+ *
+ */
+ public abstract int getMaxIcons();
+
+ }
+
+ private static class SingleIconInfo
+ extends IconInfo {
+
+ static int count;
+
+ public static final SingleIconInfo NULL_INFO = new SingleIconInfo(){
+ public int getNumberofIcons() {
+ return 0;
+ }
+ };
+
+ final Image icon;
+
+ /** total icon size */
+ private Dimension totalIconSize;
+
+ private SingleIconInfo() {
+ icon = null;//don't increment count, used only for NULL_INFO
+ }
+
+ public SingleIconInfo(Image icon) {
+ this.icon = icon;
+ ++count;
+ }
+
+ public final int getMaxIcons() {
+ return 1;
+ }
+
+
+ public Image getIcon(int i) {
+ if (i == 0) {
+ return icon;
+ } else if (i > 0) {
+ return null;
+ }
+ throw new IndexOutOfBoundsException();
+ }
+
+
+ public void setIcon(Image img, int i) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public Dimension getIconSize(IMapMode mapMode, int i) {
+ if (i == 0) {
+ return getTotalIconSize(mapMode);
+ }
+
+ throw new IndexOutOfBoundsException();
+ }
+
+
+ public int getNumberofIcons() {
+ return 1;
+ }
+
+
+ public Dimension getTotalIconSize(IMapMode mapMode) {
+ if (totalIconSize != null)
+ return totalIconSize;
+
+ if (icon != null && !icon.isDisposed()) {
+ org.eclipse.swt.graphics.Rectangle imgBounds = icon.getBounds();
+ totalIconSize = new Dimension(mapMode.DPtoLP(imgBounds.width),
+ mapMode.DPtoLP(imgBounds.height));
+ } else {
+ totalIconSize = EMPTY_DIMENSION;
+ }
+
+ return totalIconSize;
+ }
+
+
+ public void invalidate() {
+ totalIconSize = null;
+ }
+
+ }
+
+ private static class MultiIconInfo
+ extends IconInfo {
+
+ /** the label icons */
+ private ArrayList icons = new ArrayList(2);
+
+ /** total icon size */
+ private Dimension totalIconSize;
+
+ public MultiIconInfo() {
+ super();
+ }
+
+ public int getMaxIcons() {
+ return -1;
+ }
+
+ /**
+ * Gets the icon at the index location.
+ *
+ * @param i
+ * the index to retrieve the icon of
+ * @return Image
that corresponds to the given index.
+ */
+ public Image getIcon(int i) {
+ if (i >= icons.size())
+ return null;
+
+ return (Image) icons.get(i);
+ }
+
+ /**
+ * Sets the icon at the index location.
+ *
+ * @param icon
+ * @param i
+ */
+ public void setIcon(Image icon, int i) {
+ int size = icons.size();
+ if (i >= size) {
+ for (int j = size; j < i; j++)
+ icons.add(null);
+ icons.add(icon);
+ icons.trimToSize();
+ } else
+ icons.set(i, icon);
+ }
+
+ /**
+ * Gets the icon size of the icon at the given index.
+ *
+ * @param i
+ * @return the Dimension
that is the size of the icon at
+ * the given index.
+ */
+ public Dimension getIconSize(IMapMode mapMode, int i) {
+ Image img = getIcon(i);
+ if (img != null && !img.isDisposed()) {
+ org.eclipse.swt.graphics.Rectangle imgBounds = img.getBounds();
+ return new Dimension(mapMode.DPtoLP(imgBounds.width), mapMode
+ .DPtoLP(imgBounds.height));
+ }
+ return EMPTY_DIMENSION;
+ }
+
+ /**
+ * @return the number of icons
+ */
+ public int getNumberofIcons() {
+ return icons.size();
+ }
+
+ /**
+ * @return the Dimension
that is the total size of all
+ * the icons.
+ */
+ public Dimension getTotalIconSize(IMapMode mapMode) {
+ if (totalIconSize != null)
+ return totalIconSize;
+ int iconNum = getNumberofIcons();
+ if (iconNum == 0) {
+ return totalIconSize = EMPTY_DIMENSION;
+ }
+
+ totalIconSize = new Dimension();
+ for (int i = 0; i < iconNum; i++) {
+ Dimension iconSize = getIconSize(mapMode, i);
+ totalIconSize.width += iconSize.width;
+ if (iconSize.height > totalIconSize.height)
+ totalIconSize.height = iconSize.height;
+ }
+
+ return totalIconSize;
+ }
+
+ /**
+ *
+ */
+ public void invalidate() {
+ totalIconSize = null;
+ }
+ }
+
+
+ /**
+ * Lays out children according to the offset bounds provided.
+ * This offset bounds is added to the container figure's client
+ * area and applied to all figures. This allows the positioning
+ * of all child figures in a stack layout but in a specific position
+ * and with a specific dimension.
+ *
+ */
+ protected static class OffsetLayout
+ extends StackLayout {
+
+ // the offset constraint to apply to child figures.
+ private Rectangle offsetConstraint = null;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.draw2d.StackLayout#layout(org.eclipse.draw2d.IFigure)
+ */
+ public void layout(IFigure figure) {
+ List children = figure.getChildren();
+ IFigure child;
+ for (int i = 0; i < children.size(); i++) {
+ child = (IFigure) children.get(i);
+ Rectangle r = figure.getClientArea().getCopy();
+ if (offsetConstraint != null) {
+ r.x += offsetConstraint.x;
+ r.y += offsetConstraint.y;
+
+ r.width += offsetConstraint.width;
+ r.height += offsetConstraint.height;
+
+ // we don't want the width and height to be
+ // less than zero.
+ if (r.width < 0)
+ r.width = 0;
+ if (r.height < 0)
+ r.height = 0;
+ }
+
+ child.setBounds(r);
+ }
+ }
+
+ /**
+ * Set the offset constraint.
+ *
+ * The rectangle parameter represents an offset
+ * that will be added to the container figure's client area
+ * and this will be applied to all child figures.
+ *
+ * @param offsetConstraint the offset constraint rectangle.
+ */
+ public void setOffsetConstraint(Rectangle offsetConstraint) {
+ this.offsetConstraint = offsetConstraint;
+ }
+ }
+
+ private static final Dimension EMPTY_DIMENSION = new Dimension(0, 0);
+
+ /**
+ * calculateNow is a flag to indicate whether the layout data should be
+ * recalculated before the Label is painted. This avoids recalculation
+ * of layout data upon multiple paintFigure calls when the figure has not
+ * been invalidated.
+ */
+ private static int FLAG_CALCULATE_LOCATIONS = MAX_FLAG << 4;
+
+ /**
+ * @see #setTextWrap(boolean)
+ */
+ private static int FLAG_WRAP = MAX_FLAG << 5;
+
+ /**
+ * @see #setTextAlignment(int)
+ */
+ private static int FLAG_TEXT_ALIGN = MAX_FLAG << 6;
+
+ /**
+ * @see #setIconAlignment(int)
+ */
+ private static int FLAG_ICON_ALIGN = MAX_FLAG << 12;
+
+ /**
+ * @see #setLabelAlignment(int)
+ */
+ private static int FLAG_LABEL_ALIGN = MAX_FLAG << 15;
+
+ /**
+ * @see #setTextPlacement(int)
+ */
+ private static int FLAG_TEXT_PLACEMENT = MAX_FLAG << 18;
+
+
+ // cache the map mode constants...
+ private MapModeConstants mapModeConstants;
+
+ private IconInfo iconInfo;
+
+ private SelectableTextFlow textFlow;
+
+ private BlockFlow blockFlow;
+
+ private FlowPage flowPage;
+
+ // cached location of the icon.
+ private Point iconLocation;
+
+ /**
+ * textBounds is used as the offsetConstraint in OffsetLayout,
+ * primarily to position flowPage correctly to align it with the
+ * icon(s)
+ */
+ private Rectangle textBounds;
+
+ /**
+ * Cache the preferred width and height parameters. getPreferredSize can get
+ * called multiple times with the same parameters, so cache these to avoid
+ * redundant recalculations.
+ */
+ private int cached_PrefWidth = Integer.MIN_VALUE,
+ cached_PrefHeight = Integer.MIN_VALUE;
+
+ /**
+ * Construct a Label with no text and no icon.
+ *
+ */
+ public LabelWithTextLayout() {
+ super();
+
+ this.setLayoutManager(new OffsetLayout());
+
+ setupTextFigures(false);
+
+ // default flags...
+ setAlignmentFlags(CENTER, FLAG_TEXT_ALIGN);
+ setAlignmentFlags(CENTER, FLAG_ICON_ALIGN);
+ setAlignmentFlags(CENTER, FLAG_LABEL_ALIGN);
+ blockFlow.setHorizontalAligment(LEFT);
+
+ setPlacementFlags(EAST, FLAG_TEXT_PLACEMENT);
+ setFlag(FLAG_WRAP, false);
+ }
+
+ /**
+ * Construct a Label with passed Image as its icon.
+ *
+ * @param i
+ * the label image
+ */
+ public LabelWithTextLayout(Image i) {
+ this();
+ iconInfo = new SingleIconInfo(i);
+ }
+
+ /**
+ * Construct a Label with passed String as the Label's text.
+ * @param s the String to set as the Label's text.
+ */
+ public LabelWithTextLayout(String s) {
+ this();
+ textFlow.setText(s);
+ }
+
+ /**
+ * Construct a Label with passed String as text and passed Image as its
+ * icon.
+ *
+ * @param s
+ * the label text
+ * @param i
+ * the label image
+ */
+ public LabelWithTextLayout(String s, Image i) {
+ this();
+ textFlow.setText(s);
+ iconInfo = new SingleIconInfo(i);
+
+ }
+
+ /**
+ * Calculates the text alignment relative to the icon.
NOTE: Should be
+ * called by calculateLocations only.
+ *
+ *
+ * @param textPlacement
+ * the text placement relative to the icon.
+ * @param totalIconSize
+ * the total size of all icons.
+ * @param literalTextSize
+ * the size of the text.
+ *
+ */
+ private void calculateIconAlignment(int textPlacement,
+ Dimension totalIconSize, Rectangle _literalTextBounds) {
+ switch (textPlacement) {
+ case NORTH:
+ case SOUTH:
+ if (totalIconSize.width < _literalTextBounds.width) {
+ switch (getIconAlignment()) {
+ case LEFT:
+ // nothing to add
+ break;
+ case CENTER:
+ iconLocation.x += _literalTextBounds.x +
+ (_literalTextBounds.width - totalIconSize.width) / 2;
+ break;
+ case RIGHT:
+ iconLocation.x += _literalTextBounds.x +
+ (_literalTextBounds.width - totalIconSize.width);
+ break;
+ }
+ }
+ break;
+ case WEST:
+ case EAST:
+ if (totalIconSize.height < _literalTextBounds.height) {
+ switch (getIconAlignment()) {
+ case TOP:
+ // nothing to add
+ break;
+ case CENTER:
+ iconLocation.y = (_literalTextBounds.height - totalIconSize.height) / 2;
+ break;
+ case BOTTOM:
+ iconLocation.y = (_literalTextBounds.height - totalIconSize.height);
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ /**
+ * Calculates the text alignment relative to the icon.
NOTE: Should be
+ * called by calculateLocations only.
+ *
+ * + * @param textPlacement + * the text placement relative to the icon. + * @param totalIconSize + * the total size of all icons. + * @param literalTextSize + * the size of the text. + */ + private void calculateTextAlignment(int textPlacement, + Dimension totalIconSize, Dimension literalTextSize) { + switch (textPlacement) { + case NORTH: + case SOUTH: + if (literalTextSize.width < totalIconSize.width) { + switch (getTextAlignment()) { + case LEFT: + // nothing to add + break; + case CENTER: + textBounds.x += (totalIconSize.width - literalTextSize.width) / 2; + break; + case RIGHT: + textBounds.x += (totalIconSize.width - literalTextSize.width); + break; + } + } + break; + case WEST: + case EAST: + if (literalTextSize.height < totalIconSize.height) { + switch (getTextAlignment()) { + case TOP: + // nothing to add + break; + case CENTER: + textBounds.y += (totalIconSize.height - literalTextSize.height) / 2; + break; + case BOTTOM: + textBounds.y += (totalIconSize.height - literalTextSize.height); + break; + } + } + break; + } + } + + /** + * Sets up the layout of text and icons. + * + */ + private void calculateLocations() { + + int textPlacement = getTextPlacement(); + Dimension totalIconSize = getTotalIconSize(); + Rectangle literalSubstringTextSize = textFlow.getLiteralSubstringTextBounds(); + + layoutTextAndIcons(textPlacement, totalIconSize, getPreferredSize( + cached_PrefWidth, -1)); + + calculateIconAlignment(textPlacement, totalIconSize, + literalSubstringTextSize); + calculateTextAlignment(textPlacement, totalIconSize, + literalSubstringTextSize.getSize()); + + if (getLayoutManager() instanceof OffsetLayout) { + ((OffsetLayout)getLayoutManager()).setOffsetConstraint(textBounds); + } + + this.layout(); + flowPage.getLayoutManager().layout(textFlow); + + finalIconAdjustments(textPlacement, literalSubstringTextSize.getSize()); + } + + /** + * Returns the bounds of the label's text. Note that the bounds are calculated using the + * label's text AFTER it has been laid out by the TextLayoutManager.
+ * + * If you want to know the size of the text without any layout style applied, + * use {@link #getTextSize()} + * + * @return the bounds of this label's laid-out text + */ + public Rectangle getTextBounds() { + calculateLocations(); + + return calculateTextBounds(false); + } + + /* (non-Javadoc) + * @see org.eclipse.draw2d.Label#getIconBounds() + */ + public Rectangle getIconBounds() { + if (iconLocation == null) + calculateLocations(); + + Point icon_Location = this.iconLocation.getCopy(); + translateToParent(icon_Location); + Rectangle iconBounds = new Rectangle(icon_Location, getTotalIconSize()); + return iconBounds; + } + + /** + * Returns the gap between the text and the icon(s). + * + * @return the gap, or 0 if there is no icon or text. + */ + public int getIconTextGap() { + if (iconInfo == null || getText().equals("") || getIcon() == null) //$NON-NLS-1$ + return 0; + return getMapModeConstants().nDPtoLP_3; + } + + /** + * Get the text of only the visible area. + */ + protected Dimension getSubStringTextSize() { + return textFlow.getLiteralSubstringTextBounds().getSize(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.draw2d.Label#getTextLocation() + */ + protected Point getTextLocation() { + return getTextBounds().getLocation(); + } + + /** + * not yet supported. Default is to return the entire text. + * + * @see WrapLabel#getText() + */ + public String getSubStringText() { + return getText(); + } + + /** + * Returns the visible-only or total text size from whatever + * the current state of the fragments in textFlow are.
+ * + * These bounds represents the bounds of the text and text + * only. However, note that since flowPage can be translated by + * the OffsetLayout, these will not be the same as the one given + * by {@link SelectableTextFlow#getLiteralSubstringTextBounds()}.
+ *
+ * These bounds exclude any area which the text does not occupy.
+ *
+ * @param subStringText
+ * true to stop calculating at non-visible text area.
+ */
+ private Rectangle calculateTextBounds(boolean subStringText) {
+
+ Rectangle refBounds = getBounds(), calRect = new Rectangle(
+ Integer.MAX_VALUE, Integer.MAX_VALUE, 0, 0);
+
+ if (textFlow == null || blockFlow == null || flowPage == null)
+ return calRect;
+
+ List fragments = textFlow.getFragments();
+
+ int locY = 0;
+
+ if (textBounds != null)
+ locY = textBounds.y;
+
+ for (int i = 0; i < fragments.size(); i++) {
+ TextFragmentBox fragment = (TextFragmentBox) fragments.get(i);
+
+ if (fragment.getLineRoot() == null)
+ continue;
+
+ int y = fragment.getLineRoot().getVisibleTop();
+
+ if (fragment.getX() < calRect.x)
+ calRect.x = fragment.getX();
+ if (y < calRect.y)
+ calRect.y = y;
+
+ if (calRect.width < fragment.getWidth())
+ calRect.width = fragment.getWidth();
+
+ y = fragment.getAscent() + fragment.getDescent();
+ calRect.height += y;
+
+ // we don't want to continue to non-visible fragments,
+ // resulting in performance improvement
+ if (subStringText && calRect.height + locY > refBounds.height) {
+ if (subStringText) // calculate only substring text.
+ break;
+ }
+ }
+
+ if (!subStringText) {
+ calRect.resize(getMapModeConstants().nDPtoLP_2,
+ getMapModeConstants().nDPtoLP_2);
+
+ blockFlow.translateToParent(calRect);
+ flowPage.translateToParent(calRect);
+ translateToParent(calRect);
+ }
+
+ return calRect;
+ }
+
+ /**
+ * Calculates the placement of the text relative to the icon.
+ * NOTE: to be used by calculateLocations only.
+ * @see #getTextPlacement()
+ *
+ *
+ *
+ * @param insertionPoint
+ * the Point
where the text and icon have to be
+ * inserted.
+ * @param textPlacement
+ * the placement of text relative to the icon.
+ * @param totalIconSize
+ * the total size of all icons.
+ */
+ private void calculateTextPlacement(Point insertionPoint,
+ int textPlacement, Dimension totalIconSize) {
+ switch (textPlacement) {
+ case NORTH:
+ textBounds = new Rectangle(new Point(insertionPoint.x,
+ insertionPoint.y), new Dimension(-insertionPoint.x,
+ -insertionPoint.y));
+ iconLocation = new Point(insertionPoint.x,
+ textFlow.getSize().height + getIconTextGap()
+ + textFlow.getDescent());
+
+ if (textBounds.x < 0)
+ textBounds.x = 0;
+ if (textBounds.y < 0)
+ textBounds.y = 0;
+
+ break;
+ case SOUTH:
+ textBounds = new Rectangle(new Point(insertionPoint.x,
+ totalIconSize.height + getIconTextGap()), new Dimension(
+ -insertionPoint.x,
+ -(totalIconSize.height + getIconTextGap())));
+ iconLocation = new Point(insertionPoint.x, insertionPoint.y);
+
+ if (textBounds.x < 0)
+ textBounds.x = 0;
+
+ break;
+ case WEST:
+ textBounds = new Rectangle(new Point(insertionPoint.x,
+ insertionPoint.y), new Dimension(
+ -(totalIconSize.width + getIconTextGap() + insertionPoint.x),
+ -insertionPoint.y));
+ iconLocation = new Point(getSize().width - totalIconSize.width,
+ insertionPoint.y);
+
+ if (textBounds.x < 0)
+ textBounds.x = 0;
+ if (textBounds.y < 0)
+ textBounds.y = 0;
+
+ break;
+ case EAST:
+ iconLocation = new Point(insertionPoint.x, insertionPoint.y);
+ textBounds = new Rectangle(
+ new Point(insertionPoint.x + totalIconSize.width
+ + getIconTextGap(), insertionPoint.y),
+ new Dimension(
+ -(totalIconSize.width + getIconTextGap() + insertionPoint.x),
+ -insertionPoint.y));
+
+ if ((textBounds.y < 0) || (textBounds.y > getBounds().height))
+ textBounds.y = 0;
+
+ break;
+ }
+ }
+
+ /**
+ * Clears all cached layout data. Will enable layout recalculation next time
+ * anything is validated or when paintFigure is called.
+ *
+ */
+ private void clearLocations() {
+ prefSize = null;
+ minSize = null;
+ iconLocation = null;
+ textBounds = null;
+ setFlag(FLAG_CALCULATE_LOCATIONS, true);
+ }
+
+ /**
+ * Executes the case exceptions/constraints for icon alignment.
+ * NOTE: to be used by calculateLocations only.
+ *
+ *
+ * @param textPlacement
+ * the text placement (N/S/E/W)
+ * @param literalTextSize
+ * the substring text size.
+ */
+ private void finalIconAdjustments(int textPlacement, Dimension literalTextSize) {
+ // the range checks below are to make sure we haven't calculated
+ // anything that can't be displayed...
+ int textHorizontalAlignment = getTextHorizontalAlignment();
+
+ switch (textPlacement) {
+ case EAST:
+ // we want the icon to be right next to the text all the time...
+ if (textHorizontalAlignment == CENTER) {
+ iconLocation.x = (blockFlow.getBounds().width / 2)
+ - (literalTextSize.width / 2) - getIconTextGap();
+ } else if (textHorizontalAlignment == RIGHT) {
+ iconLocation.x = blockFlow.getBounds().width
+ - literalTextSize.width - getIconTextGap();
+ }
+
+ if (iconLocation.x < 0)
+ iconLocation.x = 0;
+ if (iconLocation.y < 0)
+ iconLocation.y = 0;
+ break;
+ case WEST:
+ // we want the icon to be right next to the text all the time...
+ if (textHorizontalAlignment == LEFT) {
+ iconLocation.x = literalTextSize.width + getIconTextGap();
+ } else if (textHorizontalAlignment == CENTER) {
+ iconLocation.x = (flowPage.getBounds().width / 2)
+ + (literalTextSize.width / 2) + getIconTextGap();
+ }
+
+ if (iconLocation.y < 0)
+ iconLocation.y = 0;
+ break;
+ case NORTH:
+ if (iconLocation.x < 0)
+ iconLocation.x = 0;
+ break;
+ case SOUTH:
+ if (iconLocation.x < 0)
+ iconLocation.x = 0;
+ if (iconLocation.y < 0)
+ iconLocation.y = 0;
+ break;
+ }
+ }
+
+ /**
+ * Retrieves the alignment value from the flags member.
+ *
+ * @param flagOffset
+ * that is the bitwise value representing the offset.
+ * @return PositionConstant representing the alignment
+ */
+ private int getAlignment(int flagOffset) {
+ int wrapValue = flags & (0x7 * flagOffset);
+ if (wrapValue == 0x1 * flagOffset)
+ return CENTER;
+ else if (wrapValue == 0x2 * flagOffset)
+ return TOP;
+ else if (wrapValue == 0x3 * flagOffset)
+ return LEFT;
+ else if (wrapValue == 0x4 * flagOffset)
+ return RIGHT;
+ else if (wrapValue == 0x5 * flagOffset)
+ return BOTTOM;
+
+ return CENTER;
+ }
+
+ /**
+ * Return the ellipse string.
+ *
+ * @return the String
that represents the fact that the text
+ * has been truncated and that more text is available but hidden.
+ * Usually this is represented by "...".
+ */
+ protected String getEllipse() {
+ return FlowUtilitiesEx.ELLIPSIS;
+ }
+
+ /**
+ * Returns the Label's icon.
+ *
+ * @return the label icon
+ */
+ public Image getIcon() {
+ return getIcon(0);
+ }
+
+ /**
+ * Returns the label's icon at the given index (provided an icon exists at
+ * this index).
+ *
+ * + * @param index + * @return the icon at the given index. + */ + public Image getIcon(int index) { + if (iconInfo == null) + return null; + return iconInfo.getIcon(index); + } + + /** + * Returns the current alignment of the Label's icon. The default is + * {@link PositionConstants#CENTER}. + *
+ *
+ * @return the icon alignment
+ */
+ public int getIconAlignment() {
+ return getAlignment(FLAG_ICON_ALIGN);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.draw2d.Label#getIconLocation()
+ */
+ protected Point getIconLocation() {
+ if (iconLocation == null)
+ calculateLocations();
+ else
+ finalIconAdjustments(getTextPlacement(),
+ textFlow.getLiteralSubstringTextBounds().getSize());
+ return iconLocation;
+ }
+
+ /**
+ * Returns the size of the icon at a given index.
+ *
+ * @param index
+ * of icon to retrieve size of.
+ * @return Dimension representing the icon size.
+ */
+ protected Dimension getIconSize(int index) {
+ if (iconInfo == null)
+ return EMPTY_DIMENSION;
+ return iconInfo.getIconSize(getFigureMapMode(), index);
+ }
+
+ /**
+ * Returns the current alignment of the entire Label. The default label
+ * alignment is {@link PositionConstants#LEFT}.
+ *
+ * @return the label alignment
+ */
+ public int getLabelAlignment() {
+ return getAlignment(FLAG_LABEL_ALIGN);
+ }
+
+ /**
+ * @return IMapMode
used by this figure.
+ * IMapMode
that allows for the coordinate mapping
+ * from device to logical units.
+ */
+ private IMapMode getFigureMapMode() {
+ return (IMapMode) getMapModeConstants().mapModeRef.get();
+ }
+
+ /**
+ * Returns the stored map mode constants.
+ * @return MapModeConstants that are cached.
+ */
+ private MapModeConstants getMapModeConstants() {
+ if (mapModeConstants == null) {
+ IMapMode mapMode = MapModeUtil.getMapMode(this);
+ while (mapMode instanceof IMapModeHolder) {
+ mapMode = ((IMapModeHolder) mapMode).getMapMode();
+ }
+ mapModeConstants = (MapModeConstants) mapModeConstantsMap
+ .get(mapMode);
+ if (mapModeConstants == null) {
+ mapModeConstants = new MapModeConstants(mapMode);
+ mapModeConstantsMap.put(mapMode, mapModeConstants);
+ }
+ if (textFlow != null) {
+ ((TextLayoutManagerWithMapMode)
+ textFlow.getLayoutManager()).setMapMode(mapMode);
+ textFlow.setMapMode(mapMode);
+ }
+ }
+ return mapModeConstants;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.draw2d.Label#calculateLabelSize(org.eclipse.draw2d.geometry.Dimension)
+ */
+ protected Dimension calculateLabelSize(Dimension txtSize) {
+ if (txtSize.equals(EMPTY_DIMENSION))
+ return txtSize; // return 0,0 dimension.
+
+ int gap = getIconTextGap();
+ Dimension d = new Dimension(0, 0);
+ switch (getTextPlacement()) {
+ case WEST:
+ case EAST:
+ d.width = getTotalIconSize().width + gap + txtSize.width;
+ d.height = Math.max(getTotalIconSize().height, txtSize.height);
+ break;
+ default: // NORTH or SOUTH
+ d.width = Math.max(getTotalIconSize().width, txtSize.width);
+ d.height = getTotalIconSize().height + gap + txtSize.height;
+ break;
+ }
+
+ return d;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.draw2d.Label#calculateTextSize()
+ */
+ protected Dimension calculateTextSize() {
+ /* getTextExtent calls GC#stringExtent and this adds
+ * a blank character before calculating the text size
+ * if the text's length is zero. However, we do want an
+ * empty dimension if there is not text.
+ */
+
+ if (getText().length() == 0) {
+ return EMPTY_DIMENSION.getCopy();
+ }
+ else {
+ Dimension textExtent = (Dimension) getFigureMapMode().DPtoLP(
+ FigureUtilities.getTextExtents(getText(), getFont()));
+ textExtent.height += getMapModeConstants().nDPtoLP_2 / 2;
+ return textExtent;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.draw2d.IFigure#getPreferredSize(int, int)
+ */
+ public Dimension getPreferredSize(int wHint, int hHint) {
+ if (prefSize == null || wHint != cached_PrefWidth
+ || hHint != cached_PrefHeight) {
+
+ if (getText().length() == 0)
+ return prefSize = EMPTY_DIMENSION.getCopy();
+
+ if (wHint < 0) {
+ prefSize = calculateLabelSize(getTextSize());
+
+ Insets insets = getInsets();
+ prefSize.expand(insets.getWidth(), insets.getHeight());
+
+ } else {
+ int _wHint = wHint;
+ switch (getTextPlacement()) {
+ case EAST:
+ case WEST:
+ _wHint -= (getTotalIconSize().width + getIconTextGap());
+ break;
+ }
+
+ prefSize = calculateLabelSize(getLayoutManager().getPreferredSize(this,
+ _wHint, hHint));
+
+ minSize = null;
+ prefSize.union(getMinimumSize(wHint, hHint));
+ cached_PrefWidth = wHint;
+ cached_PrefHeight = hHint;
+ }
+
+
+ }
+
+ return prefSize;
+ }
+
+ /**
+ * @see IFigure#getMinimumSize(int, int)
+ */
+ public Dimension getMinimumSize(int w, int h) {
+ if (minSize != null)
+ return minSize;
+
+ if (getText().length() == 0)
+ return minSize = EMPTY_DIMENSION.getCopy();
+
+ if (w < 0) {
+ minSize = calculateLabelSize(getTextSize());
+
+ Insets insets = getInsets();
+ minSize.expand(insets.getWidth(), insets.getHeight());
+ } else {
+ minSize = new Dimension();
+
+ int _wHint = w;
+ switch (getTextPlacement()) {
+ case EAST:
+ case WEST:
+ _wHint -= (getTotalIconSize().width + getIconTextGap());
+ break;
+ }
+
+ if (getLayoutManager() != null)
+ minSize.setSize(getLayoutManager().getMinimumSize(this, _wHint, h));
+
+ Dimension d = FlowUtilitiesEx.getEllipsisSize(textFlow.getFont(), getFigureMapMode()).
+ getIntersected(getTextSize());
+
+ Dimension labelSize = calculateLabelSize(d);
+
+ minSize.width = labelSize.width;
+
+ Insets insets = getInsets();
+ minSize.expand(insets.getWidth(), insets.getHeight());
+ }
+
+ return minSize;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.draw2d.Figure#getMaximumSize()
+ */
+ public Dimension getMaximumSize() {
+ return prefSize;
+ }
+
+ /**
+ * Get the maximum size, given width and height hints.
+ * (Note: defaults to getMaximumSize())
+ *
+ * + * @param w + * the width hint + * @param h + * the height hint + * @return the maximum size. + */ + public Dimension getMaximumSize(int w, int h) { + return getMaximumSize(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.draw2d.Label#calculateSubStringTextSize() + */ + protected Dimension calculateSubStringTextSize() { + return getSubStringTextSize(); + } + + /** + * Returns the total number of icons being displayed. + * + * @return int number of icons in the wrap label + */ + protected int getNumberofIcons() { + if (iconInfo == null) + return 0; + return iconInfo.getNumberofIcons(); + } + + /** + * getPlacement + * + * @param flagOffset + * @return PositionConstant representing the placement + */ + private int getPlacement(int flagOffset) { + int wrapValue = flags & (0x7 * flagOffset); + if (wrapValue == 0x1 * flagOffset) + return EAST; + else if (wrapValue == 0x2 * flagOffset) + return WEST; + else if (wrapValue == 0x3 * flagOffset) + return NORTH; + else if (wrapValue == 0x4 * flagOffset) + return SOUTH; + + return EAST; + } + + /* (non-Javadoc) + * @see org.eclipse.draw2d.Label#getText() + */ + public String getText() { + return textFlow.getText(); + } + + /** + * Returns the current alignment of the Label's text. The default text + * alignment is {@link PositionConstants#CENTER}. + * + * @return the text alignment + */ + public int getTextAlignment() { + return getAlignment(FLAG_TEXT_ALIGN); + } + + /** + * Returns the current placement of the label's text relative to its icon. + * The default text placement is {@link PositionConstants#EAST}. + * + * @return the text placement + */ + public int getTextPlacement() { + return getPlacement(FLAG_TEXT_PLACEMENT); + } + + /** + * Gets the horizontal alignment of the text (Left, Center or Right + * justified). + *
+ * Default is {@link PositionConstants#CENTER}. Can be either
+ * {@link PositionConstants#CENTER}, {@link PositionConstants#LEFT}, or
+ * {@link PositionConstants#RIGHT}.
+ *
+ * @return the horizontal alignment.
+ */
+ public int getTextHorizontalAlignment() {
+ return blockFlow.getHorizontalAligment();
+ }
+
+ /**
+ * getTotalIconSize Calculates the total union of icon sizes
+ *
+ * @return Dimension that is the union of icon sizes
+ */
+ protected Dimension getTotalIconSize() {
+ if (iconInfo == null)
+ return EMPTY_DIMENSION;
+ return iconInfo.getTotalIconSize(getFigureMapMode());
+ }
+
+ /**
+ * Returns true if the WrapLabel has focus, false otherwise.
+ *
+ * @return the focus state of this label
+ */
+ public boolean hasFocus() {
+ return textFlow.hasFocus();
+ }
+
+ /**
+ * Returns true if the WrapLabel has icons, false otherwise.
+ *
+ * @return
+ */
+ protected boolean hasIcons() {
+ return (getNumberofIcons() > 0);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.draw2d.Label#invalidate()
+ */
+ public void invalidate() {
+ clearLocations();
+ if (iconInfo != null)
+ iconInfo.invalidate();
+ super.invalidate();
+ }
+
+ public void validate() {
+ super.validate();
+ // calculateLocations();
+ }
+
+ /**
+ * @return the selection state of this label
+ */
+ public boolean isSelected() {
+ return textFlow.isSelected();
+ }
+
+ /**
+ * @return whether the label text is striked-through
+ */
+ public boolean isTextStrikedThrough() {
+ return textFlow.isTextStrikeThrough();
+ }
+
+ /**
+ * Returns true
if the label's text is currently truncated,
+ * false
otherwise.
+ *
+ * @return true
if the label's text is truncated
+ */
+ public boolean isTextTruncated() {
+ return (getBounds().width < textFlow.getBounds().width)
+ || (getBounds().height < textFlow.getBounds().height);
+ }
+
+ /**
+ * @return whether the label text is underlined
+ */
+ public boolean isTextUnderlined() {
+ return textFlow.isTextUnderlined();
+ }
+
+ /**
+ * @return wether the label text wrap is on
+ */
+ public boolean isTextWrapped() {
+ return (flags & FLAG_WRAP) != 0;
+ }
+
+ /**
+ * Determines the insertion points based on the Label Alignment.
+ * Note: should be called by calculateLocations only.
+ *
+ * + * @param textPlacement + * the placement of the text relative to the icon. + * @param totalIconSize + * the total size of all icons. + * @param totalPossibleSize + * the total possible size of icon(s) and text. + */ + private void layoutTextAndIcons(int textPlacement, Dimension totalIconSize, + Dimension totalPossibleSize) { + switch (getLabelAlignment()) { + case TOP: + calculateTextPlacement(new Point(0, 0), textPlacement, + totalIconSize); + break; + case BOTTOM: + calculateTextPlacement(new Point(0, getBounds().height + - totalPossibleSize.height), textPlacement, totalIconSize); + break; + case CENTER: // RIGHT and LEFT not supported. + case RIGHT: + case LEFT: + calculateTextPlacement(new Point(0, + (getBounds().height - totalPossibleSize.height) / 2), + textPlacement, totalIconSize); + break; + + /* the following commented lines of code obtain original functionality + * of label alignment but the code is buggy. To use, remove CENTER and RIGHT + * cases above and uncomment the lines below. + */ +// case RIGHT: +// calculateTextBounds(false); +// if (literalTextBounds == null || literalTextBounds.width == 0) { +// calculateTextPlacement(new Point( +// getBounds().width - totalPossibleSize.width, +// (getBounds().height - totalPossibleSize.height) / 2), +// textPlacement, totalIconSize); +// } else { +// Dimension _totalLabelSize = calculateLabelSize(literalTextBounds +// .getSize()); +// calculateTextPlacement(new Point( +// (getBounds().width - _totalLabelSize.width), +// (getBounds().height - _totalLabelSize.height) / 2), +// textPlacement, totalIconSize); +// } +// break; +// default: // CENTER +// calculateTextBounds(false); +// if (literalTextBounds == null || literalTextBounds.width == 0) { +// calculateTextPlacement(new Point( +// (getBounds().width - totalPossibleSize.width) / 2, +// (getBounds().height - totalPossibleSize.height) / 2), +// textPlacement, totalIconSize); +// } else { +// Dimension _totalLabelSize = calculateLabelSize(literalTextBounds +// .getSize()); +// calculateTextPlacement(new Point( +// (getBounds().width - _totalLabelSize.width) / 2, +// (getBounds().height - _totalLabelSize.height) / 2), +// textPlacement, totalIconSize); +// } + } + } + + /** + * @see Figure#paintFigure(Graphics) + */ + protected void paintFigure(Graphics graphics) { + if (isOpaque()) + super.paintFigure(graphics); + + if ((flags & FLAG_CALCULATE_LOCATIONS) != 0) { + calculateLocations(); + setFlag(FLAG_CALCULATE_LOCATIONS, false); + } + + if (hasIcons()) + paintIcons(graphics); + } + + /** + * Paints the icon(s) + * + * @param graphics + * The graphics context + */ + private void paintIcons(Graphics graphics) { + Rectangle figBounds = getBounds(); + graphics.translate(figBounds.x, figBounds.y); + + Point p = Point.SINGLETON; + p.setLocation(getIconLocation()); + + int num = getNumberofIcons(); + for (int i = 0; i < num; i++) { + Image tempIcon = getIcon(i); + if (tempIcon != null) { + graphics.drawImage(tempIcon, p); + p.x += getIconSize(i).width; + } + } + + graphics.translate(-figBounds.x, -figBounds.y); + } + + /** + * setAlignmentFlags + * + * @param align + * @param flagOffset + */ + private void setAlignmentFlags(int align, int flagOffset) { + flags &= ~(0x7 * flagOffset); + switch (align) { + case CENTER: + flags |= 0x1 * flagOffset; + break; + case TOP: + flags |= 0x2 * flagOffset; + break; + case LEFT: + flags |= 0x3 * flagOffset; + break; + case RIGHT: + flags |= 0x4 * flagOffset; + break; + case BOTTOM: + flags |= 0x5 * flagOffset; + break; + } + } + + /** + * Sets the focus state of this label + * + * @param b + * true will cause a focus rectangle to be drawn around the text + * of the Label + */ + public void setFocus(boolean b) { + textFlow.setFocus(b); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.draw2d.Figure#setFont(org.eclipse.swt.graphics.Font) + */ + public void setFont(Font f) { + super.setFont(f); + + /* + * Simply calling revalidate + * may not make textFlow an invalid figure and revalidate it. + * Therefore, when font is changed (e.g. size change, bold, italic), + * the layout manager for textFlow may not get invoked. + */ + textFlow.revalidate(); + } + + /** + * Sets the label's icon to the passed image. + * + * @param image + * the new label image + */ + public void setIcon(Image image) { + setIcon(image, 0); + } + + /** + * Sets the label's icon at given index + * + * @param image The icon image or null to remove the icon + * @param index The icon index + */ + public void setIcon(Image image, int index) { + if (iconInfo == null) { + if (index == 0) { + iconInfo = getMapModeConstants().getSingleIconInfo(image); + } else { + iconInfo = new MultiIconInfo(); + iconInfo.setIcon(image, index); + } + revalidate(); + repaint();// Call repaint, in case the image dimensions are the same. + } else if (iconInfo.getIcon(index) != image) { + if (iconInfo.getMaxIcons() == 1) { + if (index == 0) { + iconInfo = getMapModeConstants().getSingleIconInfo(image); + revalidate(); + repaint();// Call repaint, in case the image dimensions are the same. + return; + } + IconInfo oldIconInfo = iconInfo; + iconInfo = new MultiIconInfo(); + iconInfo.setIcon(oldIconInfo.getIcon(0), 0); + } + iconInfo.setIcon(image, index); + revalidate(); + repaint();// Call repaint, in case the image dimensions are the same. + } + } + + /** + * Sets the icon alignment relative to the text. The default is + * {@link PositionConstants#CENTER}. + *
+ * + * If the text placement is NORTH/SOUTH, icon alignment should be either + * LEFT, CENTER, or RIGHT to the icon. + *
+ * + * If the text placement is EAST/WEST, icon alignment should be either TOP, + * CENTER, or BOTTOM to the icon. + *
+ * + * @param align + * the icon alignment + */ + public void setIconAlignment(int align) { + if (getIconAlignment() == align) + return; + setAlignmentFlags(align, FLAG_ICON_ALIGN); + revalidate(); + repaint(); + } + + /** + * Sets the Label's alignment to the passed value. The default is + * {@link PositionConstants#TOP}. Other possible values are + * {@link PositionConstants#CENTER},{@link PositionConstants#BOTTOM}. + *
+ * Note:{@link PositionConstants#LEFT} and {@link PositionConstants#RIGHT} + * are not supported as wrap label occupies the entire client area. Use + * horizontal alignment instead (see WrapLabel#setHorizontalAlignment(int)). + *
+ * + * @param align + * label alignment + */ + public void setLabelAlignment(int align) { + if (getLabelAlignment() == align) + return; + + setAlignmentFlags(align, FLAG_LABEL_ALIGN); + + revalidate(); + repaint(); + } + + /** + * setPlacementFlags + * + * @param align + * @param flagOffset + */ + private void setPlacementFlags(int align, int flagOffset) { + flags &= ~(0x7 * flagOffset); + switch (align) { + case EAST: + flags |= 0x1 * flagOffset; + break; + case WEST: + flags |= 0x2 * flagOffset; + break; + case NORTH: + flags |= 0x3 * flagOffset; + break; + case SOUTH: + flags |= 0x4 * flagOffset; + break; + } + } + + /** + * Sets the selection state of this label + * + * @param b + * true will cause the label to appear selected + */ + public void setSelected(boolean b) { + textFlow.setSelected(b); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.draw2d.Label#setText(java.lang.String) + */ + public void setText(String s) { + if (s == null) + s = "";//$NON-NLS-1$ + if (getText().equals(s)) + return; + textFlow.setText(s); + revalidate(); + repaint(); + } + + /** + * Sets the text alignment of the text relative to the icon. The default is + * {@link PositionConstants#CENTER}. + *
+ * + * If the text placement is NORTH/SOUTH, text alignment should be either + * LEFT, CENTER, or RIGHT to the icon. + *
+ * + * If the text placement is EAST/WEST, text alignment should be either TOP, + * CENTER, or BOTTOM to the icon. + * + * @param align + * the text alignment + */ + public void setTextAlignment(int align) { + if (getTextAlignment() == align) + return; + setAlignmentFlags(align, FLAG_TEXT_ALIGN); + revalidate(); + repaint(); + } + + /** + * Sets the text placement of the label relative to its icon. The default is + * {@link PositionConstants#EAST}. Other possible values are + * {@link PositionConstants#NORTH},{@link PositionConstants#SOUTH}and + * {@link PositionConstants#WEST}.
+ * + * e.g. PositionConstants#EAST indicates the text is on the east of the icon.
+ * + * @param where + * the text placement + */ + public void setTextPlacement(int where) { + if (getTextPlacement() == where) + return; + setPlacementFlags(where, FLAG_TEXT_PLACEMENT); + revalidate(); + repaint(); + } + + /** + * Sets whether the label text should be striked-through + * + * @param b + * Whether the label text should be striked-through + */ + public void setTextStrikeThrough(boolean b) { + textFlow.setStrikeThrough(b); + } + + /** + * Sets whether the label text should be underlined + * + * @param b + * Whether the label text should be underlined + */ + public void setTextUnderline(boolean b) { + textFlow.setTextUnderline(b); + } + + /** + * Sets up the flow page, block flow and text flow figures + * with appropriate wrapping layouts.
+ * + * @param enableWrapping set to true if wrapping should be enabled. + */ + private void setupTextFigures(boolean enableWrapping) { + + String oldText = ""; //$NON-NLS-1$ + + int oldTextHorizontalAlignment = CENTER; + + if (textFlow != null) { + oldText = textFlow.getText(); + oldTextHorizontalAlignment = blockFlow.getHorizontalAligment(); + remove(flowPage); + } + + flowPage = new FlowPage(); + blockFlow = new BlockFlow(); + textFlow = new SelectableTextFlow(); + + flowPage.setLayoutManager(new PageFlowLayout(flowPage)); + blockFlow.setLayoutManager(new BlockFlowLayout(blockFlow)); + + if (enableWrapping) { + textFlow.setLayoutManager(new ParagraphTextLayoutEx(textFlow, + ParagraphTextLayoutEx.WORD_WRAP_SOFT)); + } else { + textFlow.setLayoutManager(new SingleLineTextLayoutWithEllipses(textFlow)); + } + + blockFlow.add(textFlow); + flowPage.add(blockFlow); + add(flowPage); + + textFlow.setText(oldText); + setTextHorizontalAlignment(oldTextHorizontalAlignment); + } + + /** + * Sets whether the label text should wrap + * + * @param b + * whether the label text should wrap + */ + public void setTextWrap(boolean b) { + if (isTextWrapped() == b) + return; + setFlag(FLAG_WRAP, b); + + setupTextFigures(b); + + revalidate(); + repaint(); + } + + /** + * Sets the horizontal alignment of the label text. The default is + * {@link PositionConstants#CENTER}. + *
+ * + * It can be either {@link PositionConstants#LEFT}, + * {@link PositionConstants#CENTER}, or {@link PositionConstants#RIGHT} + *
+ * + * @param i + * the horizontal alignment. + */ + public void setTextHorizontalAlignment(int i) { + blockFlow.setHorizontalAligment(i); + + revalidate(); + repaint(); + } + + /** + * Obtains the text offset the caret should be placed given + * the location in absolute coordinates. + * @param location where the caret should be placed in + * absolute pixel coordinates + * @return text offset + */ + public int getCaretOffset(Point location) { + Rectangle _textBounds = getTextBounds().getCopy(); + translateToAbsolute(_textBounds); + + if (!_textBounds.contains(location)) + return -1; + + return textFlow.getCaretOffset(location); + } +} Index: src/org/eclipse/gmf/runtime/draw2d/ui/internal/text/SingleLineTextLayoutWithEllipses.java =================================================================== RCS file: src/org/eclipse/gmf/runtime/draw2d/ui/internal/text/SingleLineTextLayoutWithEllipses.java diff -N src/org/eclipse/gmf/runtime/draw2d/ui/internal/text/SingleLineTextLayoutWithEllipses.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/gmf/runtime/draw2d/ui/internal/text/SingleLineTextLayoutWithEllipses.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,160 @@ +/****************************************************************************** + * Copyright (c) 2006 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.draw2d.ui.internal.text; + +import java.util.List; + +import org.eclipse.draw2d.text.TextFlow; +import org.eclipse.draw2d.text.TextFragmentBox; +import org.eclipse.gmf.runtime.draw2d.ui.mapmode.IMapMode; +import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil; +import org.eclipse.swt.graphics.Font; + +/** + * A text layout that does not wrap words but inserts ellipses to + * truncated text. + * @author satif + * + */ +public class SingleLineTextLayoutWithEllipses + extends org.eclipse.draw2d.text.TextLayout + implements TextLayoutManagerWithMapMode { + + private static final String[] DELIMITERS = {"\r\n", //$NON-NLS-1$ + "\n", //$NON-NLS-1$ + "\r"};//$NON-NLS-1$ + + private static int result; + + private static int delimeterLength; + + private IMapMode mm = MapModeUtil.getMapMode(); + + /* (non-Javadoc) + * @see org.eclipse.gmf.runtime.draw2d.ui.internal.text.TextLayoutManagerWithMapMode#setMapMode(org.eclipse.gmf.runtime.draw2d.ui.mapmode.IMapMode) + */ + public void setMapMode(IMapMode mm) { + this.mm = mm; + } + + /** + * Creates a new SimpleTextLayout with the given TextFlow + * + * @param flow + * the TextFlow + */ + public SingleLineTextLayoutWithEllipses(TextFlow flow) { + super(flow); + } + + private int nextLineBreak(String text, int offset) { + result = text.length(); + delimeterLength = 0; + int current; + for (int i = 0; i < DELIMITERS.length; i++) { + current = text.indexOf(DELIMITERS[i], offset); + if (current != -1 && current < result) { + result = current; + delimeterLength = DELIMITERS[i].length(); + } + } + return result; + } + + /** + * @see org.eclipse.draw2d.text.FlowFigureLayout#layout() + */ + protected void layout() { + TextFlow textFlow = (TextFlow) getFlowFigure(); + String text = textFlow.getText(); + List fragments = textFlow.getFragments(); + Font font = textFlow.getFont(); + TextFragmentBox fragment; + int i = 0; + int offset = 0; + int ellipsesSize = FlowUtilitiesEx.getEllipsisSize(font, mm).width; + + do { + nextLineBreak(text, offset); + fragment = getFragment(i++, fragments); + fragment.length = result - offset; + fragment.offset = offset; + fragment.setWidth(-1); + fragment.setTruncated(false); + FlowUtilitiesEx.setupFragment(fragment, font, text, mm); + + int remainingLineWidth = getContext().getRemainingLineWidth(); + + // if the text is truncated... + + if (remainingLineWidth > 0 + && remainingLineWidth < fragment.getWidth()) { + + // estimate the length of the string just before we add the + // ellipses... + + remainingLineWidth -= ellipsesSize; + + if (remainingLineWidth <= 0) + break; + + fragment.setTruncated(true); + + // we estimate the length of the fragment by using average + // character + // width then +/- as required. This drastically increases + // the speed. + + int min = (int) (remainingLineWidth / FlowUtilitiesEx.getAverageCharWidth( + fragment, font, mm)); + + fragment.length = min; + fragment.setWidth(-1); + FlowUtilitiesEx.setupFragment(fragment, font, text, mm); + int dimensionX = fragment.getWidth(); + + int maxLength = text.length() - offset; + while (dimensionX < remainingLineWidth) { + min++; + if (min > maxLength) + break; + + fragment.length = min; + fragment.setWidth(-1); + FlowUtilitiesEx.setupFragment(fragment, font, text, + mm); + dimensionX = fragment.getWidth(); + } + + while (dimensionX > remainingLineWidth) { + min--; + if (min <= 0) + break; + + fragment.length = min; + fragment.setWidth(-1); + FlowUtilitiesEx.setupFragment(fragment, font, text, + mm); + dimensionX = fragment.getWidth(); + } + } else + fragment.setTruncated(false); + + getContext().addToCurrentLine(fragment); + getContext().endLine(); + offset = result + delimeterLength; + } while (offset < text.length()); + // Remove the remaining unused fragments. + while (i < fragments.size()) + fragments.remove(i++); + } +} Index: src/org/eclipse/gmf/runtime/draw2d/ui/internal/text/TextLayoutManagerWithMapMode.java =================================================================== RCS file: src/org/eclipse/gmf/runtime/draw2d/ui/internal/text/TextLayoutManagerWithMapMode.java diff -N src/org/eclipse/gmf/runtime/draw2d/ui/internal/text/TextLayoutManagerWithMapMode.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/gmf/runtime/draw2d/ui/internal/text/TextLayoutManagerWithMapMode.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,36 @@ +/****************************************************************************** + * Copyright (c) 2006 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.draw2d.ui.internal.text; + +import org.eclipse.draw2d.LayoutManager; +import org.eclipse.gmf.runtime.draw2d.ui.mapmode.IMapMode; +import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil; + +/** + * Interface for text layout managers to use map mode. + * @author satif + * + */ +public interface TextLayoutManagerWithMapMode + extends LayoutManager { + + /** Set the map mode to use within this text layout + * manager.
+ * + * Default map mode should be the one given by + * MapModeUtil.getMapMode() but may also depend on + * the specific implementation of the text layout manager. + * + * @param mm the map mode to set. + */ + public void setMapMode(IMapMode mm); +} Index: src/org/eclipse/gmf/runtime/draw2d/ui/internal/text/FlowUtilitiesEx.java =================================================================== RCS file: src/org/eclipse/gmf/runtime/draw2d/ui/internal/text/FlowUtilitiesEx.java diff -N src/org/eclipse/gmf/runtime/draw2d/ui/internal/text/FlowUtilitiesEx.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/gmf/runtime/draw2d/ui/internal/text/FlowUtilitiesEx.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,360 @@ +/****************************************************************************** + * Copyright (c) 2006 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.draw2d.ui.internal.text; + + +import org.eclipse.draw2d.FigureUtilities; +import org.eclipse.draw2d.geometry.Dimension; +import org.eclipse.draw2d.text.FlowContext; +import org.eclipse.draw2d.text.FlowUtilities; +import org.eclipse.draw2d.text.ParagraphTextLayout; +import org.eclipse.draw2d.text.TextFragmentBox; +import org.eclipse.gmf.runtime.draw2d.ui.mapmode.IMapMode; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.TextLayout; + +import com.ibm.icu.text.BreakIterator; + +/** + * This class is a direct copy from Draw2D's FlowUtilities but with map mode + * functionality. + * @author satif + */ +public class FlowUtilitiesEx + extends FlowUtilities { + + public static final String ELLIPSIS = "..."; //$NON-NLS-1$ + + private static final BreakIterator INTERNAL_LINE_BREAK = BreakIterator + .getLineInstance(); + + + /** + * Get the ellipses text size given the font and the map mode. + * @param font the font to measure the ellipses size. + * @param mm the map mode the fragment will be in. + * @return the width of the ellipses + */ + public static Dimension getEllipsisSize(Font font, IMapMode mm) { + return (Dimension)mm + .DPtoLP(FigureUtilities.getStringExtents(ELLIPSIS, font)); + } + + /** + * Gets the average character width. + * + * @param fragment the supplied TextFragmentBox to use for calculation. + * if the length is 0 or if the width is or below 0, + * the average character width is taken from standard + * font metrics. + * @param font the font to use incase the TextFragmentBox conditions + * above are true. + * @param mm the map mode the fragment will be in. + * @return the average character width + */ + public static float getAverageCharWidth(TextFragmentBox fragment, + Font font, IMapMode mm) { + if (fragment.getWidth() > 0 && fragment.length != 0) + return fragment.getWidth() / (float) fragment.length; + return mm.DPtoLP(getFontMetrics(font).getAverageCharWidth()); + } + + /** + * Measures the width of the supplied (sub)string.
+ * + * @param frag the supplied TextFragmentBox (needed to check + * if it uses BiDi). + * @param string the String to measure. + * @param guess the length of the supplied String to measure. + * @param font the font the fragment will use. + * @param mm the map mode the fragment will be in. + * @return the width of the supplied String + */ + public static int measureString(TextFragmentBox frag, String string, + int guess, Font font, IMapMode mm) { + if (frag.requiresBidi()) { + // The text and/or could have changed if the lookAhead was invoked. + // This will + // happen at most once. + TextLayout _layout = getTextLayout(); + _layout.setText(string); + _layout.setFont(font); + return mm.DPtoLP(_layout.getBounds(0, guess - 1).width); + } else + return mm.DPtoLP(getStringDimension(string.substring(0, guess), + font).x); + } + + /** + * Sets up the fragment's width according to BiDi and truncation + * given all the parameters and the fields in the supplied fragment.
+ * + * @param frag the supplied TextFragmentBox + * @param f the font the fragment will use. + * @param s the string the fragment will use. + * @param mm the map mode the fragment will be in. + */ + public static void setupFragment(TextFragmentBox frag, Font f, String s, + IMapMode mm) { + if (frag.getWidth() == -1 || frag.isTruncated()) { + int width; + if (s.length() == 0 || frag.length == 0) + width = 0; + else if (frag.requiresBidi()) { + TextLayout textLayout = getTextLayout(); + textLayout.setFont(f); + textLayout.setText(s); + width = mm + .DPtoLP(textLayout.getBounds(0, frag.length - 1).width); + } else + width = mm.DPtoLP(getStringDimension(s + .substring(0, frag.length), f).x); + if (frag.isTruncated()) + width += getEllipsisSize(f, mm).width; + frag.setWidth(width); + } + } + + /** + * Sets up a fragment and returns the number of characters consumed from the + * given String. An average character width can be provided as a hint for + * faster calculation. If a fragment's bidi level is set, a TextLayout will + * be used to calculate the width. + * + * @param frag + * the TextFragmentBox + * @param string + * the String + * @param font + * the Font used for measuring + * @param context + * the flow context + * @param wrapping + * the word wrap style + * @return the number of characters that will fit in the given space; can be + * 0 (eg., when the first character of the given string is a + * newline) + */ + public static int wrapFragmentInContext(TextFragmentBox frag, + String string, FlowContext context, LookAhead lookahead, Font font, + int wrapping, IMapMode mm) { + frag.setTruncated(false); + int strLen = string.length(); + if (strLen == 0) { + frag.setWidth(-1); + frag.length = 0; + setupFragment(frag, font, string, mm); + context.addToCurrentLine(frag); + return 0; + } + + INTERNAL_LINE_BREAK.setText(string); + + initBidi(frag, string, font); + float avgCharWidth = getAverageCharWidth(frag, font, mm); + frag.setWidth(-1); + + /* + * Setup initial boundaries within the string. + */ + int absoluteMin = 0; + int max, min = 1; + if (wrapping == ParagraphTextLayout.WORD_WRAP_HARD) { + absoluteMin = INTERNAL_LINE_BREAK.next(); + while (absoluteMin > 0 + && Character.isWhitespace(string.charAt(absoluteMin - 1))) + absoluteMin--; + min = Math.max(absoluteMin, 1); + } + int firstDelimiter = findFirstDelimeter(string); + if (firstDelimiter == 0) + min = max = 0; + else + max = Math.min(strLen, firstDelimiter) + 1; + + int availableWidth = context.getRemainingLineWidth(); + int guess = 0, guessSize = 0; + + while (true) { + if ((max - min) <= 1) { + if (min == absoluteMin + && context.isCurrentLineOccupied() + && !context.getContinueOnSameLine() + && availableWidth < measureString(frag, string, min, font, + mm) + + ((min == strLen && lookahead != null) ? lookahead + .getWidth() + : 0)) { + context.endLine(); + availableWidth = context.getRemainingLineWidth(); + max = Math.min(strLen, firstDelimiter) + 1; + if ((max - min) <= 1) + break; + } else + break; + } + // Pick a new guess size + // New guess is the last guess plus the missing width in pixels + // divided by the average character size in pixels + guess += 0.5f + (availableWidth - guessSize) / avgCharWidth; + + if (guess >= max) + guess = max - 1; + if (guess <= min) + guess = min + 1; + + guessSize = measureString(frag, string, guess, font, mm); + + if (guess == strLen && lookahead != null + && !canBreakAfter(string.charAt(strLen - 1)) + && guessSize + lookahead.getWidth() > availableWidth) { + max = guess; + continue; + } + + if (guessSize <= availableWidth) { + min = guess; + frag.setWidth(guessSize); + if (guessSize == availableWidth) + max = guess + 1; + } else + max = guess; + } + + int result = min; + boolean continueOnLine = false; + if (min == strLen) { + // Everything fits + if (string.charAt(strLen - 1) == ' ') { + if (frag.getWidth() == -1) { + frag.length = result; + frag + .setWidth(measureString(frag, string, result, font, mm)); + } + if (lookahead.getWidth() > availableWidth - frag.getWidth()) { + frag.length = result - 1; + frag.setWidth(-1); + } else + frag.length = result; + } else { + continueOnLine = !canBreakAfter(string.charAt(strLen - 1)); + frag.length = result; + } + } else if (min == firstDelimiter) { + // move result past the delimiter + frag.length = result; + if (string.charAt(min) == '\r') { + result++; + if (++min < strLen && string.charAt(min) == '\n') + result++; + } else if (string.charAt(min) == '\n') + result++; + } else if (string.charAt(min) == ' ' + || canBreakAfter(string.charAt(min - 1)) + || INTERNAL_LINE_BREAK.isBoundary(min)) { + frag.length = min; + if (string.charAt(min) == ' ') + result++; + else if (string.charAt(min - 1) == ' ') { + frag.length--; + frag.setWidth(-1); + } + } else + out: { + // In the middle of an unbreakable offset + result = INTERNAL_LINE_BREAK.preceding(min); + if (result == 0) { + switch (wrapping) { + case ParagraphTextLayout.WORD_WRAP_TRUNCATE: + int truncatedWidth = availableWidth - getEllipsisSize(font, mm).width; + if (truncatedWidth > 0) { + // $TODO this is very slow. It should be using + // avgCharWidth to go faster + while (min > 0) { + guessSize = measureString(frag, string, + min, font, mm); + if (guessSize <= truncatedWidth) + break; + min--; + } + frag.length = min; + } else + frag.length = 0; + frag.setTruncated(true); + result = INTERNAL_LINE_BREAK.following(max - 1); + break out; + + default: + result = min; + break; + } + } + frag.length = result; + if (string.charAt(result - 1) == ' ') + frag.length--; + frag.setWidth(-1); + } + + setupFragment(frag, font, string, mm); + context.addToCurrentLine(frag); + context.setContinueOnSameLine(continueOnLine); + return result; + } + + public static void setupEllipses(TextFragmentBox fragment, String text, + int remainingLineWidth, Font font, IMapMode mm) { + remainingLineWidth -= getEllipsisSize(font, mm).width; + + if (remainingLineWidth <= 0) + return; + + fragment.setTruncated(true); + + // we estimate the length of the fragment by using average + // character + // width then +/- as required. This drastically increases + // the speed. + + int min = (int) (remainingLineWidth / FlowUtilitiesEx.getAverageCharWidth( + fragment, font, mm)); + + fragment.length = min; + fragment.setWidth(-1); + FlowUtilitiesEx.setupFragment(fragment, font, text, mm); + int dimensionX = fragment.getWidth(); + + int maxLength = text.length() - fragment.offset; + while (dimensionX < remainingLineWidth) { + min++; + if (min > maxLength) + break; + + fragment.length = min; + fragment.setWidth(-1); + FlowUtilitiesEx.setupFragment(fragment, font, text, + mm); + dimensionX = fragment.getWidth(); + } + + while (dimensionX > remainingLineWidth) { + min--; + if (min <= 0) + break; + + fragment.length = min; + fragment.setWidth(-1); + FlowUtilitiesEx.setupFragment(fragment, font, text, + mm); + dimensionX = fragment.getWidth(); + } + } +} Index: src/org/eclipse/gmf/runtime/draw2d/ui/internal/text/ParagraphTextLayoutEx.java =================================================================== RCS file: src/org/eclipse/gmf/runtime/draw2d/ui/internal/text/ParagraphTextLayoutEx.java diff -N src/org/eclipse/gmf/runtime/draw2d/ui/internal/text/ParagraphTextLayoutEx.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/gmf/runtime/draw2d/ui/internal/text/ParagraphTextLayoutEx.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,240 @@ +/****************************************************************************** + * Copyright (c) 2006 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.draw2d.ui.internal.text; + +import java.util.List; + +import org.eclipse.draw2d.text.FlowBorder; +import org.eclipse.draw2d.text.FlowContext; +import org.eclipse.draw2d.text.FlowFigure; +import org.eclipse.draw2d.text.ParagraphTextLayout; +import org.eclipse.draw2d.text.TextFlow; +import org.eclipse.draw2d.text.TextFragmentBox; +import org.eclipse.draw2d.text.FlowUtilities.LookAhead; +import org.eclipse.gmf.runtime.draw2d.ui.mapmode.IMapMode; +import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil; +import org.eclipse.swt.graphics.Font; + +/** + * An extended Paragraph Text layout that considers map mode. + * @author satif + * + */ +public class ParagraphTextLayoutEx + extends ParagraphTextLayout + implements TextLayoutManagerWithMapMode { + + private IMapMode mm = MapModeUtil.getMapMode(); + + + /** + * Note: This method is a direct copy from + * org.eclipse.draw2d.text.ParagraphTextLayout
+ * + * Given the Bidi levels of the given text, this method breaks the given + * text up by its level runs. + * + * @param text + * the String that needs to be broken up into its level runs + * @param levelInfo + * the Bidi levels + * @return the requested segment + */ + private String[] getSegments(String text, int levelInfo[]) { + if (levelInfo.length == 1) + return new String[] {text}; + + String result[] = new String[levelInfo.length / 2 + 1]; + + int i; + int endOffset; + int beginOffset = 0; + + for (i = 0; i < result.length - 1; i++) { + endOffset = levelInfo[i * 2 + 1]; + result[i] = text.substring(beginOffset, endOffset); + beginOffset = endOffset; + } + endOffset = text.length(); + result[i] = text.substring(beginOffset, endOffset); + return result; + } + + /** + * Note: This class is a direct copy from ParagraphTextLayout + */ + class SegmentLookahead + implements LookAhead { + + private int seg = -1; + + private String segs[]; + + private int[] width; + + private final int trailingBorderSize; + + private FlowContext context; + + private FlowFigure flowFigure; + + public SegmentLookahead(String segs[], int trailingBorderSize, + FlowContext context, FlowFigure flowFigure) { + this.segs = segs; + this.trailingBorderSize = trailingBorderSize; + this.context = context; + this.flowFigure = flowFigure; + } + + public int getWidth() { + if (width == null) { + width = new int[1]; + int startingIndex = seg + 1; + TextFlow textFlow = (TextFlow) flowFigure; + + if (startingIndex == segs.length) { + width[0] += trailingBorderSize; + context.getWidthLookahead(textFlow, width); + } else { + String rest = segs[startingIndex]; + for (int k = startingIndex + 1; k < segs.length; k++) + rest += segs[k]; + if (!textFlow.addLeadingWordWidth(rest, width)) { + width[0] += trailingBorderSize; + context.getWidthLookahead(textFlow, width); + } + } + } + return width[0]; + } + + public void setIndex(int value) { + this.seg = value; + width = null; + } + } + + /** + * Note: This method is a direct copy from + * org.eclipse.draw2d.text.ParagraphTextLayout but takes into account + * the map mode and uses methods from FlowUtilitiesEx
+ */ + protected void layout() { + TextFlow textFlow = (TextFlow) getFlowFigure(); + int offset = 0; + + FlowContext context = getContext(); + List fragments = textFlow.getFragments(); + Font font = textFlow.getFont(); + int fragIndex = 0; + int advance = 0; + + TextFragmentBox fragment; + int levelInfo[] = (textFlow.getBidiInfo() == null) ? new int[] {-1} + : textFlow.getBidiInfo().levelInfo; + + String segment, segments[] = getSegments(textFlow.getText(), + levelInfo); + FlowBorder border = null; + if (textFlow.getBorder() instanceof FlowBorder) + border = (FlowBorder) textFlow.getBorder(); + + SegmentLookahead lookahead = new SegmentLookahead( + segments, border == null ? 0 + : mm.DPtoLP(border.getRightMargin()), getContext(), + getFlowFigure()); + int seg; + + if (border != null) { + fragment = getFragment(fragIndex++, fragments); + fragment.setBidiLevel(levelInfo[0]); + fragment.setTruncated(false); + fragment.offset = fragment.length = -1; + fragment.setWidth(mm.DPtoLP(border.getLeftMargin()) + + mm.DPtoLP(border.getInsets(textFlow).left)); + if (context.getRemainingLineWidth() < fragment.getWidth() + + lookahead.getWidth()) + context.endLine(); + context.addToCurrentLine(fragment); + } + + for (seg = 0; seg < segments.length; seg++) { + segment = segments[seg]; + lookahead.setIndex(seg); + + do { + fragment = getFragment(fragIndex++, fragments); + + fragment.offset = offset; + fragment.setBidiLevel(levelInfo[seg * 2]); + + advance = FlowUtilitiesEx.wrapFragmentInContext(fragment, + segment, context, lookahead, font, getWrappingStyle(), mm); + segment = segment.substring(advance); + offset += advance; + if ((segment.length() > 0 || fragment.length < advance) + || fragment.isTruncated()) + context.endLine(); + } while (segment.length() > 0 + || (!fragment.isTruncated() && fragment.length < advance)); + } + + if (border != null) { + fragment = getFragment(fragIndex++, fragments); + fragment.setBidiLevel(levelInfo[0]); + fragment.setTruncated(false); + fragment.offset = fragment.length = -1; + fragment.setWidth(mm.DPtoLP(border.getRightMargin()) + + mm.DPtoLP(border.getInsets(textFlow).right)); + context.addToCurrentLine(fragment); + } + + // Remove the remaining unused fragments. + while (fragIndex < fragments.size()) + fragments.remove(fragments.size() - 1); + } + + /* (non-Javadoc) + * @see org.eclipse.gmf.runtime.draw2d.ui.internal.text.TextLayoutManagerWithMapMode#setMapMode(org.eclipse.gmf.runtime.draw2d.ui.mapmode.IMapMode) + */ + public void setMapMode(IMapMode mm) { + this.mm = mm; + } + + /** + * Constructs a new ParagraphTextLayout on the specified TextFlow. + * + * @param flow + * the TextFlow + */ + public ParagraphTextLayoutEx(TextFlow flow) { + super(flow); + } + + /** + * Constructs the layout with the specified TextFlow and wrapping style. + * The wrapping style must be one of: + *
+ * + * @see org.eclipse.draw2d.text.TextFlow#addLeadingWordWidth(java.lang.String, int[]) + */ + public boolean addLeadingWordWidth(String text, int[] width) { + if (text.length() == 0) + return false; + if (Character.isWhitespace(text.charAt(0))) + return true; + + text = 'a' + text + 'a'; + FlowUtilitiesEx.LINE_BREAK.setText(text); + int index = FlowUtilitiesEx.LINE_BREAK.next() - 1; + if (index == 0) + return true; + while (Character.isWhitespace(text.charAt(index))) + index--; + boolean result = index < text.length() - 1; + // index should point to the end of the actual text (not including the + // 'a' that was + // appended), if there were no breaks + if (index == text.length() - 1) + index--; + text = text.substring(1, index + 1); + + if (getBidiInfo() == null) + width[0] += FlowUtilitiesEx.getStringExtents(text, getFont()).width; + else { + TextLayout textLayout = FlowUtilitiesEx.getTextLayout(); + textLayout.setFont(getFont()); + textLayout.setText(text); + width[0] += textLayout.getBounds().width; + } + return result; + } + + /** + * Calculates literal_SubstringTextBounds. + * This is the literal bounds of the text excluding any extra space occupied + * by the TextFlow. These bounds are like the union of all fragments. + */ + private void calculateBounds() { + if (literal_SubstringTextBounds != null) + return; + + List list = getFragments(); + TextFragmentBox box; + int left = Integer.MAX_VALUE, top = left; + int right = Integer.MIN_VALUE, bottom = right; + + for (int i = 0; i < list.size(); i++) { + box = (TextFragmentBox) list.get(i); + left = Math.min(left, box.getX()); + + // The +2 is for leading characters... + right = Math.max(right, box.getX() + box.getWidth() + nDPtoLP_2); + + top = Math.min(top, box.getLineRoot().getVisibleTop()); + bottom = Math.max(bottom, box.getLineRoot().getVisibleBottom()); + } + if (literal_SubstringTextBounds == null) + literal_SubstringTextBounds = new Rectangle(left, top, + right - left, bottom - top); + else { + literal_SubstringTextBounds.x = left; + literal_SubstringTextBounds.y = top; + literal_SubstringTextBounds.width = right - left; + literal_SubstringTextBounds.height = bottom - top; + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.draw2d.text.TextFlow#getAscent() + */ + public int getAscent() { + return mm.DPtoLP(super.getAscent()); + } + + /** + * Note: this method is directly copied from + * org.eclipse.draw2d.text.TextFlow
+ * + * @param box + * which fragment + * @param index + * the fragment index + * @return the bidi string for that fragment + */ + private String getBidiSubstring(TextFragmentBox box, int index) { + if (box.getBidiLevel() < 1) + return getText().substring(box.offset, box.offset + box.length); + + StringBuffer buffer = new StringBuffer(box.length + 3); + buffer.append(box.isRightToLeft() ? BidiChars.RLO + : BidiChars.LRO); + if (index == 0 && getBidiInfo().leadingJoiner) + buffer.append(BidiChars.ZWJ); + buffer.append(getText().substring(box.offset, box.offset + box.length)); + if (index == getFragments().size() - 1 && getBidiInfo().trailingJoiner) + buffer.append(BidiChars.ZWJ); + return buffer.toString(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.draw2d.text.TextFlow#getDescent() + */ + public int getDescent() { + return mm.DPtoLP(super.getDescent()); + } + + /** + * Returns the bounds of visible text. + * + * @return Rectangle bounds of visible text. + */ + public Rectangle getLiteralSubstringTextBounds() { + calculateBounds(); + return literal_SubstringTextBounds; + } + + /** + * Note: this method is directly copied from + * org.eclipse.draw2d.text.TextFlow + */ + private int getBidiPrefixLength(TextFragmentBox box, int index) { + if (box.getBidiLevel() < 1) + return 0; + if (index > 0 || !getBidiInfo().leadingJoiner) + return 1; + return 2; + } + + /** + * Note: this method is directly copied from + * org.eclipse.draw2d.text.TextFlow but takes into account + * the map mode and uses methods from FlowUtilitiesEx
+ * + * @see org.eclipse.draw2d.text.TextFlow#getPointInBox(org.eclipse.draw2d.text.TextFragmentBox, + * int, int, boolean) + */ + protected Point getPointInBox(TextFragmentBox box, int offset, int index, + boolean trailing) { + offset -= box.offset; + offset = Math.min(box.length, offset); + Point result = new Point(0, box.getBaseline() - box.getAscent()); + if (getBidiInfo() == null) { + if (trailing && offset < box.length) + offset++; + String substring = getText().substring(box.offset, box.offset + offset); + result.x = mm.DPtoLP(FigureUtilities.getStringExtents( + substring, getFont()).width); + } else { + TextLayout layout = FlowUtilitiesEx.getTextLayout(); + layout.setFont(getFont()); + String fragString = getBidiSubstring(box, index); + layout.setText(fragString); + offset += getBidiPrefixLength(box, index); + result.x = layout.getLocation(offset, trailing).x; + if (isMirrored()) + result.x = box.getWidth() - result.x; + } + result.x += box.getX(); + return result; + } + + /** + * @return the focus state of this label + */ + public boolean hasFocus() { + return (flags & FLAG_HASFOCUS) != 0; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.draw2d.Figure#invalidate() + */ + public void invalidate() { + super.invalidate(); + literal_SubstringTextBounds = null; + } + + /** + * @return the selection state of this label + */ + public boolean isSelected() { + return (flags & FLAG_SELECTED) != 0; + } + + /** + * @return whether the label text is striked-through + */ + public boolean isTextStrikeThrough() { + return (flags & FLAG_STRIKEDTHROUGH) != 0; + } + + /** + * @return whether the label text is underlined + */ + public boolean isTextUnderlined() { + return (flags & FLAG_UNDERLINED) != 0; + } + + /** + * @see org.eclipse.draw2d.Figure#paintFigure(Graphics) + */ + protected void paintFigure(Graphics g) { + TextFragmentBox frag; + g.getClip(Rectangle.SINGLETON); + int yStart = Rectangle.SINGLETON.y; + int yEnd = Rectangle.SINGLETON.bottom(); + + int i; + + // first we calculate the literal size of the visible text and do the + // selection painting (note we have to do this loop, cannot merge + // it in the next one). + calculateBounds(); + + // draw the selection background, if applicable... + if (isSelected()) { + g.pushState(); + g.setBackgroundColor(ColorConstants.menuBackgroundSelected); + g.fillRectangle(literal_SubstringTextBounds); + g.popState(); + g.setForegroundColor(ColorConstants.white); + } else + g.setForegroundColor(getForegroundColor()); + + // draw the focus rectangle, if applicable... + if (hasFocus()) { + // focus drawing is done manually, as g.drawFocus gives + // incorrect results in this case. + g.pushState(); + g.setXORMode(true); + g.setLineWidth(0); + g.setLineStyle(SWT.LINE_DOT); + g.setLineDash(new int[] {1, 2}); + g.drawRectangle(literal_SubstringTextBounds.getCopy() + .resize(-1, -1)); + g.popState(); + + // restore line dash as it is not restored on pop + g.setLineDash(new int[] {}); + } + + ///////////////////////////////////////////////////////////////////////// + // START: Copy from org.eclipse.draw2d.text.TextFlow#paintFigure //////// + + for (i = 0; i < getFragments().size(); i++) { + frag = (TextFragmentBox) getFragments().get(i); + // g.drawLine(frag.getX(), frag.getLineRoot().getVisibleTop(), + // frag.getWidth() + frag.getX(), frag.getLineRoot().getVisibleTop()); + // g.drawLine(frag.getX(), frag.getBaseline(), frag.getWidth() + frag.getX(), frag.getBaseline()); + if (frag.offset == -1) + continue; + // Loop until first visible fragment + if (yStart > frag.getLineRoot().getVisibleBottom() + nDPtoLP_1)// The + 1 is for + // disabled text + continue; + // Break loop at first non-visible fragment + if (yEnd < frag.getLineRoot().getVisibleTop()) + break; + + String draw = getBidiSubstring(frag, i); + + if (frag.isTruncated()) + draw += FlowUtilitiesEx.ELLIPSIS; + + if (!isEnabled()) { + g.setForegroundColor(ColorConstants.buttonLightest); + paintText(g, draw, + frag.getX() + nDPtoLP_1, + frag.getBaseline() - getAscent() + nDPtoLP_1, + frag.getBidiLevel()); + g.setForegroundColor(ColorConstants.buttonDarker); + paintText(g, draw, + frag.getX(), + frag.getBaseline() - getAscent(), + frag.getBidiLevel()); + g.setForegroundColor(fgColor); + } else { + paintText(g, draw, + frag.getX(), + frag.getBaseline() - getAscent(), + frag.getBidiLevel()); + } + + // END: Copy from org.eclipse.draw2d.text.TextFlow#paintFigure ////////// + ///////////////////////////////////////////////////////////////////////// + + + // underline the text, if applicable... + if (isTextUnderlined()) { + g.drawLine(frag.getX(), + frag.getBaseline() + nDPtoLP_1, + frag.getWidth() + frag.getX(), + frag.getBaseline() + nDPtoLP_1); + } + + // strike through the text, if applicable... + if (isTextStrikeThrough()) { + int visibleTop = frag.getLineRoot().getVisibleTop() + + (frag.getBaseline() + getDescent() + + nDPtoLP_2 - + frag.getLineRoot().getVisibleTop()) / 2; + g.drawLine(frag.getX(), + visibleTop, + frag.getWidth() + frag.getX(), + visibleTop); + } + } + } + + /** + * Note: this method is directly copied from + * org.eclipse.draw2d.text.TextFlow but uses methods from FlowUtilitiesEx
+ * + * Paints the String draw at the given x and y location. + */ + private void paintText(Graphics g, String draw, int x, int y, int bidiLevel) { + if (bidiLevel == -1) { + g.drawString(draw, x, y); + } else { + TextLayout tl = FlowUtilitiesEx.getTextLayout(); + if (isMirrored()) + tl.setOrientation(SWT.RIGHT_TO_LEFT); + tl.setFont(g.getFont()); + tl.setText(draw); + g.drawTextLayout(tl, x, y); + } + } + + /** + * Sets the focus state of the text + * + * @param b + * true will cause a focus rectangle to be drawn around the text + * of the Label + */ + public void setFocus(boolean b) { + if (hasFocus() == b) + return; + setFlag(FLAG_HASFOCUS, b); + repaint(); + } + + /** + * Sets the map mode. + * @param mm the map mode to set. + */ + public void setMapMode(IMapMode mm) { + this.mm = mm; + nDPtoLP_1 = mm.DPtoLP(1); + nDPtoLP_2 = mm.DPtoLP(2); + } + + /** + * Sets the selection state of the text + * + * @param b + * true will cause the label to appear selected + */ + public void setSelected(boolean b) { + if (isSelected() == b) + return; + setFlag(FLAG_SELECTED, b); + repaint(); + } + + /** + * Sets whether the text should be striked-through + * + * @param b + * Whether the label text should be striked-through + */ + public void setStrikeThrough(boolean strikeThrough) { + if (isTextStrikeThrough() == strikeThrough) + return; + setFlag(FLAG_STRIKEDTHROUGH, strikeThrough); + repaint(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.draw2d.text.TextFlow#setText(java.lang.String) + */ + public void setText(String s) { + super.setText(s); + literal_SubstringTextBounds = null; + } + + /** + * Sets whether the text should be underlined + * + * @param b + * Whether the label text should be underlined + */ + public void setTextUnderline(boolean underline) { + if (isTextUnderlined() == underline) + return; + setFlag(FLAG_UNDERLINED, underline); + repaint(); + } + + /** + * Maps a location (in absolute coordinates) to an + * offset within the text.
+ *
+ * @param location (in absolute coordinates) to map into offset
+ * @return the offset within the text.
+ */
+ public int getCaretOffset(Point location) {
+ // do a binary search for the caret location...
+
+ String text = getText();
+ int min = 0,
+ max = text.length(),
+ mid = -2,
+ previousMids[] = {-1,-1}; // cache previous results to detect infinite loops
+
+ char midChar = ' ';
+
+ while (max - min > 1) {
+
+ mid = (max + min) / 2;
+
+ midChar = text.charAt(mid);
+
+ CaretInfo caretInfo = getCaretPlacement(mid, false);
+
+ if (caretInfo.getY() + caretInfo.getLineHeight() < location.y)
+ min = mid;
+ else if (caretInfo.getY() > location.y)
+ max = mid;
+ else {
+ if (caretInfo.getX() + FigureUtilities.
+ getStringExtents(String.valueOf(midChar),
+ getFont()).width < location.x)
+ min = mid;
+ else if (caretInfo.getX() > location.x)
+ max = mid;
+ else // we have found the correct match
+ return ++mid; // we want a trailing selection.
+ }
+
+ // detect and prevent infinite loops...
+ // this works because we don't expect to calculate a mid
+ // which we have calculated before.
+ if (mid == previousMids[0] || mid == previousMids[1])
+ break;
+
+ previousMids[1] = previousMids[0];
+ previousMids[0] = mid;
+ }
+
+
+ if (midChar == '\n') // last character when the loop ended
+ --mid; // this happens when the user clicks past the end of line.
+ else
+ ++mid; // we want a trailing selection.
+
+ return mid;
+ }
+}
#P org.eclipse.gmf.runtime.diagram.ui
Index: src/org/eclipse/gmf/runtime/diagram/ui/tools/TextDirectEditManager.java
===================================================================
RCS file: /cvsroot/technology/org.eclipse.gmf/plugins/org.eclipse.gmf.runtime.diagram.ui/src/org/eclipse/gmf/runtime/diagram/ui/tools/TextDirectEditManager.java,v
retrieving revision 1.13.2.10
diff -u -r1.13.2.10 TextDirectEditManager.java
--- src/org/eclipse/gmf/runtime/diagram/ui/tools/TextDirectEditManager.java 29 Nov 2006 18:47:16 -0000 1.13.2.10
+++ src/org/eclipse/gmf/runtime/diagram/ui/tools/TextDirectEditManager.java 15 Dec 2006 21:34:23 -0000
@@ -12,6 +12,7 @@
package org.eclipse.gmf.runtime.diagram.ui.tools;
+import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -35,6 +36,7 @@
import org.eclipse.gmf.runtime.diagram.ui.internal.DiagramUIPlugin;
import org.eclipse.gmf.runtime.diagram.ui.internal.DiagramUIStatusCodes;
import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramGraphicalViewer;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.LabelWithTextLayout;
import org.eclipse.gmf.runtime.draw2d.ui.figures.WrapLabel;
import org.eclipse.gmf.runtime.draw2d.ui.mapmode.IMapMode;
import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil;
@@ -55,6 +57,7 @@
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
@@ -129,6 +132,28 @@
}
public void relocate(CellEditor celleditor) {
+// Text text = (Text) celleditor.getControl();
+// WrapLabel fig = getWrapLabel();
+//
+// Rectangle rect = fig.getTextBounds().getCopy();
+// fig.translateToAbsolute(rect);
+//
+// int avrWidth = FigureUtilities.getFontMetrics(text.getFont())
+// .getAverageCharWidth();
+//
+// if (fig.isTextWrapped() && fig.getText().length() > 0)
+// rect.setSize(new Dimension(rect.width + avrWidth * 2, rect.height));
+// else
+// rect.setSize(new Dimension(text.computeSize(SWT.DEFAULT,
+// SWT.DEFAULT)).expand(avrWidth * 2, 0));
+//
+// org.eclipse.swt.graphics.Rectangle newRect =
+// text.computeTrim(rect.x, rect.y, rect.width, rect.height);
+// text.setBounds(newRect);
+
+
+ // TODO: find a common relocate method for all labels.
+
Text text = (Text) celleditor.getControl();
WrapLabel fig = getWrapLabel();
@@ -234,6 +259,46 @@
return TextCellEditorEx.class;
}
+ protected CellEditor createCellEditorOn(Composite composite) {
+
+ Class ceClass = getTextCellEditorClass(getEditPart());
+
+ if (ceClass == TextCellEditorEx.class ||
+ ceClass == WrapTextCellEditor.class) {
+
+ try {
+
+ Constructor constructor = ceClass.getConstructor(new Class[]{Composite.class,
+ int.class});
+
+ int style;
+
+ if (ceClass == TextCellEditorEx.class)
+ style = SWT.SINGLE;
+ else
+ style = SWT.MULTI | SWT.WRAP;
+
+ IFigure figure = getEditPart().getFigure();
+
+ if (figure instanceof WrapLabel) {
+ if (((WrapLabel)figure).getTextWrapAlignment() == PositionConstants.CENTER)
+ style |= SWT.CENTER;
+ else if (((WrapLabel)figure).getTextWrapAlignment() == PositionConstants.RIGHT)
+ style |= SWT.RIGHT;
+ }
+
+ Integer param1 = new Integer(style);
+
+ return (CellEditor)constructor.newInstance(new Object[]{composite, param1});
+
+ } catch (Exception e) {
+ return null;
+ }
+ }
+ else {
+ return super.createCellEditorOn(composite);
+ }
+ }
/**
* Given a WrapLabel
object, this will calculate the
@@ -535,15 +600,26 @@
String text;
IFigure fig = getEditPart().getFigure();
- if (fig instanceof WrapLabel) {
- WrapLabel label = (WrapLabel) fig;
+ if (fig instanceof LabelWithTextLayout) {
+ int caretPos = ((LabelWithTextLayout) fig)
+ .getCaretOffset(new org.eclipse.draw2d.geometry.Point(
+ location.x, location.y));
+ Text textControl = (Text) getCellEditor().getControl();
+ if (caretPos == -1)
+ textControl.setSelection(0, textControl.getText().length());
+ else
+ textControl.setSelection(caretPos);
+
+ return;
+ } else if (fig instanceof Label) {
+ Label label = (Label) fig;
iconBounds = label.getIconBounds().getCopy();
icon = label.getIcon();
textPlacement = label.getTextPlacement();
subStringText = label.getSubStringText();
text = label.getText();
- } else if (fig instanceof Label) {
- Label label = (Label) fig;
+ } else if (fig instanceof WrapLabel) {
+ WrapLabel label = (WrapLabel) fig;
iconBounds = label.getIconBounds().getCopy();
icon = label.getIcon();
textPlacement = label.getTextPlacement();