package edu.ualberta.med.biobank.widgets.multiselect; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.ByteArrayTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Font; 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.Label; import org.eclipse.swt.widgets.Tree; import edu.ualberta.med.biobank.gui.common.BgcPlugin; import edu.ualberta.med.biobank.gui.common.widgets.BgcBaseWidget; import edu.ualberta.med.biobank.widgets.listeners.TreeViewerDragListener; import edu.ualberta.med.biobank.widgets.listeners.TreeViewerDropListener; public abstract class MultiSelectWidget<T> extends BgcBaseWidget { private TreeViewer selTree; private TreeViewer availTree; private Button moveRightButton; private Button moveLeftButton; private MultiSelectNode<T> selTreeRootNode = new MultiSelectNode<T>(null, null); private MultiSelectNode<T> availTreeRootNode = new MultiSelectNode<T>(null, null); private int minHeight; protected boolean ctrl; private List<T> allObjectsList = new ArrayList<T>(); private Transfer dndTransfer; /** * Default will drag and drop for ModelWrapper. Should use the other * constructor if want to use another one */ public MultiSelectWidget(Composite parent, int style, String leftLabel, String rightLabel, int minHeight) { this(parent, style, leftLabel, rightLabel, minHeight, MultiSelectNodeTransfer.getInstance()); } public MultiSelectWidget(Composite parent, int style, String leftLabel, String rightLabel, int minHeight, ByteArrayTransfer dndTransfer) { super(parent, style); this.dndTransfer = dndTransfer; this.minHeight = minHeight; setLayout(new GridLayout(3, false)); setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); availTree = createLabelledTree(this, leftLabel); availTree.setInput(availTreeRootNode); availTree.setComparator(new ViewerComparator()); Composite moveComposite = new Composite(this, SWT.NONE); moveComposite.setLayout(new GridLayout(1, false)); moveComposite.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, true)); moveRightButton = new Button(moveComposite, SWT.PUSH); moveRightButton.setImage(BgcPlugin.getDefault().getImageRegistry() .get(BgcPlugin.IMG_ARROW_RIGHT)); moveRightButton.setToolTipText(Messages.MultiSelectWidget_move_tooltip); moveLeftButton = new Button(moveComposite, SWT.PUSH); moveLeftButton.setImage(BgcPlugin.getDefault().getImageRegistry() .get(BgcPlugin.IMG_ARROW_LEFT)); moveLeftButton .setToolTipText(Messages.MultiSelectWidget_remove_tooltip); selTree = createLabelledTree(this, rightLabel); selTree.setInput(selTreeRootNode); selTree.setComparator(new ViewerComparator()); dragAndDropSupport(availTree, selTree); dragAndDropSupport(selTree, availTree); moveRightButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { moveTreeViewerSelection(availTree, selTree); } }); moveLeftButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { moveTreeViewerSelection(selTree, availTree); } }); } public void addSelections(Collection<T> allObjects, Collection<T> selectedObjects) { allObjectsList.addAll(allObjects); for (T o : allObjects) { if (selectedObjects.contains(o)) { selTreeRootNode.addChild(new MultiSelectNode<T>( selTreeRootNode, o)); } else { availTreeRootNode.addChild(new MultiSelectNode<T>( availTreeRootNode, o)); } } } /** * same as addSelections but remove previously set elements */ public void setSelections(Collection<T> allObjects, Collection<T> selectedObjects) { selTreeRootNode.clear(); availTreeRootNode.clear(); addSelections(allObjects, selectedObjects); selTreeRootNode.reset(); availTreeRootNode.reset(); } public void setFilter(ViewerFilter filter) { ViewerFilter[] filters = new ViewerFilter[] { filter }; availTree.setFilters(filters); selTree.setFilters(filters); } @SuppressWarnings("unchecked") private void moveTreeViewerSelection(TreeViewer srcTree, TreeViewer destTree) { MultiSelectNode<T> srcRootNode = (MultiSelectNode<T>) srcTree .getInput(); MultiSelectNode<T> destRootNode = (MultiSelectNode<T>) destTree .getInput(); List<?> fromSelection = ((IStructuredSelection) srcTree.getSelection()) .toList(); for (Object obj : fromSelection) { MultiSelectNode<T> node = (MultiSelectNode<T>) obj; destRootNode.addChild(node); srcRootNode.removeChild(node); destTree.reveal(node); srcTree.refresh(); } notifyListeners(); } public void selectAll() { availTree.getTree().selectAll(); moveTreeViewerSelection(availTree, selTree); } public void deselectAll() { selTree.getTree().selectAll(); moveTreeViewerSelection(selTree, availTree); } private TreeViewer createLabelledTree(Composite parent, String label) { Composite selComposite = new Composite(parent, SWT.NONE); selComposite.setLayout(new GridLayout(1, true)); GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true); selComposite.setLayoutData(gd); Label l = new Label(selComposite, SWT.NONE); l.setText(label); l.setFont(new Font(null, "sans-serif", 8, SWT.BOLD)); //$NON-NLS-1$ gd = new GridData(SWT.FILL, SWT.FILL, true, true); gd.horizontalSpan = 2; gd.horizontalAlignment = SWT.CENTER; l.setLayoutData(gd); TreeViewer tv = new TreeViewer(selComposite, SWT.MULTI | SWT.BORDER); gd = new GridData(SWT.FILL, SWT.FILL, true, true); gd.heightHint = minHeight; gd.widthHint = 180; tv.getTree().setLayoutData(gd); tv.getTree().addKeyListener(new KeyListener() { @Override public void keyPressed(KeyEvent e) { if ((e.stateMask & SWT.CTRL) != 0) ctrl = true; // check characters if (ctrl == true && e.keyCode == 'a') { ((Tree) e.getSource()).selectAll(); } } @Override public void keyReleased(KeyEvent e) { if ((e.stateMask & SWT.CTRL) != 0) ctrl = false; } }); tv.setLabelProvider(new LabelProvider() { @SuppressWarnings("unchecked") @Override public String getText(Object element) { MultiSelectNode<T> node = ((MultiSelectNode<T>) element); return getTextForObject(node.getNodeObject()); } }); tv.setContentProvider(new MultiSelectNodeContentProvider<T>()); return tv; } protected abstract String getTextForObject(T nodeObject); private void dragAndDropSupport(TreeViewer fromList, TreeViewer toList) { new TreeViewerDragListener<T>(fromList, dndTransfer); new TreeViewerDropListener<T>(toList, this); } /** * Return the selected items in the order specified by user. * */ public List<T> getSelected() { List<T> result = new ArrayList<T>(); for (MultiSelectNode<T> node : selTreeRootNode.getChildren()) { result.add(node.getNodeObject()); } return result; } public List<T> getAddedToSelection() { List<T> result = new ArrayList<T>(); for (MultiSelectNode<T> node : selTreeRootNode.getAddedChildren()) { result.add(node.getNodeObject()); } return result; } public List<T> getRemovedFromSelection() { List<T> result = new ArrayList<T>(); for (MultiSelectNode<T> node : selTreeRootNode.getRemovedChildren()) { result.add(node.getNodeObject()); } return result; } @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); selTree.getControl().setEnabled(enabled); availTree.getControl().setEnabled(enabled); } public void refreshLists() { availTree.refresh(); selTree.refresh(); } public Transfer getDndTransfer() { return dndTransfer; } }