/******************************************************************************* * 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 ); } }