/******************************************************************************* * Copyright (c) 2008 Matthew Hall * 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 : * Matthew Hall <matthall@woodcraftmill.com> - initial API and implementation *******************************************************************************/ package org.eclipse.nebula.widgets.radiogroup; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.RowLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Item; import org.eclipse.swt.widgets.Layout; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.TypedListener; /** * <p> * SWT Widget that presents a group of radio buttons. This widget require * jdk-1.4+ * </p> * <p> * <dl> * <dt><b>Styles:</b></dt> * <dd>BORDER, FLAT, HORIZONTAL, VERTICAL, LEFT, RIGHT, CENTER, LEFT_TO_RIGHT, * RIGHT_TO_LEFT</dd> * </dl> * <p> * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified. * </p> * <p> * Note: Only one of the styles LEFT, RIGHT, and CENTER may be specified. * </p> * <p> * Note: Only one of the styles LEFT_TO_RIGHT and RIGHT_TO_LEFT may be * specified. * </p> * <p> * <dl> * <dt><b>Events:</b></dt> * <dd>Selection, DefaultSelection</dd> * </dl> * </p> * <p> * NOTE: THIS WIDGET AND ITS API ARE STILL UNDER DEVELOPMENT. THIS IS A * PRE-RELEASE ALPHA VERSION. USERS SHOULD EXPECT API CHANGES IN FUTURE * VERSIONS. * </p> * <p> * IMPORTANT: This class is <em>not</em> intended to be subclassed. * </p> * * @noextend This class is not intended to be subclassed. * @author Matthew Hall <matthall@woodcraftmill.com> */ public class RadioGroup extends Composite { private final int cardinality; private final int buttonStyle; private RadioItem[] items = {}; private RadioItem selection = null; public RadioGroup(Composite parent, int style) { super(parent, checkCompositeStyle(style)); this.cardinality = checkCardinality(style); this.buttonStyle = checkButtonStyle(style); super.setLayout(new RowLayout(cardinality)); setBackgroundMode(SWT.INHERIT_DEFAULT); addListener(SWT.Dispose, new Listener() { public void handleEvent(Event event) { handleDispose(event); } }); } private static int checkCompositeStyle(int style) { int result = style & SWT.BORDER; if ((style & SWT.LEFT_TO_RIGHT) != 0) result |= SWT.LEFT_TO_RIGHT; else if ((style & SWT.RIGHT_TO_LEFT) != 0) result |= SWT.RIGHT_TO_LEFT; return result; } private int checkCardinality(int style) { if ((style & SWT.VERTICAL) != 0) return SWT.VERTICAL; return SWT.HORIZONTAL; } private static int checkButtonStyle(int style) { int result = 0; if ((style & SWT.FLAT) != 0) result |= SWT.FLAT; if ((style & SWT.LEFT) != 0) result |= SWT.LEFT; else if ((style & SWT.CENTER) != 0) result |= SWT.CENTER; else if ((style & SWT.RIGHT) != 0) result |= SWT.RIGHT; else result |= SWT.LEFT; return result; } private void handleDispose(Event event) { RadioItem[] items = getItems(); for (int i = 0; i < items.length; i++) items[i].dispose(); } public int getStyle() { return super.getStyle() | buttonStyle | cardinality; } // TODO Cannot override getChildren method to hide children until we are // doing manual layout. Currently we delegate to RowLayout which depends on // getChildren. // public Control[] getChildren() { // checkWidget(); // return new Control[0]; // } /** * Sets the layout which is associated with the receiver to be the argument * which may be null. * <p> * Note: No Layout can be set on this Control because it already manages the * size and position of its children. * </p> * * @param layout * the receiver's new layout 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 setLayout(Layout layout) { checkWidget(); return; } public void clear(int position) { checkWidget(); checkExistingPosition(position); items[position].clear(); } private void checkExistingPosition(int position) { if (position < 0 || position >= getItemCount()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); } public void remove(RadioItem item) { checkWidget(); if (item.isDisposed() || item.getParent() != this) SWT.error(SWT.ERROR_INVALID_ARGUMENT); item.dispose(); } public void remove(int position) { checkWidget(); checkExistingPosition(position); items[position].dispose(); } public void remove(int start, int end) { checkWidget(); if (start > end) return; if (start < 0 || end >= items.length) SWT.error(SWT.ERROR_INVALID_RANGE); setLayoutDeferred(true); try { Item[] items = (Item[]) this.items.clone(); for (int i = start; i <= end; i++) { items[i].dispose(); } } finally { setLayoutDeferred(false); } } public void removeAll() { checkWidget(); remove(0, items.length - 1); } /** * Returns the number of items in the receiver. * * @return the number of items in the receiver. */ public int getItemCount() { checkWidget(); if (items == null) return 0; return items.length; } public void addSelectionListener(SelectionListener listener) { checkWidget(); if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); TypedListener typedListener = new TypedListener(listener); addListener(SWT.Selection, typedListener); addListener(SWT.DefaultSelection, typedListener); } public void removeSelectionListener(SelectionListener listener) { checkWidget(); removeListener(SWT.Selection, listener); removeListener(SWT.DefaultSelection, listener); } public RadioItem[] getItems() { checkWidget(); if (items == null) return new RadioItem[0]; RadioItem[] result = new RadioItem[items.length]; System.arraycopy(items, 0, result, 0, items.length); return result; } public int indexOf(RadioItem item) { checkWidget(); if (items == null) return -1; if (item == null) return -1; for (int i = 0; i < items.length; i++) { if (items[i] == item) return i; } return -1; } public RadioItem getSelection() { checkWidget(); return selection; } public int getSelectionIndex() { checkWidget(); return indexOf(selection); } public void setSelection(RadioItem item) { checkWidget(); if (selection == item) return; if (selection != null) selection.deselect(); if (item != null) { if (item.getParent() != this) SWT.error(SWT.ERROR_INVALID_ARGUMENT); item.select(); } } public void select(int index) { checkWidget(); checkExistingPosition(index); setSelection(items[index]); } public void deselectAll() { checkWidget(); setSelection(null); } Button createButton(int itemStyle, int position) { // Check add position (which may throw exception) before creating button position = checkAddPosition(position); Button button = new Button(this, computeButtonStyle(itemStyle)); if (position < items.length) button.moveAbove(items[position].getButton()); layout(new Control[] { button }); return button; } private int computeButtonStyle(int itemStyle) { int buttonStyle = SWT.RADIO | this.buttonStyle; int itemStyleMask = SWT.LEFT | SWT.CENTER | SWT.RIGHT; if ((itemStyle & itemStyleMask) != 0) { buttonStyle &= ~itemStyleMask; buttonStyle |= itemStyle; } return buttonStyle; } void addItem(RadioItem item, int position) { position = checkAddPosition(position); RadioItem[] newItems = new RadioItem[items == null ? 1 : items.length + 1]; if (items == null) { items = new RadioItem[] { item }; } else { System.arraycopy(items, 0, newItems, 0, position); newItems[position] = item; System.arraycopy(items, position, newItems, position + 1, items.length - position); items = newItems; } } private int checkAddPosition(int position) { if (position == -1) position = getItemCount(); else if (position < 0 || position > getItemCount()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); return position; } void removeItem(RadioItem item) { checkWidget(); int position = indexOf(item); if (position != -1) { RadioItem[] newItems = new RadioItem[items.length - 1]; System.arraycopy(items, 0, newItems, 0, position); System.arraycopy(items, position + 1, newItems, position, newItems.length - position); items = newItems; } if (selection == item) { selection = null; notifyListeners(SWT.Selection, null); } } void itemSelected(RadioItem item) { RadioItem oldSelection = selection; RadioItem newSelection = item.isSelected() ? item : null; if (oldSelection == newSelection) return; selection = newSelection; Event event = new Event(); event.item = selection; event.index = indexOf(selection); notifyListeners(SWT.Selection, event); } }