package org.simantics.document.linking.wizard; import java.util.HashMap; import java.util.Map; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.LocalResourceManager; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.ColumnViewer; import org.eclipse.jface.viewers.ColumnViewerEditor; import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent; import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy; import org.eclipse.jface.viewers.ICellModifier; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TextCellEditor; import org.eclipse.jface.viewers.TreeSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.TreeViewerEditor; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerDropAdapter; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DragSourceEvent; import org.eclipse.swt.dnd.DragSourceListener; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.dnd.TransferData; import org.eclipse.swt.events.MenuDetectEvent; import org.eclipse.swt.events.MenuDetectListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.plugin.AbstractUIPlugin; import org.simantics.browsing.ui.swt.ComboBoxCellEditor2; import org.simantics.document.linking.report.evaluator.EnumEditableNode; import org.simantics.document.linking.report.evaluator.EvaluatorItem; import org.simantics.document.linking.report.evaluator.EvaluatorNode; import org.simantics.document.linking.report.evaluator.EvaluatorRoot; import org.simantics.document.linking.report.evaluator.StringEditableNode; import org.simantics.document.linking.report.templates.custom.EvaluatorCustomizableContent; import org.simantics.ui.dnd.LocalObjectTransfer; /** * UI component for configuring evaluator trees. * * @author Marko Luukkainen * */ public class EvaluatorConfigurationWidget extends Composite { EvaluatorCustomizableContent input; LocalResourceManager manager; EvaluatorRoot root; TreeViewer viewer; public EvaluatorConfigurationWidget(Composite parent, LocalResourceManager manager, int style) { super(parent, style); this.manager = manager; root = new EvaluatorRoot(); setLayout(new GridLayout(1,false)); viewer = new TreeViewer(this); TreeViewerEditor.create(viewer, null, new DoubleClickEditorActivationStrategy(viewer), ColumnViewerEditor.DEFAULT); viewer.setContentProvider(new EvaluatorNodeContentProvider()); viewer.setLabelProvider(new EvaluatorLabelProvider()); viewer.setCellEditors(new CellEditor[]{new EvaluatorNodeCellEditor(viewer.getTree())}); viewer.setCellModifier(new EvaluatorNodeCellModifier()); viewer.setColumnProperties(new String[]{"value"}); viewer.setInput(root); viewer.getTree().addMenuDetectListener(new MenuDetectListener() { @Override public void menuDetected(MenuDetectEvent e) { StructuredSelection sel = (StructuredSelection)viewer.getSelection(); createPopupMenu(e, sel); } }); int operations = DND.DROP_COPY| DND.DROP_MOVE; viewer.addDragSupport(operations, new Transfer[]{LocalObjectTransfer.getTransfer()}, new DragSourceListener() { @Override public void dragStart(DragSourceEvent event) { ISelection sel = viewer.getSelection(); event.doit = !sel.isEmpty(); } @Override public void dragSetData(DragSourceEvent event) { if (LocalObjectTransfer.getTransfer().isSupportedType(event.dataType)) { event.data = viewer.getSelection(); } } @Override public void dragFinished(DragSourceEvent event) { // TODO Auto-generated method stub } }); viewer.addDropSupport(operations, new Transfer[]{LocalObjectTransfer.getTransfer()}, new ViewerDropAdapter(viewer) { @Override public boolean validateDrop(Object target, int operation, TransferData transferType) { if ((operation & DND.DROP_COPY) > 0) { return true; } else if ((operation & DND.DROP_MOVE) > 0) { return true; } else { return false; } } @Override public boolean performDrop(Object data) { EvaluatorItem item = (EvaluatorItem)determineTarget(getCurrentEvent()); EvaluatorNode parent = item.getParent(); EvaluatorItem toProcess = (EvaluatorItem)((TreeSelection)data).getFirstElement(); if (toProcess == null) return false; EvaluatorNode toProcessParent = toProcess.getParent(); int index = parent.indexOf(item); boolean copy = false; if ((getCurrentOperation() & DND.DROP_COPY) > 0) { copy = true; toProcess = toProcess.copy(); } switch (getCurrentLocation()) { case LOCATION_BEFORE: { if (!dropValid(parent, toProcessParent, toProcess, index, copy)) return false; if (!copy && toProcessParent != null) { toProcessParent.removeChild(toProcess); viewer.refresh(toProcessParent); } parent.addChild(index, toProcess); viewer.refresh(parent); return true; } case LOCATION_AFTER: { if (!dropValid(parent, toProcessParent, toProcess, index, copy)) return false; if (!copy && toProcessParent != null) { toProcessParent.removeChild(toProcess); viewer.refresh(toProcessParent); } parent.addChild(index+1, toProcess); viewer.refresh(parent); return true; } case LOCATION_ON: { if (item instanceof EvaluatorNode) { EvaluatorNode node = ((EvaluatorNode)item); if (!dropValid(node, toProcessParent, toProcess, index, copy)) return false; if (!copy && toProcessParent != null) { toProcessParent.removeChild(toProcess); viewer.refresh(toProcessParent); } node.addChild(toProcess); viewer.refresh(item); if (!copy) return true; } return false; } } return false; } }); GridDataFactory.fillDefaults().span(1, 1).grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(viewer.getTree()); } private boolean dropValid(EvaluatorNode parent, EvaluatorNode toProcessParent, EvaluatorItem toProcess, int index, boolean copy) { if (parent.equals(toProcessParent)) { if (copy && !parent.acceptChild(index,toProcess)) return false; } else { if (!parent.acceptChild(index,toProcess)) return false; } return true; } public void setInput(EvaluatorCustomizableContent content) { input = content; } public void updateContent() { if (input != null) { viewer.getTree().setEnabled(true); root.getChildren().clear(); root.addChild(input.getItem()); root.setSupportStyles(input.isSupportStyles()); root.setSupportMultiline(input.isSupportMultiline()); viewer.setInput(root); } else { root.getChildren().clear(); viewer.setInput(root); viewer.getTree().setEnabled(false); } } private Map, Image> imageMap = new HashMap, Image>(); private Image getImage(Class cls) { Image image = imageMap.get(cls); if (image == null) { try { EvaluatorItem tempItem = (EvaluatorItem)cls.newInstance(); ImageDescriptor imageDescriptor = tempItem.getImage(); if (imageDescriptor != null) { image = manager.createImage(imageDescriptor); imageMap.put(cls, image); } } catch (Exception e1) { imageMap.put(cls, null); } } return image; } private void createPopupMenu(MenuDetectEvent event, StructuredSelection sel) { EvaluatorItem i = null; if (sel.isEmpty()) { i = root; } else { i = (EvaluatorItem) sel.getFirstElement(); } final EvaluatorItem item = i; Menu menu = new Menu(viewer.getControl()); MenuItem add = new MenuItem(menu, SWT.CASCADE); add.setText("Add"); Menu addMenu = new Menu(menu); add.setMenu(addMenu); add.setImage(manager.createImage(AbstractUIPlugin.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/arrow_right.png"))); MenuItem insert = new MenuItem(menu, SWT.CASCADE); insert.setText("Insert"); Menu insertMenu = new Menu(menu); insert.setMenu(insertMenu); insert.setImage(manager.createImage(AbstractUIPlugin.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/arrow_left.png"))); // add menu if (item instanceof EvaluatorNode) { final EvaluatorNode node = (EvaluatorNode)item; for (final Class cls : node.getPossibleChildren(true)) { MenuItem menuItem = new MenuItem(addMenu, SWT.PUSH); menuItem.setText(cls.getSimpleName()); menuItem.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { node.createChild(cls); update(node); }; }); menuItem.setImage(getImage(cls)); } } if (addMenu.getItemCount() == 0) add.setEnabled(false); if (item.getParent() != null) { final EvaluatorNode node = item.getParent(); for (final Class cls : node.getPossibleChildren(false)) { if (EvaluatorNode.class.isAssignableFrom(cls)) { MenuItem menuItem = new MenuItem(insertMenu, SWT.PUSH); menuItem.setText(cls.getSimpleName()); menuItem.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { int index = node.indexOf(item); node.removeChild(item); EvaluatorNode inserted = (EvaluatorNode)node.createChild(index,cls); inserted.addChild(item); update(node); }; }); menuItem.setImage(getImage(cls)); } } } if (insertMenu.getItemCount() == 0) insert.setEnabled(false); MenuItem menuItem = new MenuItem(menu, SWT.PUSH); menuItem.setText("Remove"); menuItem.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { EvaluatorNode parent = item.getParent(); if (parent != null) { parent.removeChild(item); update(parent); } }; }); menuItem.setEnabled(item != root); menuItem.setImage(manager.createImage(AbstractUIPlugin.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/delete.png"))); menu.setLocation(event.x,event.y); menu.setVisible(true); } private void update(EvaluatorItem item) { viewer.refresh(item); if (item == root) { if (root.getChildren().size() > 0) { input.setItem(root.getChildren().get(0)); } else { //input.setItem(null); } } } private class EvaluatorLabelProvider extends LabelProvider { @Override public Image getImage(Object element) { EvaluatorItem item = (EvaluatorItem)element; ImageDescriptor descriptor = item.getImage(); if (descriptor == null) return null; return manager.createImage(descriptor); } } private class EvaluatorNodeContentProvider implements ITreeContentProvider { @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } @Override public void dispose() { } @Override public boolean hasChildren(Object element) { if (element instanceof EvaluatorNode) { return true; } return false; } @Override public Object getParent(Object element) { if (element instanceof EvaluatorItem) { return ((EvaluatorItem)element).getParent(); } return null; } @Override public Object[] getElements(Object inputElement) { if (inputElement instanceof EvaluatorNode) { EvaluatorNode node = (EvaluatorNode)inputElement; return node.getChildren().toArray(); } return new Object[0]; } @Override public Object[] getChildren(Object parentElement) { if (parentElement instanceof EvaluatorNode) { EvaluatorNode node = (EvaluatorNode)parentElement; return node.getChildren().toArray(); } return new Object[0]; } } private class EvaluatorNodeCellEditor extends CellEditor { TextCellEditor textEditor; ComboBoxCellEditor2 enumEditor; CellEditor current; public EvaluatorNodeCellEditor(Composite parent) { super(parent); } Object getSelected() { StructuredSelection sel = (StructuredSelection)viewer.getSelection(); return sel.getFirstElement(); } @Override protected Control createControl(Composite parent) { textEditor = new TextCellEditor(parent); enumEditor = new ComboBoxCellEditor2(parent, new String[0]); current = textEditor; return null; } @Override protected Object doGetValue() { return current.getValue(); } @Override protected void doSetValue(Object value) { Object selected = getSelected(); if (selected instanceof StringEditableNode) { if (current != textEditor) current = textEditor; } else if (selected instanceof EnumEditableNode) { if (current != enumEditor) current = enumEditor; enumEditor.setItems(((EnumEditableNode)selected).getEnumearation()); } current.setValue(value); } @Override protected void doSetFocus() { current.setFocus(); } @Override public void activate(ColumnViewerEditorActivationEvent activationEvent) { // TODO Auto-generated method stub current.activate(activationEvent); } @Override public void activate() { current.activate(); } @Override public void deactivate() { current.deactivate(); } @Override public Control getControl() { return current.getControl(); } } private class EvaluatorNodeCellModifier implements ICellModifier { @Override public boolean canModify(Object element, String property) { return (element instanceof StringEditableNode || element instanceof EnumEditableNode); } @Override public Object getValue(Object element, String property) { if (element instanceof StringEditableNode) return ((StringEditableNode)element).getValue(); else if (element instanceof EnumEditableNode) { String values[] = ((EnumEditableNode)element).getEnumearation(); String value = ((EnumEditableNode)element).getValue(); for (int i = 0; i < values.length; i++) { if (value.equals(values[i])) return i; } return 0; } return ""; } @Override public void modify(Object element, String property, Object value) { StringEditableNode node = null; EnumEditableNode node2 = null; if (element instanceof TreeItem) { Object data = ((TreeItem)element).getData(); if (data instanceof StringEditableNode) node = (StringEditableNode)data; else if (data instanceof EnumEditableNode) { node2 = (EnumEditableNode)data; } } else if (element instanceof StringEditableNode){ node = (StringEditableNode)element; } else if (element instanceof EnumEditableNode) { node2 = (EnumEditableNode)element; } if (node != null) { node.setValue((String)value); update(node); } else if (node2 != null) { node2.setValue(node2.getEnumearation()[(Integer)value]); update(node2); } } } private class DoubleClickEditorActivationStrategy extends ColumnViewerEditorActivationStrategy { public DoubleClickEditorActivationStrategy(ColumnViewer viewer) { super(viewer); } @Override protected boolean isEditorActivationEvent( ColumnViewerEditorActivationEvent event) { boolean singleSelect = ((IStructuredSelection)viewer.getSelection()).size() == 1; boolean isLeftMouseSelect = event.eventType == ColumnViewerEditorActivationEvent.MOUSE_DOUBLE_CLICK_SELECTION && ((MouseEvent)event.sourceEvent).button == 1; return singleSelect && (isLeftMouseSelect || event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC || event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL); } } }