package com.tibco.as.spacebar.ui.wizards.space;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.core.databinding.beans.BeanProperties;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.list.IListChangeListener;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.list.ListChangeEvent;
import org.eclipse.core.databinding.observable.list.ListDiffEntry;
import org.eclipse.core.databinding.observable.list.WritableList;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.databinding.viewers.ViewerSupport;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
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.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
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.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TableColumn;
import com.tibco.as.space.FieldDef.FieldType;
import com.tibco.as.space.SpaceDef;
import com.tibco.as.spacebar.ui.model.Field;
import com.tibco.as.spacebar.ui.model.Metaspace;
import com.tibco.as.spacebar.ui.model.Metaspaces;
import com.tibco.as.spacebar.ui.model.Space;
import com.tibco.as.spacebar.ui.model.Spaces;
public class DualList<T> extends Composite implements IListChangeListener {
private TableViewer leftViewer;
private TableViewer rightViewer;
private IObservableList leftList;
private IObservableList rightList;
private Button addButton;
private Button addAllButton;
private Button removeButton;
private Button removeAllButton;
private Button upButton;
private Button downButton;
private Button topButton;
private Button bottomButton;
public DualList(Composite parent, int style, Class<T> type,
String propertyName, List<T> items) {
super(parent, style);
setLayout(new GridLayout(4, false));
leftViewer = createTableViewer();
Composite leftButtonPane = new Composite(this, SWT.NONE);
leftButtonPane.setLayout(new GridLayout());
GridDataFactory.fillDefaults().grab(false, true)
.align(GridData.CENTER, GridData.CENTER)
.applyTo(leftButtonPane);
addButton = createButton(leftButtonPane, "Add ->",
new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
selectItem();
}
});
addAllButton = createButton(leftButtonPane, "Add All ->",
new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
selectAll();
}
});
removeButton = createButton(leftButtonPane, "<- Remove",
new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
deselectItem();
}
});
removeAllButton = createButton(leftButtonPane, "<- Remove All",
new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
deselectAll();
}
});
leftViewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
addButton.setEnabled(!event.getSelection().isEmpty());
}
});
rightViewer = createTableViewer();
rightViewer.getTable().addMouseListener(new MouseAdapter() {
@Override
public void mouseDoubleClick(MouseEvent event) {
deselectItem();
}
});
Composite rightButtonPane = new Composite(this, SWT.NONE);
rightButtonPane.setLayout(new GridLayout());
GridDataFactory.fillDefaults().grab(false, true)
.align(GridData.CENTER, GridData.CENTER)
.applyTo(rightButtonPane);
upButton = createButton(rightButtonPane, "Up", new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
moveSelectionUp();
}
});
downButton = createButton(rightButtonPane, "Down",
new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
moveSelectionDown();
}
});
topButton = createButton(rightButtonPane, "Top",
new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
moveSelectionToFirstPosition();
}
});
bottomButton = createButton(rightButtonPane, "Bottom",
new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
moveSelectionToLastPosition();
}
});
rightViewer
.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
boolean hasSelection = !event.getSelection().isEmpty();
upButton.setEnabled(hasSelection);
downButton.setEnabled(hasSelection);
topButton.setEnabled(hasSelection);
bottomButton.setEnabled(hasSelection);
removeButton.setEnabled(hasSelection);
}
});
// data binding
leftList = WritableList.withElementType(type);
leftList.addListChangeListener(new IListChangeListener() {
@Override
public void handleListChange(ListChangeEvent event) {
addAllButton.setEnabled(!leftList.isEmpty());
}
});
leftList.addAll(items);
ViewerSupport.bind(leftViewer, leftList,
BeanProperties.value(type, propertyName));
rightList = WritableList.withElementType(type);
rightList.addListChangeListener(new IListChangeListener() {
@Override
public void handleListChange(ListChangeEvent event) {
removeAllButton.setEnabled(!rightList.isEmpty());
}
});
ViewerSupport.bind(rightViewer, rightList,
BeanProperties.value(type, propertyName));
}
private TableViewer createTableViewer() {
TableViewer tableViewer = new TableViewer(this);
GridDataFactory.fillDefaults().grab(true, true).span(1, 4)
.applyTo(tableViewer.getTable());
new TableColumn(tableViewer.getTable(), SWT.NONE);
return tableViewer;
}
public void setSelection(List<T> selection) {
for (T element : selection) {
addSelection(element);
}
}
public void addSelection(T element) {
rightList.add(element);
leftList.remove(element);
}
public void addSelection(Collection<T> elements) {
rightList.addAll(elements);
leftList.removeAll(elements);
}
/**
* 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(Composite parent, String text,
SelectionListener listener) {
Button button = new Button(parent, SWT.PUSH);
button.setText(text);
GridDataFactory.fillDefaults().grab(true, false).applyTo(button);
button.addSelectionListener(listener);
button.setEnabled(false);
return button;
}
/**
* 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() {
leftList.addAll(rightList);
rightList.clear();
}
/**
* 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 Object getItem(int index) {
return leftList.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() {
return leftList.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 removeItem(int index) {
leftList.remove(index);
}
/**
* 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 removeItems(int[] indices) {
for (int index : indices) {
leftList.remove(index);
}
}
/**
* 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 removeItems(int start, int end) {
for (int index = start; index < end; index++) {
leftList.remove(index);
}
}
/**
* 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 removeItem(Object item) {
leftList.remove(item);
}
/**
* 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 removeAllItems() {
leftList.clear();
}
/**
* 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(int index) {
if (index < 0 || index >= leftList.size()) {
return;
}
rightList.add(leftList.get(index));
}
/**
* 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(int[] indices) {
for (int index : indices) {
if (index < 0 || index >= leftList.size()) {
continue;
}
rightList.add(leftList.get(index));
}
}
/**
* 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
*
* @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>
*
* @see List#setSelection(int,int)
*/
public void select(int start, int end) {
for (int index = start; index <= end; index++) {
if (index < 0 || index >= leftList.size()) {
continue;
}
rightList.add(leftList.get(index));
}
}
/**
* 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() {
rightList.addAll(leftList);
leftList.clear();
}
/**
* @see org.eclipse.swt.widgets.Control#setBounds(int, int, int, int)
*/
@Override
public void setBounds(int x, int y, int width, int height) {
super.setBounds(x, y, width, height);
Point itemsTableDefaultSize = leftViewer.getTable().computeSize(
SWT.DEFAULT, SWT.DEFAULT);
Point selectionTableDefaultSize = rightViewer.getTable().computeSize(
SWT.DEFAULT, SWT.DEFAULT);
int itemsTableSize = leftViewer.getTable().getSize().x;
if (itemsTableDefaultSize.y > leftViewer.getTable().getSize().y) {
itemsTableSize -= leftViewer.getTable().getVerticalBar().getSize().x;
}
int selectionTableSize = rightViewer.getTable().getSize().x;
if (selectionTableDefaultSize.y > rightViewer.getTable().getSize().y) {
selectionTableSize -= rightViewer.getTable().getVerticalBar()
.getSize().x;
}
leftViewer.getTable().getColumn(0).setWidth(itemsTableSize);
rightViewer.getTable().getColumn(0).setWidth(selectionTableSize);
}
/**
* 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(int index, T item) {
leftList.set(index, item);
}
/**
* 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(T[] items) {
List<T> temp = new ArrayList<T>();
for (T item : items) {
temp.add(item);
}
leftList.clear();
leftList.addAll(temp);
}
/**
* Move the selected item to the first position
*/
@SuppressWarnings("unchecked")
protected void moveSelectionToFirstPosition() {
IStructuredSelection selection = (IStructuredSelection) rightViewer
.getSelection();
Object[] elements = selection.toArray();
for (int index = 0; index < elements.length; index++) {
rightList.remove(elements[index]);
rightList.add(index, elements[index]);
}
rightViewer.setSelection(new StructuredSelection(elements));
rightViewer.getTable().forceFocus();
}
/**
* Select a given item
*/
protected void selectItem() {
IStructuredSelection selection = (IStructuredSelection) leftViewer
.getSelection();
for (Object element : selection.toArray()) {
rightList.add(element);
leftList.remove(element);
}
}
/**
* Move the selected item up
*/
private void moveSelectionUp() {
ISelection selection = rightViewer.getSelection();
if (selection.isEmpty()) {
return;
}
List<?> selectionList = ((IStructuredSelection) selection).toList();
// starting with 2nd element because we can't move up the first element
for (int index = 1; index < rightList.size(); index++) {
Object element = rightList.get(index);
if (selectionList.contains(element)) {
rightList.set(index, rightList.get(index - 1));
rightList.set(index - 1, element);
}
}
rightViewer.setSelection(new StructuredSelection(selectionList));
}
private void moveSelectionDown() {
ISelection selection = rightViewer.getSelection();
if (selection.isEmpty()) {
return;
}
List<?> selectionList = ((IStructuredSelection) selection).toList();
// starting with penultimate because we can't move down the last element
for (int index = rightList.size() - 2; index >= 0; index--) {
Object element = rightList.get(index);
if (selectionList.contains(element)) {
rightList.set(index, rightList.get(index + 1));
rightList.set(index + 1, element);
}
}
rightViewer.setSelection(new StructuredSelection(selectionList));
}
/**
* Deselect a given item
*/
protected void deselectItem() {
IStructuredSelection selection = (IStructuredSelection) rightViewer
.getSelection();
for (Object element : selection.toArray()) {
leftList.add(element);
rightList.remove(element);
}
}
/**
* Move the selected item to the last position
*/
protected void moveSelectionToLastPosition() {
IStructuredSelection selection = (IStructuredSelection) rightViewer
.getSelection();
Object[] elements = selection.toArray();
for (Object element : elements) {
rightList.remove(element);
rightList.add(element);
}
rightViewer.setSelection(new StructuredSelection(elements));
rightViewer.getTable().forceFocus();
}
public static void main(String[] args) {
Metaspaces metaspaces = new Metaspaces();
Metaspace metaspace = new Metaspace();
metaspace.setMetaspaces(metaspaces);
Spaces spaces = new Spaces();
spaces.setMetaspace(metaspace);
Space space = new Space();
space.setSpaceDef(SpaceDef.create("space1"));
final List<Field> fields = new ArrayList<Field>();
final List<Field> selected = new ArrayList<Field>();
for (int index = 0; index < 2; index++) {
Field field = new Field();
field.setFields(space.getFields());
field.setName("Field" + (index + 1));
field.setType(FieldType.values()[index % FieldType.values().length]);
field.setNullable(true);
fields.add(field);
if (index < 10) {
selected.add(field);
}
}
Display display = new Display();
Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
public void run() {
// Build a UI
Display display = Display.getDefault();
Shell shell = new Shell(display);
shell.setLayout(new GridLayout());
DualList<Field> dualList = new DualList<Field>(shell, SWT.NONE,
Field.class, "name", fields);
dualList.setSelection(selected);
// dualList.setItems(new WritableList(fields, Field.class));
// Open and return the Shell
shell.setSize(640, 480);
shell.open();
// The SWT event loop
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
});
}
public IObservableList getSelection() {
return rightList;
}
@SuppressWarnings("unchecked")
@Override
public void handleListChange(ListChangeEvent event) {
for (ListDiffEntry entry : event.diff.getDifferences()) {
if (entry.isAddition()) {
if (entry.getPosition() >= leftList.size()) {
leftList.add(entry.getElement());
} else {
leftList.add(entry.getPosition(), entry.getElement());
}
} else {
leftList.remove(entry.getElement());
rightList.remove(entry.getElement());
}
}
}
}