c24c41e2a72313388a0ab53cf4f98463a0132c94
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / featuretree / e4 / FeatureTreeEditor.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9
10 package eu.etaxonomy.taxeditor.featuretree.e4;
11
12 import java.util.Collection;
13
14 import javax.annotation.PostConstruct;
15 import javax.inject.Inject;
16 import javax.inject.Named;
17
18 import org.eclipse.core.runtime.IStatus;
19 import org.eclipse.e4.ui.di.Persist;
20 import org.eclipse.e4.ui.model.application.ui.MDirtyable;
21 import org.eclipse.e4.ui.services.IServiceConstants;
22 import org.eclipse.jface.viewers.ISelectionChangedListener;
23 import org.eclipse.jface.viewers.IStructuredSelection;
24 import org.eclipse.jface.viewers.SelectionChangedEvent;
25 import org.eclipse.jface.viewers.TreeViewer;
26 import org.eclipse.jface.viewers.Viewer;
27 import org.eclipse.jface.viewers.ViewerDropAdapter;
28 import org.eclipse.jface.wizard.WizardDialog;
29 import org.eclipse.swt.SWT;
30 import org.eclipse.swt.dnd.DND;
31 import org.eclipse.swt.dnd.DragSourceAdapter;
32 import org.eclipse.swt.dnd.DragSourceEvent;
33 import org.eclipse.swt.dnd.Transfer;
34 import org.eclipse.swt.dnd.TransferData;
35 import org.eclipse.swt.events.ModifyEvent;
36 import org.eclipse.swt.events.ModifyListener;
37 import org.eclipse.swt.events.SelectionAdapter;
38 import org.eclipse.swt.events.SelectionEvent;
39 import org.eclipse.swt.events.SelectionListener;
40 import org.eclipse.swt.layout.GridData;
41 import org.eclipse.swt.layout.GridLayout;
42 import org.eclipse.swt.widgets.Button;
43 import org.eclipse.swt.widgets.Composite;
44 import org.eclipse.swt.widgets.Label;
45 import org.eclipse.swt.widgets.Shell;
46 import org.eclipse.swt.widgets.Text;
47 import org.eclipse.swt.widgets.Tree;
48
49 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
50 import eu.etaxonomy.cdm.api.service.IFeatureNodeService;
51 import eu.etaxonomy.cdm.api.service.IFeatureTreeService;
52 import eu.etaxonomy.cdm.api.service.config.FeatureNodeDeletionConfigurator;
53 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
54 import eu.etaxonomy.cdm.model.description.Feature;
55 import eu.etaxonomy.cdm.model.description.FeatureNode;
56 import eu.etaxonomy.cdm.model.description.FeatureTree;
57 import eu.etaxonomy.taxeditor.featuretree.AvailableFeaturesWizard;
58 import eu.etaxonomy.taxeditor.featuretree.FeatureNodeTransfer;
59 import eu.etaxonomy.taxeditor.featuretree.FeatureTreeContentProvider;
60 import eu.etaxonomy.taxeditor.featuretree.FeatureTreeLabelProvider;
61 import eu.etaxonomy.taxeditor.model.ImageResources;
62 import eu.etaxonomy.taxeditor.model.MessagingUtils;
63 import eu.etaxonomy.taxeditor.store.CdmStore;
64 import eu.etaxonomy.taxeditor.ui.dialog.selection.FeatureTreeSelectionDialog;
65
66 /**
67 *
68 * @author pplitzner
69 * @date 06.06.2017
70 *
71 */
72 public class FeatureTreeEditor implements
73 ModifyListener, ISelectionChangedListener {
74
75 private TreeViewer viewer;
76 private Label label_title;
77 private Button button_add;
78 private Button button_remove;
79 private Label label_treeInfo;
80 private FeatureTree featureTree;
81 private Text text_title;
82 private Button btnOpenFeatureTree;
83 private Button btnNewFeatureTree;
84
85 private ConversationHolder conversation;
86 @Inject
87 private MDirtyable dirty;
88
89 private Shell shell;
90
91 @Inject
92 public FeatureTreeEditor(@Named(IServiceConstants.ACTIVE_SHELL)Shell shell) {
93 this.shell = shell;
94 if(conversation==null){
95 conversation = CdmStore.createConversation();
96 }
97 }
98
99 /** {@inheritDoc} */
100 @PostConstruct
101 public void createControl(Composite parent, @Named(IServiceConstants.ACTIVE_SHELL)Shell shell) {
102 parent.setLayout(new GridLayout());
103 Composite composite = new Composite(parent, SWT.NULL);
104 composite.setLayout(new GridLayout());
105 composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
106
107 Composite composite_treeTitle = new Composite(composite, SWT.NULL);
108 composite_treeTitle.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true,
109 false));
110 composite_treeTitle.setLayout(new GridLayout(4, false));
111
112 label_title = new Label(composite_treeTitle, SWT.NULL);
113 label_title.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
114 label_title.setText("Title");
115
116 text_title = new Text(composite_treeTitle, SWT.BORDER);
117 text_title.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
118
119 btnOpenFeatureTree = new Button(composite_treeTitle, SWT.NONE);
120 btnOpenFeatureTree.setImage(ImageResources.getImage(ImageResources.BROWSE_ICON));
121 btnOpenFeatureTree.setText("Open Tree");
122
123 btnNewFeatureTree = new Button(composite_treeTitle, SWT.NONE);
124 btnNewFeatureTree.setText("New Feature Tree");
125
126 Composite composite_treeContent = new Composite(composite, SWT.NULL);
127 composite_treeContent.setLayoutData(new GridData(SWT.FILL, SWT.FILL,
128 true, true));
129 composite_treeContent.setLayout(new GridLayout(2, false));
130
131 viewer = new TreeViewer(composite_treeContent);
132 Tree tree = viewer.getTree();
133 tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
134 viewer.getControl().setLayoutData(
135 new GridData(SWT.FILL, SWT.FILL, true, true));
136
137 Composite composite_buttons = new Composite(composite_treeContent,
138 SWT.NULL);
139 composite_buttons.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false,
140 false));
141 composite_buttons.setLayout(new GridLayout());
142
143 button_add = new Button(composite_buttons, SWT.PUSH);
144 button_add.setText("Add");
145 button_add.setToolTipText("Add a feature to this feature treee.");
146 button_remove = new Button(composite_buttons, SWT.PUSH);
147 button_remove.setText("Remove");
148 button_remove
149 .setToolTipText("Remove a feature from this feature tree.");
150
151 label_treeInfo = new Label(composite, SWT.NULL);
152 label_treeInfo
153 .setText("Order and nesting of feature nodes may be changed through drag and drop.");
154
155 init(shell);
156 }
157
158 private void setDirty(boolean isDirty){
159 this.dirty.setDirty(isDirty);
160 }
161
162 private void init(Shell shell) {
163 viewer.setContentProvider(new FeatureTreeContentProvider());
164 viewer.setLabelProvider(new FeatureTreeLabelProvider());
165
166 int ops = DND.DROP_COPY | DND.DROP_MOVE;
167 Transfer[] transfers = new Transfer[] { FeatureNodeTransfer
168 .getInstance() };
169 viewer.addDragSupport(ops, transfers, new FeatureNodeDragListener(
170 viewer));
171 viewer.addDropSupport(ops, transfers,
172 new FeatureNodeDropAdapter(viewer));
173
174 viewer.addSelectionChangedListener(this);
175
176 button_add.addSelectionListener(new AddButtonListener());
177 button_remove.addSelectionListener(new RemoveSelectionListener());
178
179 btnOpenFeatureTree.addSelectionListener(new SelectionListener() {
180
181 @Override
182 public void widgetSelected(SelectionEvent e) {
183 FeatureTree tree = FeatureTreeSelectionDialog.select(shell, conversation, null);
184 setSelectedTree(tree);
185 }
186
187 @Override
188 public void widgetDefaultSelected(SelectionEvent e) {
189 }
190 });
191 }
192
193 public void setSelectedTree(FeatureTree featureTree) {
194 this.featureTree = HibernateProxyHelper.deproxy(featureTree, FeatureTree.class);
195 this.featureTree.setRoot(HibernateProxyHelper.deproxy(featureTree.getRoot(), FeatureNode.class));
196 viewer.setInput(featureTree);
197
198 text_title.removeModifyListener(this);
199 text_title.setText(featureTree.getTitleCache());
200 text_title.addModifyListener(this);
201 }
202
203 /** {@inheritDoc} */
204 @Override
205 public void modifyText(ModifyEvent e) {
206 featureTree.setTitleCache(text_title.getText(), true);
207 setDirty(true);
208 }
209
210 /** {@inheritDoc} */
211 @Override
212 public void selectionChanged(SelectionChangedEvent event) {
213 IStructuredSelection selection = (IStructuredSelection) event
214 .getSelection();
215
216 button_add.setEnabled(selection.size() <= 1);
217 button_remove.setEnabled(selection.size() > 0);
218 }
219
220 @Persist
221 public void save(){
222 CdmStore.getService(IFeatureTreeService.class).saveOrUpdate(featureTree);
223 setDirty(false);
224 }
225
226 private class AddButtonListener extends SelectionAdapter {
227 @Override
228 public void widgetSelected(SelectionEvent e) {
229 AvailableFeaturesWizard wizard = new AvailableFeaturesWizard(
230 featureTree);
231 WizardDialog dialog = new WizardDialog(shell, wizard);
232
233 if (dialog.open() == IStatus.OK) {
234 IStructuredSelection selection = (IStructuredSelection) viewer
235 .getSelection();
236 FeatureNode parent = (FeatureNode) (selection.getFirstElement() != null ? selection
237 .getFirstElement() : ((FeatureTree) viewer.getInput())
238 .getRoot());
239 Collection<Feature> additionalFeatures = wizard
240 .getAdditionalFeatures();
241 for (Feature feature : additionalFeatures) {
242 FeatureNode child = FeatureNode.NewInstance(feature);
243 CdmStore.getService(IFeatureNodeService.class).merge(child, true);
244
245 parent.addChild(child);
246 }
247 setDirty(true);
248 viewer.refresh();
249 }
250 }
251
252 }
253
254 private class RemoveSelectionListener extends SelectionAdapter {
255 @Override
256 public void widgetSelected(SelectionEvent e) {
257 IStructuredSelection selection = (IStructuredSelection) viewer
258 .getSelection();
259
260 for (Object selectedObject : selection.toArray()) {
261 FeatureNode featureNode = (FeatureNode) selectedObject;
262 FeatureNode parent = featureNode.getParent();
263 parent.removeChild(featureNode);
264
265 CdmStore.getService(IFeatureNodeService.class).deleteFeatureNode(featureNode.getUuid(), new FeatureNodeDeletionConfigurator());
266
267 }
268 setDirty(true);
269 viewer.refresh();
270 }
271 }
272
273 private class FeatureNodeDragListener extends DragSourceAdapter {
274
275 private final TreeViewer viewer;
276
277 public FeatureNodeDragListener(TreeViewer viewer) {
278 this.viewer = viewer;
279 }
280
281 /**
282 * Method declared on DragSourceListener
283 */
284 @Override
285 public void dragFinished(DragSourceEvent event) {
286 if (!event.doit) {
287 return;
288 }
289 // if the featureNode was moved, remove it from the source viewer
290 if (event.detail == DND.DROP_MOVE) {
291 IStructuredSelection selection = (IStructuredSelection) viewer
292 .getSelection();
293 viewer.refresh();
294 }
295 }
296
297 /**
298 * Method declared on DragSourceListener
299 */
300 @Override
301 public void dragSetData(DragSourceEvent event) {
302 IStructuredSelection selection = (IStructuredSelection) viewer
303 .getSelection();
304 FeatureNode[] featureNodes = (FeatureNode[]) selection.toList()
305 .toArray(new FeatureNode[selection.size()]);
306 if (FeatureNodeTransfer.getInstance().isSupportedType(
307 event.dataType)) {
308 event.data = featureNodes;
309 }
310 }
311
312 /**
313 * Method declared on DragSourceListener
314 */
315 @Override
316 public void dragStart(DragSourceEvent event) {
317 event.doit = !viewer.getSelection().isEmpty();
318 }
319
320 }
321
322 private class FeatureNodeDropAdapter extends ViewerDropAdapter {
323
324 protected FeatureNodeDropAdapter(Viewer viewer) {
325 super(viewer);
326 }
327
328 @Override
329 public boolean performDrop(Object data) {
330 FeatureNode target = (FeatureNode) getCurrentTarget();
331 int position = 0;
332
333 if (target != null) {
334 int location = getCurrentLocation();
335 FeatureNode parent = target.getParent();
336 if (location == LOCATION_BEFORE) {
337 position = Math.max(0, parent.getIndex(target) - 1);
338 target = parent;
339 }
340
341 if (location == LOCATION_AFTER) {
342 position = parent.getIndex(target);
343 target = parent;
344 }
345 }
346
347 // set target to root node if there is no target specified
348 if (target == null) {
349 FeatureTree featureTree = (FeatureTree) getViewer().getInput();
350 target = featureTree.getRoot();
351 }
352
353 Object[] droppedObjects = (Object[]) data;
354 TreeViewer viewer = (TreeViewer) getViewer();
355
356 // cannot drop a feature node onto itself
357 for (Object droppedObject : droppedObjects) {
358 if (droppedObject == null) {
359 MessagingUtils.warningDialog(
360 "Operation not supported yet",
361 this,
362 "We are currently unable to change the order of freshly created "
363 + "feature trees nodes. Please close and reopen the dialog to change the order of features.");
364 return false;
365 }
366 if (droppedObject.equals(target)) {
367 return false;
368 }
369 }
370 for (Object droppedObject : droppedObjects) {
371 FeatureNode droppedNode = (FeatureNode) droppedObject;
372 target.addChild(droppedNode, position);
373 viewer.add(target, droppedNode);
374 viewer.reveal(droppedNode);
375 }
376 return true;
377 }
378
379 @Override
380 public boolean validateDrop(Object target, int operation,
381 TransferData transferData) {
382 return FeatureNodeTransfer.getInstance().isSupportedType(
383 transferData);
384 }
385
386 }
387 }