/******************************************************************************* * Copyright (c) 2012 Obeo. * 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: * Obeo - initial API and implementation *******************************************************************************/ package org.eclipse.emf.eef.runtime.ui.widgets; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import org.eclipse.emf.eef.runtime.EEFRuntimePlugin; import org.eclipse.jface.viewers.IBaseLabelProvider; import org.eclipse.jface.viewers.IContentProvider; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.ITreeViewerListener; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.StructuredViewer; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.viewers.ViewerSorter; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.DragSourceListener; import org.eclipse.swt.dnd.DropTargetListener; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; 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.Widget; import com.google.common.collect.Lists; /** * @author <a href="mailto:goulwen.lefur@obeo.fr">Goulwen Le Fur</a> */ public class EReferenceEditor extends StructuredViewer { private int lowerBound = 0; private int upperBound = -1; private Composite control; private TreeViewer tree; private Collection<ReferenceEditorListener> listeners; private Button addButton; private Button removeButton; private Button upButton; private Button downButton; /** * @param parent * @param style */ public EReferenceEditor(Composite parent, int style) { control = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(4, false); layout.marginWidth = 0; layout.marginHeight = 0; control.setLayout(layout); addButton = new Button(control, SWT.PUSH); GridData addButtonData = new GridData(GridData.FILL_HORIZONTAL); addButtonData.horizontalAlignment = SWT.RIGHT; //addButton.setImage(EEFRuntimeUI.getPlugin().getRuntimeImage("Add")); addButton.setImage(EEFRuntimePlugin.getImage("Add")); addButton.setLayoutData(addButtonData); addButton.addSelectionListener(new SelectionAdapter() { /** * {@inheritDoc} * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) */ public void widgetSelected(SelectionEvent e) { for (ReferenceEditorListener listener : listeners) { listener.add(); } } }); GridData buttonData = new GridData(); buttonData.horizontalAlignment = SWT.RIGHT; removeButton = new Button(control, SWT.PUSH); //removeButton.setImage(EEFRuntimeUI.getPlugin().getRuntimeImage("Delete")); removeButton.setImage(EEFRuntimePlugin.getImage("Delete")); removeButton.setLayoutData(buttonData); removeButton.addSelectionListener(new ReferenceEditorSelectionAdapter() { /** * {@inheritDoc} * @see org.eclipse.emf.eef.runtime.ui.widgets.EReferenceEditor.ReferenceEditorSelectionAdapter#fireSingleSelection(java.lang.Object) */ public void fireSingleSelection(Object selection) { for (ReferenceEditorListener listener : listeners) { listener.remove(selection); } } /** * {@inheritDoc} * @see org.eclipse.emf.eef.runtime.ui.widgets.EReferenceEditor.ReferenceEditorSelectionAdapter#fireMultiSelection(java.util.List) */ protected void fireMultiSelection(List<?> selection) { for (ReferenceEditorListener listener : listeners) { listener.removeAll(selection); } } }); upButton = new Button(control, SWT.PUSH); //upButton.setImage(EEFRuntimeUI.getPlugin().getRuntimeImage("ArrowUp")); upButton.setImage(EEFRuntimePlugin.getImage("ArrowUp")); upButton.setLayoutData(buttonData); upButton.addSelectionListener(new ReferenceEditorSelectionAdapter() { /** * {@inheritDoc} * @see org.eclipse.emf.eef.runtime.ui.widgets.EReferenceEditor.ReferenceEditorSelectionAdapter#fireSingleSelection(java.lang.Object) */ public void fireSingleSelection(Object selection) { for (ReferenceEditorListener listener : listeners) { listener.moveUp(selection); } } }); downButton = new Button(control, SWT.PUSH); //downButton.setImage(EEFRuntimeUI.getPlugin().getRuntimeImage("ArrowDown")); downButton.setImage(EEFRuntimePlugin.getImage("ArrowDown")); downButton.setLayoutData(buttonData); downButton.addSelectionListener(new ReferenceEditorSelectionAdapter() { /** * {@inheritDoc} * @see org.eclipse.emf.eef.runtime.ui.widgets.EReferenceEditor.ReferenceEditorSelectionAdapter#fireSingleSelection(java.lang.Object) */ public void fireSingleSelection(Object selection) { for (ReferenceEditorListener listener : listeners) { listener.moveDown(selection); } } }); tree = new TreeViewer(control, style); GridData treeData = new GridData(GridData.FILL_BOTH); treeData.horizontalSpan = 4; tree.getControl().setLayoutData(treeData); tree.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { updateButtons(); } }); listeners = Lists.newArrayList(); } /** * @param lowerBound the lowerBound to set */ public void setLowerBound(int lowerBound) { this.lowerBound = lowerBound; } /** * @param upperBound the upperBound to set */ public void setUpperBound(int upperBound) { this.upperBound = upperBound; } /** * Add a {@link ReferenceEditorListener} to this instance. * @param listener {@link ReferenceEditorListener} to add. */ public void addReferenceEditorListener(ReferenceEditorListener listener) { listeners.add(listener); } /** * Remove a {@link ReferenceEditorListener} to this instance. * @param listener {@link ReferenceEditorListener} to remove. */ public void removeReferenceEditorListener(ReferenceEditorListener listener) { listeners.remove(listener); } /** * @see org.eclipse.jface.viewers.ContentViewer#getContentProvider() */ public IContentProvider getContentProvider() { return tree.getContentProvider(); } /** * @see org.eclipse.jface.viewers.ContentViewer#getInput() */ public Object getInput() { return tree.getInput(); } /** * {@inheritDoc} * @see org.eclipse.jface.viewers.Viewer#inputChanged(java.lang.Object, java.lang.Object) */ protected void inputChanged(Object input, Object oldInput) { tree.setInput(input); } /** * @see org.eclipse.jface.viewers.TreeViewer#getLabelProvider() */ public IBaseLabelProvider getLabelProvider() { return tree.getLabelProvider(); } /** * @see org.eclipse.jface.viewers.ColumnViewer#setLabelProvider(org.eclipse.jface.viewers.IBaseLabelProvider) */ public void setLabelProvider(IBaseLabelProvider labelProvider) { tree.setLabelProvider(labelProvider); } /** * @see org.eclipse.jface.viewers.StructuredViewer#addDoubleClickListener(org.eclipse.jface.viewers.IDoubleClickListener) */ public void addDoubleClickListener(IDoubleClickListener listener) { tree.addDoubleClickListener(listener); } /** * @see org.eclipse.jface.viewers.Viewer#setSelection(org.eclipse.jface.viewers.ISelection) */ public void setSelection(ISelection selection) { tree.setSelection(selection); } /** * @see org.eclipse.jface.viewers.StructuredViewer#addDragSupport(int, org.eclipse.swt.dnd.Transfer[], org.eclipse.swt.dnd.DragSourceListener) */ public void addDragSupport(int operations, Transfer[] transferTypes, DragSourceListener listener) { tree.addDragSupport(operations, transferTypes, listener); } /** * @see org.eclipse.jface.viewers.StructuredViewer#addDropSupport(int, org.eclipse.swt.dnd.Transfer[], org.eclipse.swt.dnd.DropTargetListener) */ public void addDropSupport(int operations, Transfer[] transferTypes, DropTargetListener listener) { tree.addDropSupport(operations, transferTypes, listener); } /** * @see org.eclipse.jface.viewers.StructuredViewer#addFilter(org.eclipse.jface.viewers.ViewerFilter) */ public void addFilter(ViewerFilter filter) { tree.addFilter(filter); } /** * @see org.eclipse.jface.viewers.StructuredViewer#getFilters() */ public ViewerFilter[] getFilters() { return tree.getFilters(); } /** * @see org.eclipse.jface.viewers.TreeViewer#setContentProvider(org.eclipse.jface.viewers.IContentProvider) */ public void setContentProvider(IContentProvider provider) { //super.setContentProvider(new NullContentProvider()); tree.setContentProvider(provider); } /** * @see org.eclipse.jface.viewers.StructuredViewer#getSorter() */ public ViewerSorter getSorter() { return tree.getSorter(); } /** * @see org.eclipse.jface.viewers.TreeViewer#setSelection(org.eclipse.jface.viewers.ISelection, boolean) */ public void setSelection(ISelection selection, boolean reveal) { tree.setSelection(selection, reveal); } /** * @see org.eclipse.jface.viewers.StructuredViewer#setFilters(org.eclipse.jface.viewers.ViewerFilter[]) */ public void setFilters(ViewerFilter[] filters) { tree.setFilters(filters); } /** * @param listener * @see org.eclipse.jface.viewers.Viewer#addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) */ public void addSelectionChangedListener(ISelectionChangedListener listener) { tree.addSelectionChangedListener(listener); } /** * @param listener * @see org.eclipse.jface.viewers.StructuredViewer#addPostSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) */ public void addPostSelectionChangedListener(ISelectionChangedListener listener) { tree.addPostSelectionChangedListener(listener); } /** * @param listener * @see org.eclipse.jface.viewers.AbstractTreeViewer#addTreeListener(org.eclipse.jface.viewers.ITreeViewerListener) */ public void addTreeListener(ITreeViewerListener listener) { tree.addTreeListener(listener); } /** * @param layoutData * @see org.eclipse.swt.widgets.Control#setLayoutData(java.lang.Object) */ public void setLayoutData(Object layoutData) { control.setLayoutData(layoutData); } /** * {@inheritDoc} * @see org.eclipse.jface.viewers.StructuredViewer#doFindInputItem(java.lang.Object) */ @Override protected Widget doFindInputItem(Object element) { //TODO return null; } /** * {@inheritDoc} * @see org.eclipse.jface.viewers.StructuredViewer#doFindItem(java.lang.Object) */ @Override protected Widget doFindItem(Object element) { //TODO return null; } /** * {@inheritDoc} * @see org.eclipse.jface.viewers.StructuredViewer#doUpdateItem(org.eclipse.swt.widgets.Widget, java.lang.Object, boolean) */ @Override protected void doUpdateItem(Widget item, Object element, boolean fullMap) { //TODO } /** * {@inheritDoc} * @see org.eclipse.jface.viewers.StructuredViewer#getSelectionFromWidget() */ @Override protected List<?> getSelectionFromWidget() { ISelection selection = tree.getSelection(); if (selection instanceof StructuredSelection) { return ((StructuredSelection) selection).toList(); } else { if (selection != null) { if (selection.isEmpty()) { return Collections.EMPTY_LIST; } else { return Lists.newArrayList(selection); } } } return Collections.emptyList(); } /** * {@inheritDoc} * @see org.eclipse.jface.viewers.StructuredViewer#internalRefresh(java.lang.Object) */ @Override protected void internalRefresh(Object element) { tree.refresh(); updateButtons(); } /** * {@inheritDoc} * @see org.eclipse.jface.viewers.StructuredViewer#reveal(java.lang.Object) */ @Override public void reveal(Object element) { tree.reveal(element); } /** * {@inheritDoc} * @see org.eclipse.jface.viewers.StructuredViewer#setSelectionToWidget(java.util.List, boolean) */ @Override protected void setSelectionToWidget(@SuppressWarnings("rawtypes") List elements, boolean reveal) { StructuredSelection selection = new StructuredSelection(elements); tree.setSelection(selection, reveal); } /** * {@inheritDoc} * @see org.eclipse.jface.viewers.Viewer#getControl() */ @Override public Control getControl() { return control; } /** * Update the list buttons. */ protected void updateButtons() { StructuredSelection selection = (StructuredSelection) tree.getSelection(); addButton.setEnabled(shouldEnableAdd(selection)); if (selection.size() == 0) { removeButton.setEnabled(false); upButton.setEnabled(false); downButton.setEnabled(false); } else if (selection.size() == 1) { removeButton.setEnabled(shouldEnableRemove(selection)); upButton.setEnabled(shouldEnableUp(selection)); downButton.setEnabled(shouldEnableDown(selection)); } else { removeButton.setEnabled(shouldEnableRemove(selection)); upButton.setEnabled(false); downButton.setEnabled(false); } } private boolean shouldEnableAdd(StructuredSelection selection) { Object[] elements = ((IStructuredContentProvider)tree.getContentProvider()).getElements(tree.getInput()); return ((upperBound == -1) || (elements.length < upperBound)); } private boolean shouldEnableRemove(StructuredSelection selection) { Object[] elements = ((IStructuredContentProvider)tree.getContentProvider()).getElements(tree.getInput()); return ((lowerBound == 0) || (elements.length > lowerBound)); } private boolean shouldEnableUp(StructuredSelection selection) { Object selectedElement = selection.getFirstElement(); Object[] elements = ((IStructuredContentProvider)tree.getContentProvider()).getElements(tree.getInput()); if (elements != null) { List<?> listInput = Arrays.asList(elements); return listInput.size() > 1 && listInput.indexOf(selectedElement) > 0; } return false; } private boolean shouldEnableDown(StructuredSelection selection) { Object selectedElement = selection.getFirstElement(); Object[] elements = ((IStructuredContentProvider)tree.getContentProvider()).getElements(tree.getInput()); if (elements != null) { List<?> listInput = Arrays.asList(elements); return (listInput.size() > 1) && (listInput.indexOf(selectedElement) < listInput.size() - 1); } return false; } /** * @author <a href="mailto:goulwen.lefur@obeo.fr">Goulwen Le Fur</a> * */ public interface ReferenceEditorListener { /** * Handle a "add" request. */ void add(); /** * Handle a "edit" request. * @param editedElement Edited Element. */ void edit(Object editedElement); /** * Handle a "remove" request. * @param removedElement Removed Element. */ void remove(Object removedElement); /** * Handle a "remove" request for several elements. * @param removedElements Removed Elements. */ void removeAll(Collection<?> removedElements); /** * Handle a "move up" request. * @param movedElement Moved Element. */ void moveUp(Object movedElement); /** * Handle a "move down" request. * @param movedElement Moved Element. */ void moveDown(Object movedElement); } /** * @author <a href="mailto:goulwen.lefur@obeo.fr">Goulwen Le Fur</a> * */ private abstract class ReferenceEditorSelectionAdapter extends SelectionAdapter { /** * {@inheritDoc} * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) */ public void widgetSelected(SelectionEvent e) { if (tree.getSelection() != null && !tree.getSelection().isEmpty()) { if (tree.getSelection() instanceof StructuredSelection) { StructuredSelection sSel = (StructuredSelection) tree.getSelection(); if (sSel.size() == 1) { fireSingleSelection(sSel.getFirstElement()); } else { fireMultiSelection((List<?>) sSel.toList()); } } } } public abstract void fireSingleSelection(Object selection); protected void fireMultiSelection(List<?> selection) { //do nothing } } }