org.eclipse.swt.widgets.ExpandItem.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.swt.widgets.ExpandItem.java

Source

/*******************************************************************************
 * Copyright (c) 2008, 2016 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
 *    Tom Schindl<tom.schindl@bestsolution.at> - fix for issue 272674
 ******************************************************************************/
package org.eclipse.swt.widgets;

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.internal.lifecycle.WidgetLCA;
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.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.internal.widgets.MarkupValidator;
import org.eclipse.swt.internal.widgets.expandbarkit.ExpandBarThemeAdapter;
import org.eclipse.swt.internal.widgets.expanditemkit.ExpandItemLCA;

/**
 * Instances of this class represent a selectable user interface object that
 * represents a expandable item in a expand bar.
 * <p>
 * <dl>
 * <dt><b>Styles:</b></dt>
 * <dd>(none)</dd>
 * <dt><b>Events:</b></dt>
 * <dd>(none)</dd>
 * </dl>
 * </p>
 * <p>
 * IMPORTANT: This class is <em>not</em> intended to be subclassed.
 * </p>
 *
 * @see ExpandBar
 * @since 1.2
 */
public class ExpandItem extends Item {

    static final int LEFT_MARGIN = 4;
    static final int RIGHT_MARGIN = 24;
    static final int INTERNAL_SPACING = 4;
    static final int CHEVRON_SIZE = 24;

    ExpandBar parent;
    Control control;
    boolean expanded;
    int x, y, width, height;
    int imageHeight, imageWidth;

    /**
     * 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 composite control which will be the parent of the new
     *          instance (cannot be null)
     * @param style the style of control 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>
     *              <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed
     *              subclass</li>
     *              </ul>
     * @see Widget#checkSubclass
     * @see Widget#getStyle
     */
    public ExpandItem(ExpandBar parent, int style) {
        this(parent, style, checkNull(parent).getItemCount());
    }

    /**
     * Constructs a new instance of this class given its parent, a style value
     * describing its behavior and appearance, and the index at which to place it
     * in the items maintained by its parent.
     * <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 composite control which will be the parent of the new
     *          instance (cannot be null)
     * @param style the style of control to construct
     * @param index the zero-relative index to store the receiver in its parent
     * @exception IllegalArgumentException
     *              <ul>
     *              <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
     *              <li>ERROR_INVALID_RANGE - if the index is not between 0 and
     *              the number of elements in the parent (inclusive)</li>
     *              </ul>
     * @exception SWTException
     *              <ul>
     *              <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
     *              thread that created the parent</li>
     *              <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed
     *              subclass</li>
     *              </ul>
     * @see Widget#checkSubclass
     * @see Widget#getStyle
     */
    public ExpandItem(ExpandBar parent, int style, int index) {
        super(parent, style);
        this.parent = parent;
        parent.createItem(this, index);
    }

    static ExpandBar checkNull(ExpandBar control) {
        if (control == null) {
            SWT.error(SWT.ERROR_NULL_ARGUMENT);
        }
        return control;
    }

    ///////////////////
    // Widget overrides

    @Override
    public void dispose() {
        if (!isDisposed()) {
            parent.destroyItem(this);
            if (control != null) {
                control.dispose();
                control = null;
            }
            super.dispose();
        }
    }

    /**
     * Returns the control that is shown when the item is expanded. If no control
     * has been set, return <code>null</code>.
     *
     * @return the control
     * @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 Control getControl() {
        checkWidget();
        return control;
    }

    /**
     * Returns <code>true</code> if the receiver is expanded, and false
     * otherwise.
     *
     * @return the expanded state
     * @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 boolean getExpanded() {
        checkWidget();
        return expanded;
    }

    /**
     * Returns the height of the receiver's header
     *
     * @return the height of the header
     * @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 int getHeaderHeight() {
        checkWidget();
        Font font = parent.getFont();
        BoxDimensions itemHeaderBorder = getItemHeaderBorder();
        int borderHeight = itemHeaderBorder.top + itemHeaderBorder.bottom;
        int textHeight = textExtent(font, text, SWT.DEFAULT, isMarkupEnabledFor(parent)).y + 4;
        return Math.max(Math.max(CHEVRON_SIZE, imageHeight), textHeight) + borderHeight;
    }

    /**
     * Gets the height of the receiver.
     *
     * @return the height
     * @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 int getHeight() {
        checkWidget();
        return height;
    }

    /**
     * Returns the receiver's parent, which must be a <code>ExpandBar</code>.
     *
     * @return the receiver's parent
     * @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 ExpandBar getParent() {
        checkWidget();
        return parent;
    }

    int getPreferredWidth() {
        if (!isDisposed()) {
            Image image = getImage();
            String text = getText();
            int width = (image == null) ? 0 : image.getBounds().width;
            if (width > 0) {
                width += INTERNAL_SPACING;
            }
            width += textExtent(parent.getFont(), text, SWT.DEFAULT, isMarkupEnabledFor(parent)).x;
            return width + LEFT_MARGIN + RIGHT_MARGIN;
        }
        return 0;
    }

    Rectangle getBounds() {
        BoxDimensions itemBorder = getItemBorder();
        int itemHeight = getHeaderHeight() + itemBorder.top + itemBorder.bottom;
        if (expanded) {
            itemHeight += height;
        }
        return new Rectangle(x, y, width, itemHeight);
    }

    void setBounds(int x, int y, int width, int height, boolean move, boolean size) {
        int headerHeight = getHeaderHeight();
        int aX = x;
        int aY = y;
        int aWidth = width;
        int aHeight = height;
        if (move) {
            if (imageHeight > headerHeight) {
                aY += (imageHeight - headerHeight);
            }
            this.x = aX;
            this.y = aY;
        }
        if (size) {
            this.width = aWidth;
            this.height = aHeight;
        }
        if (control != null && !control.isDisposed()) {
            if (!parent.isAppThemed()) {
                BoxDimensions border = getItemBorder();
                aX += border.left;
                aY += border.top;
                aWidth = Math.max(0, aWidth - border.left - border.right);
                aHeight = Math.max(0, aHeight - border.top - border.bottom);
            }
            if (move && size) {
                control.setBounds(aX, aY + headerHeight, aWidth, aHeight);
            }
            if (move && !size) {
                control.setLocation(aX, aY + headerHeight);
            }
            if (!move && size) {
                control.setSize(aWidth, aHeight);
            }
        }
    }

    /**
     * Sets the control that is shown when the item is expanded.
     *
     * @param control the new control (or null)
     * @exception IllegalArgumentException
     *              <ul>
     *              <li>ERROR_INVALID_ARGUMENT - if the control has been disposed</li>
     *              <li>ERROR_INVALID_PARENT - if the control is not in the same
     *              widget tree</li>
     *              </ul>
     * @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 setControl(Control control) {
        checkWidget();
        if (control != null) {
            if (control.isDisposed()) {
                error(SWT.ERROR_INVALID_ARGUMENT);
            }
            if (control._getParent() != parent) {
                error(SWT.ERROR_INVALID_PARENT);
            }
        }
        this.control = control;
        if (control != null) {
            int headerHeight = getHeaderHeight();
            control.setVisible(expanded);
            if (!parent.isAppThemed()) {
                BoxDimensions border = getItemBorder();
                int width = Math.max(0, this.width - border.left - border.right);
                int height = Math.max(0, this.height - border.top - border.bottom);
                control.setBounds(x + border.left, y + border.top + headerHeight, width, height);
            } else {
                control.setBounds(x, y + headerHeight, width, height);
            }
        }
    }

    /**
     * Sets the expanded state of the receiver.
     *
     * @param expanded the new expanded state
     * @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 setExpanded(boolean expanded) {
        checkWidget();
        this.expanded = expanded;
        parent.showItem(this);
    }

    /**
     * Sets the height of the receiver. This is height of the item when it is
     * expanded, excluding the height of the header.
     *
     * @param height the new height
     * @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 setHeight(int height) {
        checkWidget();
        if (height >= 0) {
            setBounds(0, 0, width, height, false, true);
            if (expanded) {
                parent.layoutItems(parent.indexOf(this) + 1);
            }
        }
    }

    @Override
    public void setImage(Image image) {
        checkWidget();
        if (image != getImage()) {
            super.setImage(image);
            updateBounds();
        }
        int oldImageHeight = imageHeight;
        if (image != null) {
            Rectangle bounds = image.getBounds();
            imageHeight = bounds.height;
            imageWidth = bounds.width;
        } else {
            imageHeight = imageWidth = 0;
        }
        if (oldImageHeight != imageHeight) {
            parent.layoutItems(parent.indexOf(this));
        }
    }

    @Override
    public void setText(String string) {
        checkWidget();
        if (string == null) {
            SWT.error(SWT.ERROR_NULL_ARGUMENT);
        }
        if (isMarkupEnabledFor(parent) && !isValidationDisabledFor(parent)) {
            MarkupValidator.getInstance().validate(string);
        }
        if (!string.equals(getText())) {
            super.setText(string);
            updateBounds();
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T getAdapter(Class<T> adapter) {
        if (adapter == WidgetLCA.class) {
            return (T) ExpandItemLCA.INSTANCE;
        }
        return super.getAdapter(adapter);
    }

    private void updateBounds() {
        int parentWidth = parent.computeSize(SWT.DEFAULT, SWT.DEFAULT, false).x;
        int scrollBarWidth = parent.getVScrollBarWidth();
        int availableWidth = parentWidth - 2 * parent.spacing - scrollBarWidth;
        width = Math.max(getPreferredWidth(), availableWidth);
        setBounds(0, 0, width, height, false, true);
    }

    ////////////////////////////
    // Helping methods - various

    BoxDimensions getItemBorder() {
        return getExpandBarThemeAdapter().getItemBorder(parent);
    }

    BoxDimensions getItemHeaderBorder() {
        return getExpandBarThemeAdapter().getItemHeaderBorder(parent);
    }

    private ExpandBarThemeAdapter getExpandBarThemeAdapter() {
        return (ExpandBarThemeAdapter) parent.getAdapter(ThemeAdapter.class);
    }

}