diff options
Diffstat (limited to 'org.mihalis.opal/src/main/java/org/mihalis/opal/itemSelector/DualList.java')
-rw-r--r-- | org.mihalis.opal/src/main/java/org/mihalis/opal/itemSelector/DualList.java | 1858 |
1 files changed, 1858 insertions, 0 deletions
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/itemSelector/DualList.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/itemSelector/DualList.java new file mode 100644 index 0000000..94bfdbc --- /dev/null +++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/itemSelector/DualList.java @@ -0,0 +1,1858 @@ +/******************************************************************************* + * Copyright (c) 2011 Laurent CARON + * 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: + * Laurent CARON (laurent.caron at gmail dot com) - initial API and implementation + *******************************************************************************/ +package org.mihalis.opal.itemSelector; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; +import org.mihalis.opal.itemSelector.DLItem.LAST_ACTION; +import org.mihalis.opal.utils.SWTGraphicUtil; +import org.mihalis.opal.utils.SimpleSelectionAdapter; + +/** + * Instances of this class are controls that allow the user to select multiple + * elements. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>(none)</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection</dd> + * </dl> + */ + +public class DualList extends Composite { + + /** The Constant DOUBLE_DOWN_IMAGE. */ + private static final String DOUBLE_DOWN_IMAGE = "double_down.png"; + + /** The Constant DOUBLE_UP_IMAGE. */ + private static final String DOUBLE_UP_IMAGE = "double_up.png"; + + /** The Constant DOUBLE_LEFT_IMAGE. */ + private static final String DOUBLE_LEFT_IMAGE = "double_left.png"; + + /** The Constant DOUBLE_RIGHT_IMAGE. */ + private static final String DOUBLE_RIGHT_IMAGE = "double_right.png"; + + /** The Constant ARROW_DOWN_IMAGE. */ + private static final String ARROW_DOWN_IMAGE = "arrow_down.png"; + + /** The Constant ARROW_LEFT_IMAGE. */ + private static final String ARROW_LEFT_IMAGE = "arrow_left.png"; + + /** The Constant ARROW_UP_IMAGE. */ + private static final String ARROW_UP_IMAGE = "arrow_up.png"; + + /** The Constant ARROW_RIGHT_IMAGE. */ + private static final String ARROW_RIGHT_IMAGE = "arrow_right.png"; + + /** The items. */ + private final List<DLItem> items; + + /** The selection. */ + private final List<DLItem> selection; + + /** The items table. */ + private Table itemsTable; + + /** The selection table. */ + private Table selectionTable; + + /** The selection listeners. */ + private List<SelectionListener> selectionListeners; + + /** The selection change listeners. */ + private List<SelectionChangeListener> selectionChangeListeners; + + /** + * 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> + * </ul> + * + */ + public DualList(final Composite parent, final int style) { + super(parent, style); + items = new ArrayList<DLItem>(); + selection = new ArrayList<DLItem>(); + + setLayout(new GridLayout(4, false)); + createItemsTable(); + createButtonSelectAll(); + createSelectionTable(); + createButtonMoveFirst(); + createButtonSelect(); + createButtonMoveUp(); + createButtonDeselect(); + createButtonMoveDown(); + createButtonDeselectAll(); + createButtonMoveLast(); + } + + /** + * Creates the items table. + */ + private void createItemsTable() { + itemsTable = createTable(); + itemsTable.addMouseListener(new MouseAdapter() { + /** + * @see org.eclipse.swt.events.MouseAdapter#mouseDoubleClick(org.eclipse.swt.events.MouseEvent) + */ + @Override + public void mouseDoubleClick(final MouseEvent event) { + DualList.this.selectItem(); + } + }); + } + + /** + * Creates the table. + * + * @return a table that will contain data + */ + private Table createTable() { + final Table table = new Table(this, SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI | SWT.FULL_SELECTION); + table.setLinesVisible(false); + table.setHeaderVisible(false); + final GridData gd = new GridData(GridData.FILL, GridData.FILL, true, true, 1, 4); + gd.widthHint = 200; + table.setLayoutData(gd); +// new TableColumn(table, SWT.CENTER); +// new TableColumn(table, SWT.LEFT); + table.setData(-1); + return table; + } + + /** + * Creates the button select all. + */ + private void createButtonSelectAll() { + final Button buttonSelectAll = createButton(DOUBLE_RIGHT_IMAGE, true, GridData.END); + buttonSelectAll.addSelectionListener(new SimpleSelectionAdapter() { + /** + * @see org.mihalis.opal.utils.SimpleSelectionAdapter#handle(org.eclipse.swt.events.SelectionEvent) + */ + @Override + public void handle(final SelectionEvent e) { + DualList.this.selectAll(); + } + }); + } + + /** + * Creates the selection table. + */ + private void createSelectionTable() { + selectionTable = createTable(); + selectionTable.addMouseListener(new MouseAdapter() { + /** + * @see org.eclipse.swt.events.MouseAdapter#mouseDoubleClick(org.eclipse.swt.events.MouseEvent) + */ + @Override + public void mouseDoubleClick(final MouseEvent event) { + DualList.this.deselectItem(); + } + }); + } + + /** + * Creates the button move first. + */ + private void createButtonMoveFirst() { + final Button buttonMoveFirst = createButton(DOUBLE_UP_IMAGE, true, GridData.END); + buttonMoveFirst.addSelectionListener(new SimpleSelectionAdapter() { + /** + * @see org.mihalis.opal.utils.SimpleSelectionAdapter#handle(org.eclipse.swt.events.SelectionEvent) + */ + @Override + public void handle(final SelectionEvent e) { + DualList.this.moveSelectionToFirstPosition(); + } + }); + } + + /** + * Creates the button select. + */ + private void createButtonSelect() { + final Button buttonSelect = createButton(ARROW_RIGHT_IMAGE, false, GridData.CENTER); + buttonSelect.addSelectionListener(new SimpleSelectionAdapter() { + /** + * @see org.mihalis.opal.utils.SimpleSelectionAdapter#handle(org.eclipse.swt.events.SelectionEvent) + */ + @Override + public void handle(final SelectionEvent e) { + DualList.this.selectItem(); + } + }); + } + + /** + * Creates the button move up. + */ + private void createButtonMoveUp() { + final Button buttonMoveUp = createButton(ARROW_UP_IMAGE, false, GridData.CENTER); + buttonMoveUp.addSelectionListener(new SimpleSelectionAdapter() { + /** + * @see org.mihalis.opal.utils.SimpleSelectionAdapter#handle(org.eclipse.swt.events.SelectionEvent) + */ + @Override + public void handle(final SelectionEvent e) { + DualList.this.moveUpItem(); + } + }); + } + + /** + * Creates the button deselect. + */ + private void createButtonDeselect() { + final Button buttonDeselect = createButton(ARROW_LEFT_IMAGE, false, GridData.CENTER); + buttonDeselect.addSelectionListener(new SimpleSelectionAdapter() { + /** + * @see org.mihalis.opal.utils.SimpleSelectionAdapter#handle(org.eclipse.swt.events.SelectionEvent) + */ + @Override + public void handle(final SelectionEvent e) { + DualList.this.deselectItem(); + } + }); + } + + /** + * Creates the button move down. + */ + private void createButtonMoveDown() { + final Button buttonMoveDown = createButton(ARROW_DOWN_IMAGE, false, GridData.CENTER); + buttonMoveDown.addSelectionListener(new SimpleSelectionAdapter() { + /** + * @see org.mihalis.opal.utils.SimpleSelectionAdapter#handle(org.eclipse.swt.events.SelectionEvent) + */ + @Override + public void handle(final SelectionEvent e) { + DualList.this.moveDownItem(); + } + }); + } + + /** + * Creates the button deselect all. + */ + private void createButtonDeselectAll() { + final Button buttonDeselectAll = createButton(DOUBLE_LEFT_IMAGE, false, GridData.BEGINNING); + buttonDeselectAll.addSelectionListener(new SimpleSelectionAdapter() { + /** + * @see org.mihalis.opal.utils.SimpleSelectionAdapter#handle(org.eclipse.swt.events.SelectionEvent) + */ + @Override + public void handle(final SelectionEvent e) { + DualList.this.deselectAll(); + } + }); + } + + /** + * Creates the button move last. + */ + private void createButtonMoveLast() { + final Button buttonMoveLast = createButton(DOUBLE_DOWN_IMAGE, true, GridData.BEGINNING); + buttonMoveLast.addSelectionListener(new SimpleSelectionAdapter() { + /** + * @see org.mihalis.opal.utils.SimpleSelectionAdapter#handle(org.eclipse.swt.events.SelectionEvent) + */ + @Override + public void handle(final SelectionEvent e) { + DualList.this.moveSelectionToLastPosition(); + } + }); + } + + /** + * Create a button. + * + * @param fileName file name of the icon + * @param verticalExpand if <code>true</code>, the button will take all the + * available space vertically + * @param alignment button alignment + * @return a new button + */ + private Button createButton(final String fileName, final boolean verticalExpand, final int alignment) { + final Button button = new Button(this, SWT.PUSH); + final ClassLoader loader = org.mihalis.opal.itemSelector.DualList.class.getClassLoader(); + final Image image = new Image(getDisplay(), loader.getResourceAsStream("images/" + fileName)); + button.setImage(image); + button.setLayoutData(new GridData(GridData.CENTER, alignment, false, verticalExpand)); + SWTGraphicUtil.addDisposer(button, image); + return button; + } + + /** + * Adds the argument to the end of the receiver's list. + * + * @param item the new item + * @see #add(DLItem,int) + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the item 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> + */ + public void add(final DLItem item) { + checkWidget(); + if (item == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + items.add(item); + redrawTables(); + } + + /** + * Adds the argument to the receiver's list at the given zero-relative + * index. + * <p> + * Note: To add an item at the end of the list, use the result of calling + * <code>getItemCount()</code> as the index or use <code>add(DLItem)</code>. + * </p> + * + * @param item the new item + * @param index the index for the item + * @see #add(String) + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the item is null</li> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 + * and the number of elements in the list (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 void add(final DLItem item, final int index) { + checkWidget(); + if (item == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (index < 0 || index >= items.size()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + items.add(index, item); + redrawTables(); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the user changes the receiver's selection, by sending it one of the + * messages defined in the <code>SelectionListener</code> interface. + * + * @param listener the listener which should be notified + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener 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> + */ + public void addSelectionListener(final SelectionListener listener) { + checkWidget(); + if (listener == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (selectionListeners == null) { + selectionListeners = new ArrayList<SelectionListener>(); + } + selectionListeners.add(listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the user changes the receiver's selection. + * + * @param listener the listener which should no longer be notified + * @see SelectionListener + * @see #addSelectionListener + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener 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> + */ + public void removeSelectionListener(final SelectionListener listener) { + checkWidget(); + if (listener == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (selectionListeners == null) { + return; + } + selectionListeners.remove(listener); + } + + /** + * Adds the listener to the collection of listeners who will be notified + * when the user changes the receiver's selection, by sending it one of the + * messages defined in the <code>SelectionChangeListener</code> interface. + * + * @param listener the listener which should be notified + * @see SelectionChangeListener + * @see #removeSelectionChangeListener + * @see SelectionChangeEvent + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener 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> + */ + public void addSelectionChangeListener(final SelectionChangeListener listener) { + checkWidget(); + if (listener == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (selectionChangeListeners == null) { + selectionChangeListeners = new ArrayList<SelectionChangeListener>(); + } + selectionChangeListeners.add(listener); + } + + /** + * Removes the listener from the collection of listeners who will be + * notified when the user changes the receiver's selection. + * + * @param listener the listener which should no longer be notified + * @see SelectionChangeListener + * @see #addSelectionChangeListener + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener 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> + */ + public void removeSelectionChangeListener(final SelectionChangeListener listener) { + checkWidget(); + if (listener == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (selectionChangeListeners == null) { + return; + } + selectionChangeListeners.remove(listener); + } + + /** + * Deselects the item at the given zero-relative index in the receiver. If + * the item at the index was already deselected, it remains deselected. + * Indices that are out of range are ignored. + * + * @param index the index of the item to deselect + * + * @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 deselect(final int index) { + deselect(index, true); + } + + /** + * Deselects the item at the given zero-relative index in the receiver. If + * the item at the index was already deselected, it remains deselected. + * Indices that are out of range are ignored. + * + * @param index the index of the item to deselect + * + * @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 deselectDoNotFireEvent(final int index) { + deselect(index, false); + } + + /** + * Deselects the item at the given zero-relative index in the receiver. If + * the item at the index was already deselected, it remains deselected. + * Indices that are out of range are ignored. + * + * @param index the index of the item to deselect + * @param shouldFireEvents the should fire events + * @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> + */ + private void deselect(final int index, final boolean shouldFireEvents) { + checkWidget(); + if (index < 0 || index >= items.size()) { + return; + } + final DLItem item = selection.remove(index); + if (shouldFireEvents) { + fireSelectionEvent(item); + } + + final List<DLItem> deselectedItems = new ArrayList<DLItem>(); + item.setLastAction(LAST_ACTION.DESELECTION); + deselectedItems.add(item); + if (shouldFireEvents) { + fireSelectionChangeEvent(deselectedItems); + } + redrawTables(); + } + + /** + * Deselects the items at the given zero-relative indices in the receiver. + * If the item at the given zero-relative index in the receiver is selected, + * it is deselected. If the item at the index was not selected, it remains + * deselected. Indices that are out of range and duplicate indices are + * ignored. + * + * @param indices the array of indices for the items to deselect + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the set of indices 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> + */ + public void deselect(final int[] indices) { + deselect(indices, true); + } + + /** + * Deselects the items at the given zero-relative indices in the receiver. + * If the item at the given zero-relative index in the receiver is selected, + * it is deselected. If the item at the index was not selected, it remains + * deselected. Indices that are out of range and duplicate indices are + * ignored. + * + * @param indices the array of indices for the items to deselect + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the set of indices 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> + */ + public void deselectDoNotFireEvent(final int[] indices) { + deselect(indices, false); + } + + /** + * Deselects the items at the given zero-relative indices in the receiver. + * If the item at the given zero-relative index in the receiver is selected, + * it is deselected. If the item at the index was not selected, it remains + * deselected. Indices that are out of range and duplicate indices are + * ignored. + * + * @param indices the array of indices for the items to deselect + * @param shouldFireEvents the should fire events + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the set of indices 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> + */ + private void deselect(final int[] indices, final boolean shouldFireEvents) { + checkWidget(); + if (indices == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + + final List<DLItem> toBeRemoved = new ArrayList<DLItem>(); + + for (final int index : indices) { + if (index < 0 || index >= items.size()) { + continue; + } + toBeRemoved.add(selection.get(index)); + } + + for (final DLItem item : toBeRemoved) { + selection.remove(item); + if (shouldFireEvents) { + fireSelectionEvent(item); + } + } + if (shouldFireEvents) { + fireSelectionChangeEvent(toBeRemoved); + } + + toBeRemoved.clear(); + redrawTables(); + } + + /** + * Deselects the items at the given zero-relative indices in the receiver. + * If the item at the given zero-relative index in the receiver is selected, + * it is deselected. If the item at the index was not selected, it remains + * deselected. The range of the indices is inclusive. Indices that are out + * of range are ignored. + * + * @param start the start index of the items to deselect + * @param end the end index of the items to deselect + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if start is greater than end + * </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 deselect(final int start, final int end) { + deselect(start, end, true); + } + + /** + * Deselects the items at the given zero-relative indices in the receiver. + * If the item at the given zero-relative index in the receiver is selected, + * it is deselected. If the item at the index was not selected, it remains + * deselected. The range of the indices is inclusive. Indices that are out + * of range are ignored. + * + * @param start the start index of the items to deselect + * @param end the end index of the items to deselect + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if start is greater than end + * </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 deselectDoNotFireEvent(final int start, final int end) { + deselect(start, end, false); + } + + /** + * Deselect. + * + * @param start the start + * @param end the end + * @param shouldFireEvents the should fire events + */ + private void deselect(final int start, final int end, final boolean shouldFireEvents) { + checkWidget(); + if (start > end) { + SWT.error(SWT.ERROR_INVALID_RANGE); + } + final List<DLItem> toBeRemoved = new ArrayList<DLItem>(); + + for (int index = start; index <= end; index++) { + if (index < 0 || index >= items.size()) { + continue; + } + toBeRemoved.add(selection.get(index)); + } + + for (final DLItem item : toBeRemoved) { + selection.remove(item); + if (shouldFireEvents) { + fireSelectionEvent(item); + } + } + if (shouldFireEvents) { + fireSelectionChangeEvent(toBeRemoved); + } + toBeRemoved.clear(); + redrawTables(); + } + + /** + * Deselects all selected 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 void deselectAll() { + deselectAll(true); + } + + /** + * Deselects all selected 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 void deselectAllDoNotFireEvent() { + deselectAll(false); + } + + /** + * Deselects all selected items in the receiver. + * + * @param shouldFireEvents the should fire events + * @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 deselectAll(final boolean shouldFireEvents) { + checkWidget(); + items.addAll(selection); + + final List<DLItem> deselectedItems = new ArrayList<DLItem>(); + for (final DLItem item : selection) { + item.setLastAction(LAST_ACTION.DESELECTION); + deselectedItems.add(item); + if (shouldFireEvents) { + fireSelectionEvent(item); + } + } + fireSelectionChangeEvent(deselectedItems); + + selection.clear(); + redrawTables(); + } + + /** + * 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 DLItem getItem(final int index) { + checkWidget(); + if (index < 0 || index >= items.size()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + return items.get(index); + } + + /** + * 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 items.size(); + } + + /** + * Returns a (possibly empty) array of <code>DLItem</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's list + * + * @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 DLItem[] getItems() { + checkWidget(); + return items.toArray(new DLItem[items.size()]); + } + + /** + * Returns a (possibly empty) list of <code>DLItem</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's list + * + * @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 List<DLItem> getItemsAsList() { + checkWidget(); + return new ArrayList<DLItem>(items); + } + + /** + * Returns an array of <code>DLItem</code>s that are currently selected in + * the receiver. An empty array indicates that no items are selected. + * <p> + * Note: This is not the actual structure used by the receiver to maintain + * its selection, so modifying the array will not affect the receiver. + * </p> + * + * @return an array representing the selection + * + * @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 DLItem[] getSelection() { + checkWidget(); + return selection.toArray(new DLItem[items.size()]); + } + + /** + * Returns a list of <code>DLItem</code>s that are currently selected in the + * receiver. An empty array indicates that no items are selected. + * <p> + * Note: This is not the actual structure used by the receiver to maintain + * its selection, so modifying the array will not affect the receiver. + * </p> + * + * @return an array representing the selection + * + * @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 List<DLItem> getSelectionAsList() { + checkWidget(); + return new ArrayList<DLItem>(selection); + } + + /** + * Returns the number of selected items contained in the receiver. + * + * @return the number of selected 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 getSelectionCount() { + checkWidget(); + return selection.size(); + } + + /** + * Removes the item from the receiver at the given zero-relative index. + * + * @param index the index for the item + * + * @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 void remove(final int index) { + checkWidget(); + if (index < 0 || index >= items.size()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + items.remove(index); + redrawTables(); + } + + /** + * Removes the items from the receiver at the given zero-relative indices. + * + * @param indices the array of indices of the items + * + * @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> + * <li>ERROR_NULL_ARGUMENT - if the indices array 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> + */ + public void remove(final int[] indices) { + checkWidget(); + for (final int index : indices) { + if (index < 0 || index >= items.size()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + items.remove(index); + } + redrawTables(); + } + + /** + * Removes the items from the receiver which are between the given + * zero-relative start and end indices (inclusive). + * + * @param start the start of the range + * @param end the end of the range + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_INVALID_RANGE - if either the start or end are + * not between 0 and the number of elements in the list minus + * 1 (inclusive) or if start>end</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 remove(final int start, final int end) { + checkWidget(); + if (start > end) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + for (int index = start; index < end; index++) { + if (index < 0 || index >= items.size()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + items.remove(index); + } + redrawTables(); + } + + /** + * Searches the receiver's list starting at the first item until an item is + * found that is equal to the argument, and removes that item from the list. + * + * @param item the item to remove + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the item is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the item is not found in + * the list</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 remove(final DLItem item) { + checkWidget(); + if (item == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (!items.contains(item)) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + items.remove(item); + redrawTables(); + } + + /** + * Removes all of the items from the receiver. + * <p> + * + * @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 removeAll() { + checkWidget(); + items.clear(); + redrawTables(); + } + + /** + * Selects the item at the given zero-relative index in the receiver's list. + * If the item at the index was already selected, it remains selected. + * Indices that are out of range are ignored. + * + * @param index the index of the item to select + * + * @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 select(final int index) { + select(index, true); + } + + /** + * Selects the item at the given zero-relative index in the receiver's list. + * If the item at the index was already selected, it remains selected. + * Indices that are out of range are ignored. + * + * @param index the index of the item to select + * + * @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 selectDoNotFireEvent(final int index) { + select(index, false); + } + + /** + * Select. + * + * @param index the index + * @param shouldFireEvents the should fire events + */ + private void select(final int index, final boolean shouldFireEvents) { + checkWidget(); + if (index < 0 || index >= items.size()) { + return; + } + final List<DLItem> selectedItems = new ArrayList<DLItem>(); + final DLItem item = items.get(index); + item.setLastAction(LAST_ACTION.SELECTION); + selectedItems.add(item); + selection.add(item); + + if (shouldFireEvents) { + fireSelectionEvent(item); + fireSelectionChangeEvent(selectedItems); + } + + redrawTables(); + } + + /** + * Selects the items at the given zero-relative indices in the receiver. The + * current selection is not cleared before the new items are selected. + * <p> + * If the item at a given index is not selected, it is selected. If the item + * at a given index was already selected, it remains selected. Indices that + * are out of range and duplicate indices are ignored. If the receiver is + * single-select and multiple indices are specified, then all indices are + * ignored. + * + * @param indices the array of indices for the items to select + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the array of indices 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> + */ + public void select(final int[] indices) { + select(indices, true); + } + + /** + * Selects the items at the given zero-relative indices in the receiver. The + * current selection is not cleared before the new items are selected. + * <p> + * If the item at a given index is not selected, it is selected. If the item + * at a given index was already selected, it remains selected. Indices that + * are out of range and duplicate indices are ignored. If the receiver is + * single-select and multiple indices are specified, then all indices are + * ignored. + * + * @param indices the array of indices for the items to select + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the array of indices 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> + */ + public void selectDoNotFireEvent(final int[] indices) { + select(indices, false); + } + + /** + * Select. + * + * @param indices the indices + * @param shouldFireEvents the should fire events + */ + private void select(final int[] indices, final boolean shouldFireEvents) { + checkWidget(); + if (indices == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + + final List<DLItem> selectedItems = new ArrayList<DLItem>(); + for (final int index : indices) { + if (index < 0 || index >= items.size()) { + continue; + } + final DLItem item = items.get(index); + item.setLastAction(LAST_ACTION.SELECTION); + selectedItems.add(item); + + selection.add(item); + if (shouldFireEvents) { + fireSelectionEvent(item); + } + } + if (shouldFireEvents) { + fireSelectionChangeEvent(selectedItems); + } + redrawTables(); + } + + /** + * Selects the items in the range specified by the given zero-relative + * indices in the receiver. The range of indices is inclusive. The current + * selection is not cleared before the new items are selected. + * <p> + * If an item in the given range is not selected, it is selected. If an item + * in the given range was already selected, it remains selected. Indices + * that are out of range are ignored and no items will be selected if start + * is greater than end. If the receiver is single-select and there is more + * than one item in the given range, then all indices are ignored. + * + * @param start the start of the range + * @param end the end of the range + * @see List#setSelection(int,int) + * @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 select(final int start, final int end) { + select(start, end, true); + } + + /** + * Selects the items in the range specified by the given zero-relative + * indices in the receiver. The range of indices is inclusive. The current + * selection is not cleared before the new items are selected. + * <p> + * If an item in the given range is not selected, it is selected. If an item + * in the given range was already selected, it remains selected. Indices + * that are out of range are ignored and no items will be selected if start + * is greater than end. If the receiver is single-select and there is more + * than one item in the given range, then all indices are ignored. + * + * @param start the start of the range + * @param end the end of the range + * @see List#setSelection(int,int) + * @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 selectDoNotFireEvent(final int start, final int end) { + select(start, end, false); + } + + /** + * Select. + * + * @param start the start + * @param end the end + * @param shouldFireEvents the should fire events + */ + private void select(final int start, final int end, final boolean shouldFireEvents) { + checkWidget(); + if (start > end) { + SWT.error(SWT.ERROR_INVALID_RANGE); + } + final List<DLItem> selectedItems = new ArrayList<DLItem>(); + for (int index = start; index <= end; index++) { + if (index < 0 || index >= items.size()) { + continue; + } + final DLItem item = items.get(index); + item.setLastAction(LAST_ACTION.SELECTION); + selectedItems.add(item); + selection.add(item); + if (shouldFireEvents) { + fireSelectionEvent(item); + } + } + if (shouldFireEvents) { + fireSelectionChangeEvent(selectedItems); + } + redrawTables(); + } + + /** + * Selects all of the items in the receiver. + * <p> + * If the receiver is single-select, do nothing. + * + * @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 selectAll() { + selectAll(true); + } + + /** + * Selects all of the items in the receiver. + * <p> + * If the receiver is single-select, do nothing. + * + * @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 selectAllDoNotFireEvent() { + selectAll(false); + } + + /** + * Select all. + * + * @param shouldFireEvents the should fire events + */ + private void selectAll(final boolean shouldFireEvents) { + checkWidget(); + selection.addAll(items); + if (shouldFireEvents) { + for (final DLItem item : items) { + fireSelectionEvent(item); + } + } + + if (shouldFireEvents) { + final List<DLItem> selectedItems = new ArrayList<DLItem>(); + for (final DLItem item : items) { + item.setLastAction(LAST_ACTION.SELECTION); + selectedItems.add(item); + } + fireSelectionChangeEvent(selectedItems); + } + items.clear(); + redrawTables(); + } + + /** + * Sets the bounds. + * + * @param x the x + * @param y the y + * @param width the width + * @param height the height + * @see org.eclipse.swt.widgets.Control#setBounds(int, int, int, int) + */ + @Override + public void setBounds(final int x, final int y, final int width, final int height) { + super.setBounds(x, y, width, height); + final boolean itemsContainImage = itemsContainImage(); + final Point itemsTableDefaultSize = itemsTable.computeSize(SWT.DEFAULT, SWT.DEFAULT); + final Point selectionTableDefaultSize = selectionTable.computeSize(SWT.DEFAULT, SWT.DEFAULT); + + int itemsTableSize = itemsTable.getSize().x; + if (itemsTableDefaultSize.y > itemsTable.getSize().y) { + itemsTableSize -= itemsTable.getVerticalBar().getSize().x; + } + + int selectionTableSize = selectionTable.getSize().x; + if (selectionTableDefaultSize.y > selectionTable.getSize().y) { + selectionTableSize -= selectionTable.getVerticalBar().getSize().x; + } + + if (itemsContainImage) { + itemsTable.getColumn(0).pack(); + itemsTable.getColumn(1).setWidth(itemsTableSize - itemsTable.getColumn(0).getWidth()); + + selectionTable.getColumn(0).pack(); + selectionTable.getColumn(1).setWidth(selectionTableSize - selectionTable.getColumn(0).getWidth()); + + } else { + itemsTable.getColumn(0).setWidth(itemsTableSize); + selectionTable.getColumn(0).setWidth(selectionTableSize); + } + + itemsTable.getColumn(0).pack(); + selectionTable.getColumn(0).pack(); + } + + /** + * Items contain image. + * + * @return <code>true</code> if any item contains an image + */ + private boolean itemsContainImage() { + for (final DLItem item : items) { + if (item.getImage() != null) { + return true; + } + } + + for (final DLItem item : selection) { + if (item.getImage() != null) { + return true; + } + } + + return false; + } + + /** + * Sets the item in the receiver's list at the given zero-relative index to + * the item argument. + * + * @param index the index for the item + * @param item the new item + * + * @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> + * <li>ERROR_NULL_ARGUMENT - if the item 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> + */ + public void setItem(final int index, final DLItem item) { + checkWidget(); + if (item == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (index < 0 || index >= items.size()) { + SWT.error(SWT.ERROR_INVALID_RANGE); + } + items.set(index, item); + redrawTables(); + } + + /** + * Sets the receiver's items to be the given array of items. + * + * @param items the array of items + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the items array is null</li> + * <li>ERROR_INVALID_ARGUMENT - if an item in the items array + * 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> + */ + public void setItems(final DLItem[] items) { + checkWidget(); + if (items == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + + final List<DLItem> temp = new ArrayList<DLItem>(); + for (final DLItem item : items) { + if (item == null) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + temp.add(item); + } + this.items.clear(); + this.items.addAll(temp); + redrawTables(); + } + + /** + * Sets the receiver's items to be the given list of items. + * + * @param items the list of items + * + * @exception IllegalArgumentException + * <ul> + * <li>ERROR_NULL_ARGUMENT - if the items list is null</li> + * <li>ERROR_INVALID_ARGUMENT - if an item in the items list + * 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> + */ + public void setItems(final List<DLItem> items) { + checkWidget(); + checkWidget(); + if (items == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + + final List<DLItem> temp = new ArrayList<DLItem>(); + for (final DLItem item : items) { + if (item == null) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + temp.add(item); + } + this.items.clear(); + this.items.addAll(temp); + redrawTables(); + } + + /** + * Redraws all tables that compose this widget. + */ + private void redrawTables() { + setRedraw(false); + redrawTable(itemsTable, false); + redrawTable(selectionTable, true); + setRedraw(true); + this.setBounds(getBounds()); + } + + /** + * Redraw a given table. + * + * @param table table to be redrawned + * @param isSelected if <code>true</code>, fill the table with the + * selection. Otherwise, fill the table with the unselected + * items. + */ + private void redrawTable(final Table table, final boolean isSelected) { + clean(table); + fillData(table, isSelected ? selection : items); + } + + /** + * Cleans the content of a table. + * + * @param table table to be emptied + */ + private void clean(final Table table) { + if (table == null) { + return; + } + + for (final TableItem item : table.getItems()) { + item.dispose(); + } + } + + /** + * Fill a table with data. + * + * @param table table to be filled + * @param listOfData list of data + */ + private void fillData(final Table table, final List<DLItem> listOfData) { + final boolean itemsContainImage = itemsContainImage(); + for (final DLItem item : listOfData) { + final TableItem tableItem = new TableItem(table, SWT.NONE); + tableItem.setData(item); + + if (item.getBackground() != null) { + tableItem.setBackground(item.getBackground()); + } + + if (item.getForeground() != null) { + tableItem.setForeground(item.getForeground()); + } + + if (item.getImage() != null) { + tableItem.setImage(0, item.getImage()); + } + + if (item.getFont() != null) { + tableItem.setFont(item.getFont()); + } + final int textColumn = itemsContainImage ? 1 : 0; + tableItem.setText(textColumn, item.getText()); + } + } + + /** + * Move the selected item to the first position. + */ + protected void moveSelectionToFirstPosition() { + if (selectionTable.getSelectionCount() == 0) { + return; + } + + int index = 0; + for (final TableItem tableItem : selectionTable.getSelection()) { + final DLItem item = (DLItem) tableItem.getData(); + selection.remove(item); + selection.add(index++, item); + } + + redrawTables(); + selectionTable.select(0, index - 1); + selectionTable.forceFocus(); + } + + /** + * Select a given item. + */ + protected void selectItem() { + if (itemsTable.getSelectionCount() == 0) { + return; + } + final List<DLItem> selectedItems = new ArrayList<DLItem>(); + for (final TableItem tableItem : itemsTable.getSelection()) { + final DLItem item = (DLItem) tableItem.getData(); + item.setLastAction(LAST_ACTION.SELECTION); + selectedItems.add(item); + selection.add(item); + items.remove(item); + fireSelectionEvent(item); + } + fireSelectionChangeEvent(selectedItems); + + redrawTables(); + } + + /** + * Move the selected item up. + */ + protected void moveUpItem() { + if (selectionTable.getSelectionCount() == 0) { + return; + } + + for (final int index : selectionTable.getSelectionIndices()) { + if (index == 0) { + selectionTable.forceFocus(); + return; + } + } + + final int[] newSelection = new int[selectionTable.getSelectionCount()]; + int newSelectionIndex = 0; + for (final TableItem tableItem : selectionTable.getSelection()) { + final int position = selection.indexOf(tableItem.getData()); + swap(position, position - 1); + newSelection[newSelectionIndex++] = position - 1; + } + + redrawTables(); + selectionTable.select(newSelection); + selectionTable.forceFocus(); + } + + /** + * Deselect a given item. + */ + protected void deselectItem() { + if (selectionTable.getSelectionCount() == 0) { + return; + } + final List<DLItem> deselectedItems = new ArrayList<DLItem>(); + for (final TableItem tableItem : selectionTable.getSelection()) { + final DLItem item = (DLItem) tableItem.getData(); + item.setLastAction(LAST_ACTION.DESELECTION); + deselectedItems.add(item); + items.add(item); + selection.remove(item); + fireSelectionEvent(item); + } + fireSelectionChangeEvent(deselectedItems); + redrawTables(); + } + + /** + * Move the selected item down. + */ + protected void moveDownItem() { + if (selectionTable.getSelectionCount() == 0) { + return; + } + + for (final int index : selectionTable.getSelectionIndices()) { + if (index == selectionTable.getItemCount() - 1) { + selectionTable.forceFocus(); + return; + } + } + + final int[] newSelection = new int[selectionTable.getSelectionCount()]; + int newSelectionIndex = 0; + for (final TableItem tableItem : selectionTable.getSelection()) { + final int position = selection.indexOf(tableItem.getData()); + swap(position, position + 1); + newSelection[newSelectionIndex++] = position + 1; + } + + redrawTables(); + selectionTable.select(newSelection); + selectionTable.forceFocus(); + } + + /** + * Swap 2 items. + * + * @param first position of the first item to swap + * @param second position of the second item to swap + */ + private void swap(final int first, final int second) { + final DLItem temp = selection.get(first); + selection.set(first, selection.get(second)); + selection.set(second, temp); + } + + /** + * Move the selected item to the last position. + */ + protected void moveSelectionToLastPosition() { + if (selectionTable.getSelectionCount() == 0) { + return; + } + + final int numberOfSelectedElements = selectionTable.getSelectionCount(); + for (final TableItem tableItem : selectionTable.getSelection()) { + final DLItem item = (DLItem) tableItem.getData(); + selection.remove(item); + selection.add(item); + } + + redrawTables(); + final int numberOfElements = selectionTable.getItemCount(); + selectionTable.select(numberOfElements - numberOfSelectedElements, numberOfElements - 1); + selectionTable.forceFocus(); + } + + /** + * Call all selection listeners. + * + * @param item selected item + */ + private void fireSelectionEvent(final DLItem item) { + if (selectionListeners == null) { + return; + } + + final Event event = new Event(); + event.button = 1; + event.display = getDisplay(); + event.item = null; + event.widget = this; + event.data = item; + final SelectionEvent selectionEvent = new SelectionEvent(event); + + for (final SelectionListener listener : selectionListeners) { + listener.widgetSelected(selectionEvent); + } + } + + /** + * Fire selection change event. + * + * @param items the items + */ + private void fireSelectionChangeEvent(final List<DLItem> items) { + if (selectionChangeListeners == null) { + return; + } + + final Event event = new Event(); + event.button = 1; + event.display = getDisplay(); + event.item = null; + event.widget = this; + final SelectionChangeEvent selectionChangeEvent = new SelectionChangeEvent(event); + selectionChangeEvent.setItems(items); + + for (final SelectionChangeListener listener : selectionChangeListeners) { + listener.widgetSelected(selectionChangeEvent); + } + } +} |