Java tutorial
/******************************************************************************* * Copyright (c) 2007, 2015 Innoopract Informationssysteme GmbH 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: * Innoopract Informationssysteme GmbH - initial API and implementation * EclipseSource - ongoing development ******************************************************************************/ package org.eclipse.swt.custom; import static org.eclipse.rap.rwt.internal.textsize.TextSizeUtil.textExtent; import static org.eclipse.swt.internal.widgets.MarkupUtil.isMarkupEnabledFor; import static org.eclipse.swt.internal.widgets.MarkupValidator.isValidationDisabledFor; import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.internal.lifecycle.WidgetLCA; import org.eclipse.rap.rwt.internal.textsize.TextSizeUtil; import org.eclipse.rap.rwt.internal.theme.ThemeAdapter; import org.eclipse.rap.rwt.theme.BoxDimensions; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.internal.custom.clabelkit.CLabelLCA; import org.eclipse.swt.internal.custom.clabelkit.CLabelThemeAdapter; import org.eclipse.swt.internal.widgets.IWidgetGraphicsAdapter; import org.eclipse.swt.internal.widgets.MarkupValidator; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Composite; /** * A Label which supports aligned text and/or an image and different border styles. * <p> * If there is not enough space a CLabel uses the following strategy to fit the * information into the available space: * <pre> * ignores the indent in left align mode * ignores the image and the gap * shortens the text by replacing the center portion of the label with an ellipsis * shortens the text by removing the center portion of the label * </pre> * <p> * <dl> * <dt><b>Styles:</b> * <dd>LEFT, RIGHT, CENTER, SHADOW_IN, SHADOW_OUT, SHADOW_NONE</dd> * <dt><b>Events:</b> * <dd></dd> * </dl> * * </p><p> * IMPORTANT: This class is <em>not</em> intended to be subclassed. * </p> * @since 1.0 */ public class CLabel extends Canvas { private class LabelDisposeListener implements DisposeListener { @Override public void widgetDisposed(DisposeEvent event) { onDispose(); } } /** a string inserted in the middle of text that has been shortened */ // private static final String ELLIPSIS = "..."; //$NON-NLS-1$ // could use the ellipsis glyph on some platforms "\u2026" /** the alignment. Either CENTER, RIGHT, LEFT. Default is LEFT */ private int align = SWT.LEFT; private int leftMargin; private int topMargin; private int rightMargin; private int bottomMargin; /** the current text */ private String text; /** the current icon */ private Image image; // The tooltip is used for two purposes - the application can set // a tooltip or the tooltip can be used to display the full text when the // the text has been truncated due to the label being too short. // The appToolTip stores the tooltip set by the application. // Control.tooltiptext // contains whatever tooltip is currently being displayed. private String appToolTipText; private Image backgroundImage; private Color background; /** * Constructs a new instance of this class given its parent * and a style value describing its behavior and appearance. * <p> * The style value is either one of the style constants defined in * class <code>SWT</code> which is applicable to instances of this * class, or must be built by <em>bitwise OR</em>'ing together * (that is, using the <code>int</code> "|" operator) two or more * of those <code>SWT</code> style constants. The class description * lists the style constants that are applicable to the class. * Style bits are also inherited from superclasses. * </p> * * @param parent a widget which will be the parent of the new instance (cannot be null) * @param style the style of widget to construct * * @exception IllegalArgumentException <ul> * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> * </ul> * @exception SWTException <ul> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> * </ul> * * @see SWT#LEFT * @see SWT#RIGHT * @see SWT#CENTER * @see SWT#SHADOW_IN * @see SWT#SHADOW_OUT * @see SWT#SHADOW_NONE * @see #getStyle() */ public CLabel(Composite parent, int style) { super(parent, checkStyle(style)); int result = style; if ((style & (SWT.CENTER | SWT.RIGHT)) == 0) { result |= SWT.LEFT; } if ((result & SWT.CENTER) != 0) { align = SWT.CENTER; } if ((result & SWT.RIGHT) != 0) { align = SWT.RIGHT; } if ((result & SWT.LEFT) != 0) { align = SWT.LEFT; } addDisposeListener(new LabelDisposeListener()); initMargins(); } /** * Check the style bits to ensure that no invalid styles are applied. */ private static int checkStyle(int style) { int result = style; if ((style & SWT.BORDER) != 0) { result |= SWT.SHADOW_IN; } int mask = SWT.SHADOW_IN | SWT.SHADOW_OUT | SWT.SHADOW_NONE | SWT.LEFT_TO_RIGHT /*| SWT.RIGHT_TO_LEFT*/; result = style & mask; return result |= SWT.NO_FOCUS; } @Override public Point computeSize(int wHint, int hHint, boolean changed) { checkWidget(); BoxDimensions border = getCLabelThemeAdapter().getBorder(this); Point e = getTotalSize(image, text); if (wHint == SWT.DEFAULT) { e.x += leftMargin + rightMargin; e.x += border.left + border.right; } else { e.x = wHint; } if (hHint == SWT.DEFAULT) { e.y += topMargin + bottomMargin; e.y += border.top + border.bottom; } else { e.y = hHint; } return e; } /** * Returns the alignment. * The alignment style (LEFT, CENTER or RIGHT) is returned. * * @return SWT.LEFT, SWT.RIGHT or SWT.CENTER */ public int getAlignment() { checkWidget(); return align; } /** * Return the CLabel's image or <code>null</code>. * * @return the image of the label or null */ public Image getImage() { checkWidget(); return image; } /** * Compute the minimum size. */ private Point getTotalSize(Image image, String text) { Point size = new Point(0, 0); int spacing = getCLabelThemeAdapter().getSpacing(this); if (image != null) { Rectangle imageBounds = image.getBounds(); size.x += imageBounds.width; size.y += imageBounds.height; } if (text != null && text.length() > 0) { Point extent = textExtent(getFont(), text, SWT.DEFAULT, isMarkupEnabledFor(this)); size.x += extent.x; size.y = Math.max(size.y, extent.y); if (image != null) { size.x += spacing; } } else { int charHeight = TextSizeUtil.getCharHeight(getFont()); size.y = Math.max(size.y, charHeight); } return size; } @Override public int getStyle() { int style = super.getStyle(); switch (align) { case SWT.RIGHT: style |= SWT.RIGHT; break; case SWT.CENTER: style |= SWT.CENTER; break; case SWT.LEFT: style |= SWT.LEFT; break; } return style; } /** * Return the Label's text. * * @return the text of the label or null */ public String getText() { checkWidget(); return text; } @Override public String getToolTipText() { checkWidget(); return appToolTipText; } private void onDispose() { backgroundImage = null; text = null; image = null; appToolTipText = null; } /** * Set the alignment of the CLabel. * Use the values LEFT, CENTER and RIGHT to align image and text within the available space. * * @param align the alignment style of LEFT, RIGHT or CENTER * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * <li>ERROR_INVALID_ARGUMENT - if the value of align is not one of SWT.LEFT, SWT.RIGHT or SWT.CENTER</li> * </ul> */ public void setAlignment(int align) { checkWidget(); if (align != SWT.LEFT && align != SWT.RIGHT && align != SWT.CENTER) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } if (this.align != align) { this.align = align; } } @Override public void setBackground(Color color) { super.setBackground(color); // Are these settings the same as before? if (backgroundImage == null) { if (color == null) { if (background == null) { return; } } else { if (color.equals(background)) { return; } } } background = color; backgroundImage = null; setBackgroundGradient(null, null, false); } /** * Set the image to be drawn in the background of the label. * * @param image the image to be drawn in the background * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> */ public void setBackground(Image image) { checkWidget(); if (image != backgroundImage) { backgroundImage = image; if (image != null) { setBackgroundGradient(null, null, false); } } } /** * Specify a gradient of colours to be drawn in the background of the CLabel. * <p>For example, to draw a gradient that varies from dark blue to blue and then to * white and stays white for the right half of the label, use the following call * to setBackground:</p> * <pre> * clabel.setBackground(new Color[]{display.getSystemColor(SWT.COLOR_DARK_BLUE), * display.getSystemColor(SWT.COLOR_BLUE), * display.getSystemColor(SWT.COLOR_WHITE), * display.getSystemColor(SWT.COLOR_WHITE)}, * new int[] {25, 50, 100}); * </pre> * * @param colors an array of Color that specifies the colors to appear in the gradient * in order of appearance from left to right; The value <code>null</code> * clears the background gradient; the value <code>null</code> can be used * inside the array of Color to specify the background color. * @param percents an array of integers between 0 and 100 specifying the percent of the width * of the widget at which the color should change; the size of the percents * array must be one less than the size of the colors array. * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * <li>ERROR_INVALID_ARGUMENT - if the values of colors and percents are not consistent</li> * </ul> * * @since 1.4 */ public void setBackground(Color[] colors, int[] percents) { setBackground(colors, percents, false); } /** * Specify a gradient of colours to be drawn in the background of the CLabel. * <p>For example, to draw a gradient that varies from dark blue to white in the vertical, * direction use the following call * to setBackground:</p> * <pre> * clabel.setBackground(new Color[]{display.getSystemColor(SWT.COLOR_DARK_BLUE), * display.getSystemColor(SWT.COLOR_WHITE)}, * new int[] {100}, true); * </pre> * * @param colors an array of Color that specifies the colors to appear in the gradient * in order of appearance from left/top to right/bottom; The value <code>null</code> * clears the background gradient; the value <code>null</code> can be used * inside the array of Color to specify the background color. * @param percents an array of integers between 0 and 100 specifying the percent of the width/height * of the widget at which the color should change; the size of the percents * array must be one less than the size of the colors array. * @param vertical indicate the direction of the gradient. True is vertical and false is horizontal. * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * <li>ERROR_INVALID_ARGUMENT - if the values of colors and percents are not consistent</li> * </ul> * * @since 1.4 */ public void setBackground(Color[] colors, int[] percents, boolean vertical) { checkWidget(); if (colors != null) { if (percents == null || percents.length != colors.length - 1) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } for (int i = 0; i < percents.length; i++) { if (percents[i] < 0 || percents[i] > 100) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } if (i > 0 && percents[i] < percents[i - 1]) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } } } if (colors == null) { setBackgroundGradient(null, null, false); } else { Color[] gradientColors = new Color[colors.length]; for (int i = 0; i < colors.length; ++i) { gradientColors[i] = colors[i] != null ? colors[i] : background; } int[] gradientPercents = new int[gradientColors.length]; gradientPercents[0] = 0; for (int i = 1; i < gradientPercents.length; i++) { gradientPercents[i] = percents[i - 1]; } setBackgroundGradient(gradientColors, gradientPercents, vertical); } backgroundImage = null; } private void setBackgroundGradient(Color[] colors, int[] percents, boolean vertical) { IWidgetGraphicsAdapter adapter = getAdapter(IWidgetGraphicsAdapter.class); adapter.setBackgroundGradient(colors, percents, vertical); } @Override public void setFont(Font font) { super.setFont(font); } /** * Set the label's Image. * The value <code>null</code> clears it. * * @param image the image to be displayed in the label or null * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> */ public void setImage(Image image) { checkWidget(); if (image != this.image) { this.image = image; } } /** * Set the label's text. * The value <code>null</code> clears it. * * @param text the text to be displayed in the label or null * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> */ public void setText(String text) { checkWidget(); if (text == null) { this.text = ""; } else if (!text.equals(this.text)) { if (isMarkupEnabledFor(this) && !isValidationDisabledFor(this)) { MarkupValidator.getInstance().validate(text); } this.text = text; } } @Override public void setToolTipText(String string) { super.setToolTipText(string); appToolTipText = super.getToolTipText(); } /** * Shorten the given text <code>t</code> so that its length doesn't exceed * the given width. The default implementation replaces characters in the * center of the original string with an ellipsis ("..."). * Override if you need a different strategy. * * @param gc the gc to use for text measurement * @param t the text to shorten * @param width the width to shorten the text to, in pixels * @return the shortened text */ // TODO: [bm] review //protected String shortenText(Object gc, String t, int width) { // if (t == null) return null; // int w = FontSizeEstimation.stringExtent( ELLIPSIS, getFont() ).x; // if (width<=w) return t; // int l = t.length(); // int max = l/2; // int min = 0; // int mid = (max+min)/2 - 1; // if (mid <= 0) return t; // while (min < mid && mid < max) { // String s1 = t.substring(0, mid); // String s2 = t.substring(l-mid, l); // int l1 = FontSizeEstimation.stringExtent( s1, getFont() ).x; // int l2 = FontSizeEstimation.stringExtent( s2, getFont() ).x; // if (l1+w+l2 > width) { // max = mid; // mid = (max+min)/2; // } else if (l1+w+l2 < width) { // min = mid; // mid = (max+min)/2; // } else { // min = max; // } // } // if (mid == 0) return t; // return t.substring(0, mid)+ELLIPSIS+t.substring(l-mid, l); //} // //private String[] splitString(String text) { // String[] lines = new String[1]; // int start = 0, pos; // do { // pos = text.indexOf('\n', start); // if (pos == -1) { // lines[lines.length - 1] = text.substring(start); // } else { // boolean crlf = (pos > 0) && (text.charAt(pos - 1) == '\r'); // lines[lines.length - 1] = text.substring(start, pos - (crlf ? 1 : 0)); // start = pos + 1; // String[] newLines = new String[lines.length+1]; // System.arraycopy(lines, 0, newLines, 0, lines.length); // lines = newLines; // } // } while (pos != -1); // return lines; //} /** * Set the label's margins, in pixels. * * @param leftMargin the left margin. * @param topMargin the top margin. * @param rightMargin the right margin. * @param bottomMargin the bottom margin. * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> * * @since 1.3 */ public void setMargins(int leftMargin, int topMargin, int rightMargin, int bottomMargin) { checkWidget(); this.leftMargin = Math.max(0, leftMargin); this.topMargin = Math.max(0, topMargin); this.rightMargin = Math.max(0, rightMargin); this.bottomMargin = Math.max(0, bottomMargin); } /** * Set the label's horizontal left margin, in pixels. * * @param leftMargin the left margin of the label, which must be equal to or greater than zero * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> * * @since 1.3 */ public void setLeftMargin(int leftMargin) { checkWidget(); if (leftMargin >= 0) { this.leftMargin = leftMargin; } } /** * Return the CLabel's left margin. * * @return the left margin of the label * * @since 1.3 */ public int getLeftMargin() { //checkWidget(); // [if] Commented in SWT return leftMargin; } /** * Set the label's top margin, in pixels. * * @param topMargin the top margin of the label, which must be equal to or greater than zero * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> * * @since 1.3 */ public void setTopMargin(int topMargin) { checkWidget(); if (topMargin >= 0) { this.topMargin = topMargin; } } /** * Return the CLabel's top margin. * * @return the top margin of the label * * @since 1.3 */ public int getTopMargin() { //checkWidget(); // [if] Commented in SWT return topMargin; } /** * Set the label's right margin, in pixels. * * @param rightMargin the right margin of the label, which must be equal to or greater than zero * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> * * @since 1.3 */ public void setRightMargin(int rightMargin) { checkWidget(); if (rightMargin >= 0) { this.rightMargin = rightMargin; } } /** * Return the CLabel's right margin. * * @return the right margin of the label * * @since 1.3 */ public int getRightMargin() { //checkWidget(); // [if] Commented in SWT return rightMargin; } /** * Set the label's bottom margin, in pixels. * * @param bottomMargin the bottom margin of the label, which must be equal to or greater than zero * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> * * @since 1.3 */ public void setBottomMargin(int bottomMargin) { checkWidget(); if (bottomMargin >= 0) { this.bottomMargin = bottomMargin; } } /** * Return the CLabel's bottom margin. * * @return the bottom margin of the label * * @since 1.3 */ public int getBottomMargin() { //checkWidget(); // [if] Commented in SWT return bottomMargin; } @Override public void setData(String key, Object value) { if (!RWT.MARKUP_ENABLED.equals(key) || !isMarkupEnabledFor(this)) { super.setData(key, value); } } @Override @SuppressWarnings("unchecked") public <T> T getAdapter(Class<T> adapter) { if (adapter == WidgetLCA.class) { return (T) CLabelLCA.INSTANCE; } return super.getAdapter(adapter); } private void initMargins() { BoxDimensions padding = getCLabelThemeAdapter().getPadding(this); leftMargin = padding.left; topMargin = padding.top; rightMargin = padding.right; bottomMargin = padding.bottom; } private CLabelThemeAdapter getCLabelThemeAdapter() { return (CLabelThemeAdapter) getAdapter(ThemeAdapter.class); } }