/******************************************************************************* * Copyright (c) 2002, 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.widgets; 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.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.internal.widgets.IItemHolderAdapter; import org.eclipse.swt.internal.widgets.ItemHolder; import org.eclipse.swt.internal.widgets.toolbarkit.ToolBarLCA; import org.eclipse.swt.internal.widgets.toolbarkit.ToolBarThemeAdapter; /** * Instances of this class support the layout of selectable * tool bar items. * <p> * The item children that may be added to instances of this class * must be of type <code>ToolItem</code>. * </p><p> * Note that although this class is a subclass of <code>Composite</code>, * it does not make sense to add <code>Control</code> children to it, * or set a layout on it. * </p><p> * <dl> * <dt><b>Styles:</b></dt> * <dd>FLAT, <!-- WRAP, --> RIGHT, HORIZONTAL, VERTICAL<!--, SHADOW_OUT--></dd> * <dt><b>Events:</b></dt> * <dd>(none)</dd> * </dl> * <p> * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified. * </p><p> * IMPORTANT: This class is <em>not</em> intended to be subclassed. * </p> * @since 1.0 */ public class ToolBar extends Composite { private static final int DEFAULT_TOOLBAR_WIDTH = 24; private static final int DEFAULT_TOOLBAR_HEIGHT = 22; private final ItemHolder<ToolItem> itemHolder; /** * 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 SWT#FLAT *<!-- @see SWT#WRAP --> *<!-- @see SWT#RIGHT --> * @see SWT#HORIZONTAL *<!-- @see SWT#SHADOW_OUT --> * @see SWT#VERTICAL * <!--@see Widget#checkSubclass()--> * @see Widget#getStyle() */ public ToolBar( Composite parent, int style ) { super( parent, checkStyle( style ) ); /* * Ensure that either of HORIZONTAL or VERTICAL is set. NOTE: HORIZONTAL and * VERTICAL have the same values as H_SCROLL and V_SCROLL so it is necessary * to first clear these bits to avoid scroll bars and then reset the bits * using the original style supplied by the programmer. */ if( ( style & SWT.VERTICAL ) != 0 ) { this.style |= SWT.VERTICAL; } else { this.style |= SWT.HORIZONTAL; } itemHolder = new ItemHolder<>( ToolItem.class ); } @Override @SuppressWarnings("unchecked") public <T> T getAdapter( Class<T> adapter ) { if( adapter == IItemHolderAdapter.class ) { return ( T )itemHolder; } if( adapter == WidgetLCA.class ) { return ( T )ToolBarLCA.INSTANCE; } return super.getAdapter( adapter ); } ////////////////// // Item management /** * Returns the item at the given, zero-relative index in the * receiver. Throws an exception if the index is out of range. * * @param index the index of the item to return * @return the item at the given index * * @exception IllegalArgumentException <ul> * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</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 ToolItem getItem( int index ) { checkWidget(); return itemHolder.getItem( index ); } /** * Returns the item at the given point in the receiver * or null if no such item exists. The point is in the * coordinate system of the receiver. * * @param point the point used to locate the item * @return the item at the given point * * @exception IllegalArgumentException <ul> * <li>ERROR_NULL_ARGUMENT - if the point is null</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> * @since 1.3 */ public ToolItem getItem( Point point ) { checkWidget(); if( point == null ) { error( SWT.ERROR_NULL_ARGUMENT ); } ToolItem result = null; ToolItem[] items = getItems(); for( int i = 0; result == null && i < items.length; i++ ) { Rectangle rect = items[ i ].getBounds(); if( rect.contains( point ) ) { result = items[ i ]; } } return result; } /** * Returns the number of items contained in the receiver. * * @return the number of items * * @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 getItemCount() { checkWidget(); return itemHolder.size(); } /** * Returns an array of <code>ToolItem</code>s which are the items * in the receiver. * <p> * Note: This is not the actual structure used by the receiver * to maintain its list of items, so modifying the array will * not affect the receiver. * </p> * * @return the items in the receiver * * @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 ToolItem[] getItems() { checkWidget(); return itemHolder.getItems(); } /** * Searches the receiver's list starting at the first item * (index 0) until an item is found that is equal to the * argument, and returns the index of that item. If no item * is found, returns -1. * * @param item the search item * @return the index of the item * * @exception IllegalArgumentException <ul> * <li>ERROR_NULL_ARGUMENT - if the tool item is null</li> * <li>ERROR_INVALID_ARGUMENT - if the tool item has been disposed</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 int indexOf( ToolItem item ) { checkWidget(); if( item == null ) { SWT.error( SWT.ERROR_NULL_ARGUMENT ); } if( item.isDisposed() ) { SWT.error( SWT.ERROR_INVALID_ARGUMENT ); } return itemHolder.indexOf( item ); } //////////////////// // Size computations @Override public Point computeSize( int wHint, int hHint, boolean changed ) { checkWidget(); int width = 0; int height = 0; if( ( style & SWT.VERTICAL ) != 0 ) { for( int i = 0; i < itemHolder.size(); i++ ) { ToolItem item = itemHolder.getItem( i ); Rectangle itemBounds = item.getBounds(); width = Math.max( width, itemBounds.width ); if( i == itemHolder.size() - 1 ) { height += itemBounds.height + itemBounds.y; } } } else { for( int i = 0; i < itemHolder.size(); i++ ) { ToolItem item = itemHolder.getItem( i ); Rectangle itemBounds = item.getBounds(); height = Math.max( height, itemBounds.height ); if( i == itemHolder.size() - 1 ) { width += itemBounds.width + itemBounds.x; } } } BoxDimensions toolBarPadding = getToolBarPadding(); width += toolBarPadding.left + toolBarPadding.right; height += toolBarPadding.top + toolBarPadding.bottom; if( width == 0 ) { width = DEFAULT_TOOLBAR_WIDTH; } if( height == 0 ) { height = DEFAULT_TOOLBAR_HEIGHT; } if( wHint != SWT.DEFAULT ) { width = wHint; } if( hHint != SWT.DEFAULT ) { height = hHint; } for( int i = 0; i < itemHolder.size(); i++ ) { ToolItem item = itemHolder.getItem( i ); item.resizeControl(); } Rectangle trim = computeTrim( 0, 0, width, height ); width = trim.width; height = trim.height; return new Point( width, height ); } BoxDimensions getToolBarPadding() { ToolBarThemeAdapter themeAdapter = ( ToolBarThemeAdapter )getAdapter( ThemeAdapter.class ); return themeAdapter.getToolBarPadding( this ); } /** * Returns the number of rows in the receiver. When * the receiver has the <code>WRAP</code> style, the * number of rows can be greater than one. Otherwise, * the number of rows is always one. * * @return the number of items * * @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 getRowCount() { checkWidget(); // return 1 as long as we don't support the WRAP style bit return 1; } @Override public void setBounds( Rectangle bounds ) { Point oldSize = getSize(); super.setBounds( bounds ); if( !oldSize.equals( getSize() ) ) { layoutItems(); } } @Override public void setFont( Font font ) { super.setFont( font ); layoutItems(); } //////////////////////// // Child control removal @Override void removeChild( Control control ) { super.removeChild( control ); ToolItem[] items = itemHolder.getItems(); for( int i = 0; i < items.length; i++ ) { ToolItem item = items[ i ]; if( item != null && item.getControl() == control ) { item.setControl( null ); } } } //////////////////// // Widget overrides @Override final void releaseChildren() { ToolItem[] toolItems = itemHolder.getItems(); for( int i = 0; i < toolItems.length; i++ ) { toolItems[ i ].dispose(); } } ////////////////// // Helping methods private static int checkStyle( int style ) { /* * Even though it is legal to create this widget * with scroll bars, they serve no useful purpose * because they do not automatically scroll the * widget's client area. The fix is to clear * the SWT style. */ return style & ~( SWT.H_SCROLL | SWT.V_SCROLL ); } void createItem( ToolItem item, int index ) { itemHolder.insert( item, index ); layoutItems(); } void destroyItem( ToolItem item ) { itemHolder.remove( item ); layoutItems(); } void layoutItems() { for( int i = 0; i < itemHolder.size(); i++ ) { ToolItem item = itemHolder.getItem( i ); Rectangle ibounds = item.getBounds(); Rectangle bounds = getBounds(); boolean hasEnoughWidth = ibounds.x + ibounds.width <= bounds.width; boolean hasEnoughHeight = ibounds.y + ibounds.height <= bounds.height; item.setVisible( hasEnoughWidth && hasEnoughHeight ); item.resizeControl(); } } /////////////////// // Skinning support @Override void reskinChildren( int flags ) { ToolItem[] items = getItems(); if( items != null ) { for( int i = 0; i < items.length; i++ ) { ToolItem item = items[ i ]; if( item != null ) { item.reskin( flags ); } } } super.reskinChildren( flags ); } }