Project

General

Profile

Revision 5ce82a07

ID5ce82a07a6e04e8bb3e4f68604d0acfbade26f18
Parent 2ffb3ef3
Child 880044bc

Added by Patrick Plitzner about 3 years ago

ref #6694 Implement Feature Tree Editor

View differences:

eu.etaxonomy.taxeditor.store/fragment.e4xmi
2 2
<fragment:ModelFragments xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:basic="http://www.eclipse.org/ui/2010/UIModel/application/descriptor/basic" xmlns:commands="http://www.eclipse.org/ui/2010/UIModel/application/commands" xmlns:fragment="http://www.eclipse.org/ui/2010/UIModel/fragment" xmlns:menu="http://www.eclipse.org/ui/2010/UIModel/application/ui/menu" xmlns:ui="http://www.eclipse.org/ui/2010/UIModel/application/ui" xmi:id="_OhwnQCTfEeeiN5lBIuqN3g">
3 3
  <imports xsi:type="commands:Command" xmi:id="_bnVKsCZxEeeQLpuomSmVoQ" elementId="eu.etaxonomy.taxeditor.command.openPart"/>
4 4
  <fragments xsi:type="fragment:StringModelFragment" xmi:id="_xVa1wCXXEeex9MwMOgUeWw" featurename="descriptors" parentElementId="xpath:/">
5
    <elements xsi:type="basic:PartDescriptor" xmi:id="_2xmxoCXXEeex9MwMOgUeWw" elementId="eu.etaxonomy.taxeditor.store.partdescriptor.sessionsView" label="%view.name.SESSIONS" closeable="true" contributionURI="bundleclass://eu.etaxonomy.taxeditor.store/eu.etaxonomy.taxeditor.view.sessions.SessionsViewPart"/>
5
    <elements xsi:type="basic:PartDescriptor" xmi:id="_2xmxoCXXEeex9MwMOgUeWw" elementId="eu.etaxonomy.taxeditor.view.sessions.SessionsViewPart" label="%view.name.SESSIONS" closeable="true" contributionURI="bundleclass://eu.etaxonomy.taxeditor.store/eu.etaxonomy.taxeditor.view.sessions.SessionsViewPart"/>
6
    <elements xsi:type="basic:PartDescriptor" xmi:id="_J-3UEEqgEeeN-dEYnw7m3g" elementId="eu.etaxonomy.taxeditor.featuretree.e4.FeatureTreeEditor" label="Feature Tree Editor" closeable="true" dirtyable="true" contributionURI="bundleclass://eu.etaxonomy.taxeditor.store/eu.etaxonomy.taxeditor.featuretree.e4.FeatureTreeEditor"/>
6 7
  </fragments>
7 8
  <fragments xsi:type="fragment:StringModelFragment" xmi:id="_3rW8wCXaEeex9MwMOgUeWw" featurename="children" parentElementId="eu.etaxonomy.taxeditor.menu.showView" positionInList="after:bulkeditor.menus.openmenu">
8 9
    <elements xsi:type="menu:HandledMenuItem" xmi:id="_K6sowCaGEeeTEd_pKXBflg" elementId="eu.etaxonomy.taxeditor.store.showViewMenu.details" label="%command.label.0" command="_bnVKsCZxEeeQLpuomSmVoQ">
......
22 23
    </elements>
23 24
    <elements xsi:type="menu:HandledMenuItem" xmi:id="_jFskQCZyEeeQLpuomSmVoQ" elementId="eu.etaxonomy.taxeditor.store.showViewMenu.sessions" label="%view.name.SESSIONS" command="_bnVKsCZxEeeQLpuomSmVoQ">
24 25
      <visibleWhen xsi:type="ui:CoreExpression" xmi:id="_W-C-gCaJEeeTEd_pKXBflg" coreExpressionId="isCdmStoreConnected"/>
25
      <parameters xmi:id="_BylIUCZzEeeQLpuomSmVoQ" elementId="eu.etaxonomy.taxeditor.store.showView.parameter.sessionView" name="eu.etaxonomy.taxeditor.workbench.commandparameter.partName" value="eu.etaxonomy.taxeditor.store.partdescriptor.sessionsView"/>
26
      <parameters xmi:id="_BylIUCZzEeeQLpuomSmVoQ" elementId="eu.etaxonomy.taxeditor.store.showView.parameter.sessionView" name="eu.etaxonomy.taxeditor.workbench.commandparameter.partName" value="eu.etaxonomy.taxeditor.view.sessions.SessionsViewPart"/>
27
    </elements>
28
    <elements xsi:type="menu:HandledMenuItem" xmi:id="_VINAAEqgEeeN-dEYnw7m3g" elementId="eu.etaxonomy.taxeditor.store.showViewMenu.sessions" label="Feature Tree Editor" command="_bnVKsCZxEeeQLpuomSmVoQ">
29
      <visibleWhen xsi:type="ui:CoreExpression" xmi:id="_VINAAUqgEeeN-dEYnw7m3g" coreExpressionId="isCdmStoreConnected"/>
30
      <parameters xmi:id="_VINAAkqgEeeN-dEYnw7m3g" elementId="eu.etaxonomy.taxeditor.store.showView.parameter.sessionView" name="eu.etaxonomy.taxeditor.workbench.commandparameter.partName" value="eu.etaxonomy.taxeditor.featuretree.e4.FeatureTreeEditor"/>
26 31
    </elements>
27 32
  </fragments>
28 33
</fragment:ModelFragments>
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
	}
224

  
225
	private class AddButtonListener extends SelectionAdapter {
226
		@Override
227
		public void widgetSelected(SelectionEvent e) {
228
			AvailableFeaturesWizard wizard = new AvailableFeaturesWizard(
229
					featureTree);
230
			WizardDialog dialog = new WizardDialog(shell, wizard);
231

  
232
			if (dialog.open() == IStatus.OK) {
233
				IStructuredSelection selection = (IStructuredSelection) viewer
234
						.getSelection();
235
				FeatureNode parent = (FeatureNode) (selection.getFirstElement() != null ? selection
236
						.getFirstElement() : ((FeatureTree) viewer.getInput())
237
						.getRoot());
238
				Collection<Feature> additionalFeatures = wizard
239
						.getAdditionalFeatures();
240
				for (Feature feature : additionalFeatures) {
241
					FeatureNode child = FeatureNode.NewInstance(feature);
242
					CdmStore.getService(IFeatureNodeService.class).merge(child, true);
243

  
244
					parent.addChild(child);
245
				}
246
				viewer.refresh();
247
			}
248
		}
249

  
250
	}
251

  
252
	private class RemoveSelectionListener extends SelectionAdapter {
253
		@Override
254
		public void widgetSelected(SelectionEvent e) {
255
			IStructuredSelection selection = (IStructuredSelection) viewer
256
					.getSelection();
257

  
258
			for (Object selectedObject : selection.toArray()) {
259
				FeatureNode featureNode = (FeatureNode) selectedObject;
260
				FeatureNode parent = featureNode.getParent();
261
				parent.removeChild(featureNode);
262

  
263
				CdmStore.getService(IFeatureNodeService.class).deleteFeatureNode(featureNode.getUuid(), new FeatureNodeDeletionConfigurator());
264

  
265
			}
266
			viewer.refresh();
267
		}
268
	}
269

  
270
	private class FeatureNodeDragListener extends DragSourceAdapter {
271

  
272
		private final TreeViewer viewer;
273

  
274
		public FeatureNodeDragListener(TreeViewer viewer) {
275
			this.viewer = viewer;
276
		}
277

  
278
		/**
279
		 * Method declared on DragSourceListener
280
		 */
281
		@Override
282
		public void dragFinished(DragSourceEvent event) {
283
			if (!event.doit) {
284
                return;
285
            }
286
			// if the featureNode was moved, remove it from the source viewer
287
			if (event.detail == DND.DROP_MOVE) {
288
				IStructuredSelection selection = (IStructuredSelection) viewer
289
						.getSelection();
290
				viewer.refresh();
291
			}
292
		}
293

  
294
		/**
295
		 * Method declared on DragSourceListener
296
		 */
297
		@Override
298
		public void dragSetData(DragSourceEvent event) {
299
			IStructuredSelection selection = (IStructuredSelection) viewer
300
					.getSelection();
301
			FeatureNode[] featureNodes = (FeatureNode[]) selection.toList()
302
					.toArray(new FeatureNode[selection.size()]);
303
			if (FeatureNodeTransfer.getInstance().isSupportedType(
304
					event.dataType)) {
305
				event.data = featureNodes;
306
			}
307
		}
308

  
309
		/**
310
		 * Method declared on DragSourceListener
311
		 */
312
		@Override
313
		public void dragStart(DragSourceEvent event) {
314
			event.doit = !viewer.getSelection().isEmpty();
315
		}
316

  
317
	}
318

  
319
	private class FeatureNodeDropAdapter extends ViewerDropAdapter {
320

  
321
		protected FeatureNodeDropAdapter(Viewer viewer) {
322
			super(viewer);
323
		}
324

  
325
		@Override
326
		public boolean performDrop(Object data) {
327
			FeatureNode target = (FeatureNode) getCurrentTarget();
328
			int position = 0;
329

  
330
			if (target != null) {
331
				int location = getCurrentLocation();
332
				FeatureNode parent = target.getParent();
333
				if (location == LOCATION_BEFORE) {
334
					position = Math.max(0, parent.getIndex(target) - 1);
335
					target = parent;
336
				}
337

  
338
				if (location == LOCATION_AFTER) {
339
					position = parent.getIndex(target);
340
					target = parent;
341
				}
342
			}
343

  
344
			// set target to root node if there is no target specified
345
			if (target == null) {
346
				FeatureTree featureTree = (FeatureTree) getViewer().getInput();
347
				target = featureTree.getRoot();
348
			}
349

  
350
			Object[] droppedObjects = (Object[]) data;
351
			TreeViewer viewer = (TreeViewer) getViewer();
352

  
353
			// cannot drop a feature node onto itself
354
			for (Object droppedObject : droppedObjects) {
355
				if (droppedObject == null) {
356
					MessagingUtils.warningDialog(
357
									"Operation not supported yet",
358
									this,
359
									"We are currently unable to change the order of freshly created "
360
											+ "feature trees nodes. Please close and reopen the dialog to change the order of features.");
361
					return false;
362
				}
363
				if (droppedObject.equals(target)) {
364
					return false;
365
				}
366
			}
367
			for (Object droppedObject : droppedObjects) {
368
				FeatureNode droppedNode = (FeatureNode) droppedObject;
369
				target.addChild(droppedNode, position);
370
				viewer.add(target, droppedNode);
371
				viewer.reveal(droppedNode);
372
			}
373
			return true;
374
		}
375

  
376
		@Override
377
		public boolean validateDrop(Object target, int operation,
378
				TransferData transferData) {
379
			return FeatureNodeTransfer.getInstance().isSupportedType(
380
					transferData);
381
		}
382

  
383
	}
384
}

Also available in: Unified diff

Add picture from clipboard (Maximum size: 40 MB)