package com.mobilesorcery.sdk.ui; import java.util.ArrayList; import java.util.List; import org.eclipse.jface.viewers.IBaseLabelProvider; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.ListViewer; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.SWT; 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.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Widget; /** * <p>A simple class for creating an editor for editing lists; * with add, remove, edit as well as [optional] up and down buttons.</p> * <p> * Example: * <blockquote><code> * SimpleListEditor editor = new SimpleListEditor(parent, SimpleListEditor.REARRANGEABLE); * editor.setInput(myList); * [...] * List edited = editor.getEditedInput(); * </code></blockquote> * </p> * @author Mattias Bybro * */ public class SimpleListEditor<T> extends Composite { private TableViewer list; protected Button add; protected Button edit; protected Button remove; protected Button up; protected Button down; private ArrayList<T> input; private boolean editAfterAdd = true; private Listener buttonListener; /** * A style constant for a rearrangeable list (ie up/down buttons * are added if {@link #createButtons(Composite)} is not overridden). */ public final static int REARRANGEABLE = SWT.UP | SWT.DOWN; public SimpleListEditor(Composite parent, int style) { super(parent, style); GridLayout layout = new GridLayout(2, false); layout.marginHeight = 0; layout.marginWidth = 0; setLayout(layout); list = new TableViewer(this); buttonListener = new Listener() { public void handleEvent(Event event) { buttonPressed(event.widget); } }; int numButtons = createButtons(this); list.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, numButtons)); list.setContentProvider(new ListContentProvider()); list.setLabelProvider(new LabelProvider()); list.getControl().addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { updateButtons(getSelection()); } }); updateButtons(getSelection()); } public void setLabelProvider(IBaseLabelProvider labelProvider) { this.list.setLabelProvider(labelProvider); } public void setEditAfterAdd(boolean editAfterAdd) { this.editAfterAdd = editAfterAdd; } /** * Sets the initial list of objects. * @param input */ public void setInput(List<T> input) { this.input = new ArrayList<T>(input); list.setInput(input); } public List<T> getEditedInput() { return input; } /** * Creates the buttons located to the right of the * list viewer. Clients may override. * @return The number of create buttons (used by layout manager) */ protected int createButtons(Composite main) { int numButtons = 3; add = createButton(main, "&Add"); edit = createButton(main, "&Edit"); remove = createButton(main, "&Remove"); if ((getStyle() & REARRANGEABLE) != 0) { up = createButton(main, "&Up"); down = createButton(main, "&Down"); numButtons = 5; } return numButtons; } protected Button createButton(Composite main, String caption) { Button button = new Button(main, SWT.PUSH); button.setText(caption); button.setLayoutData(new GridData(GridData.FILL, SWT.DEFAULT, true, false, 1, 1)); button.addListener(SWT.Selection, buttonListener); return button; } protected void buttonPressed(Widget widget) { ISelection selection = getSelection(); if (widget == add) { T added = add(getSelection().getFirstElement()); if (added != null) { selection = new StructuredSelection(added); } } else if (widget == edit) { edit(getSelection().getFirstElement(), false); } else if (widget == remove) { remove(getSelection()); } else if (widget == up) { up(getSelection()); } else if (widget == down) { down(getSelection()); } list.setInput(input); list.setSelection(selection); updateButtons(getSelection()); } protected IStructuredSelection getSelection() { return (IStructuredSelection) list.getSelection(); } protected void updateButtons(IStructuredSelection selection) { boolean enabled = selection.size() == 1; Object object = selection.getFirstElement(); enable(edit, enabled && canEdit(object)); enable(remove, enabled && canRemove(object)); enable(up, enabled && !isFirst(object) && canMoveUp(object)); enable(down, enabled && !isLast(object) && canMoveDown(object)); enable(add, canAdd(object)); } protected boolean canAdd(Object object) { return true; } protected boolean canMoveDown(Object object) { return true; } protected boolean canMoveUp(Object object) { return true; } protected boolean canRemove(Object object) { return true; } protected boolean canEdit(Object object) { return true; } private void enable(Control control, boolean enabled) { if (control != null) { control.setEnabled(enabled); } } /** * Moves the current selection up. Clients may override, * but in general should not need to. * @param selection */ protected void up(IStructuredSelection selection) { Object first = selection.getFirstElement(); int ix = input.indexOf(first); if (ix != -1 && !isFirst(first)) { input.remove(ix); input.add(ix - 1, (T) first); } } /** * Moves the current selection down. Clients may override, * but in general should not need to. * @param selection */ protected void down(IStructuredSelection selection) { Object first = selection.getFirstElement(); int ix = input.indexOf(first); if (ix != -1 && !isLast(first)) { input.remove(ix); input.add(ix + 1, (T) first); } } private boolean isLast(Object element) { return !input.isEmpty() && input.get(input.size() - 1) == element; } private boolean isFirst(Object element) { return !input.isEmpty() && input.get(0) == element; } /** * Removes the current selection. Clients may override, * but in general should not need to. * @param selection */ protected void remove(IStructuredSelection selection) { Object[] toBeRemoved = selection.toArray(); if (remove(toBeRemoved)) { for (Object element : selection.toArray()) { input.remove(element); } } } /** * Removes the current selection. Clients may override. * @param selection The objects to remove * @return <code>true</code> if they should be removed */ protected boolean remove(Object[] selection) { return true; } /** * Edits the current selection. Clients should override. * @param selection * @param add Whether this method was called after an "add" request * @return <code>true</code> if it should be added (only applicable for "add" requests); */ protected boolean edit(Object selection, boolean add) { return true; } /** * Adds an element to the list. Clients may override, * but in general should not need to. Instead, override * the {@link #createObject()} method. * @param nextObject The object this object should be inserted before, * or <code>null</code> if it should be added to the end of the list */ protected T add(Object nextObject) { T newObject = createObject(); boolean doAdd = newObject != null; if (editAfterAdd) { doAdd = edit(newObject, true); } if (doAdd) { int ix = nextObject == null ? -1 : input.indexOf(nextObject); if (ix == -1) { input.add(newObject); } else { input.add(ix, newObject); } return newObject; } return null; } protected T createObject() { return null; } protected TableViewer getList() { return list; } }