Save edited character in FeatureTreeEditor
[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.Arrays;
13 import java.util.Collections;
14 import java.util.HashMap;
15 import java.util.List;
16 import java.util.Map;
17
18 import javax.annotation.PostConstruct;
19 import javax.annotation.PreDestroy;
20 import javax.inject.Inject;
21
22 import org.eclipse.core.runtime.IProgressMonitor;
23 import org.eclipse.e4.ui.di.Focus;
24 import org.eclipse.e4.ui.di.Persist;
25 import org.eclipse.e4.ui.di.UISynchronize;
26 import org.eclipse.e4.ui.model.application.ui.MDirtyable;
27 import org.eclipse.e4.ui.model.application.ui.basic.MPart;
28 import org.eclipse.e4.ui.services.EMenuService;
29 import org.eclipse.e4.ui.workbench.modeling.EPartService;
30 import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
31 import org.eclipse.jface.util.LocalSelectionTransfer;
32 import org.eclipse.jface.viewers.ISelection;
33 import org.eclipse.jface.viewers.ISelectionChangedListener;
34 import org.eclipse.jface.viewers.IStructuredSelection;
35 import org.eclipse.jface.viewers.SelectionChangedEvent;
36 import org.eclipse.jface.viewers.StructuredSelection;
37 import org.eclipse.jface.viewers.TreeViewer;
38 import org.eclipse.swt.SWT;
39 import org.eclipse.swt.dnd.DND;
40 import org.eclipse.swt.dnd.Transfer;
41 import org.eclipse.swt.events.KeyAdapter;
42 import org.eclipse.swt.events.KeyEvent;
43 import org.eclipse.swt.layout.FillLayout;
44 import org.eclipse.swt.widgets.Composite;
45 import org.eclipse.ui.IMemento;
46
47 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
48 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
49 import eu.etaxonomy.cdm.api.service.IFeatureTreeService;
50 import eu.etaxonomy.cdm.api.service.ITermService;
51 import eu.etaxonomy.cdm.model.description.Character;
52 import eu.etaxonomy.cdm.model.term.FeatureNode;
53 import eu.etaxonomy.cdm.model.term.FeatureTree;
54 import eu.etaxonomy.cdm.model.term.TermType;
55 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
56 import eu.etaxonomy.taxeditor.editor.definedterm.TermTransfer;
57 import eu.etaxonomy.taxeditor.featuretree.FeatureNodeTransfer;
58 import eu.etaxonomy.taxeditor.featuretree.FeatureTreeContentProvider;
59 import eu.etaxonomy.taxeditor.featuretree.FeatureTreeLabelProvider;
60 import eu.etaxonomy.taxeditor.featuretree.e4.operation.AddFeatureOperation;
61 import eu.etaxonomy.taxeditor.model.AbstractUtility;
62 import eu.etaxonomy.taxeditor.model.IContextListener;
63 import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
64 import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
65 import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
66 import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
67 import eu.etaxonomy.taxeditor.store.AppModelId;
68 import eu.etaxonomy.taxeditor.store.CdmStore;
69 import eu.etaxonomy.taxeditor.store.StoreUtil;
70 import eu.etaxonomy.taxeditor.workbench.part.IE4ViewerPart;
71
72 /**
73 *
74 * @author pplitzner
75 * @date 06.06.2017
76 *
77 */
78 public class FeatureTreeEditor implements IFeatureTreeEditor, ISelectionChangedListener,
79 IE4ViewerPart, IPartContentHasDetails, IPartContentHasSupplementalData,
80 IContextListener, IConversationEnabled, IDirtyMarkable {
81
82 private ConversationHolder conversation;
83
84 private ICdmEntitySession cdmEntitySession;
85
86 @Inject
87 private ESelectionService selService;
88
89 @Inject
90 private MDirtyable dirty;
91
92 @Inject
93 private UISynchronize sync;
94
95 @Inject
96 private MPart thisPart;
97
98 private TreeViewer viewer;
99
100 @Inject
101 public FeatureTreeEditor() {
102 CdmStore.getContextManager().addContextListener(this);
103 }
104
105 @PostConstruct
106 public void createControl(Composite parent, EMenuService menuService){
107 if (CdmStore.isActive()){
108 initSession();
109 }
110 else{
111 return;
112 }
113 parent.setLayout(new FillLayout());
114 viewer = new TreeViewer(parent);
115 viewer.setContentProvider(new FeatureTreeContentProvider());
116 viewer.setLabelProvider(new FeatureTreeLabelProvider());
117
118 int ops = DND.DROP_COPY | DND.DROP_MOVE;
119 Transfer[] transfers = new Transfer[] {
120 FeatureNodeTransfer.getInstance(),
121 TermTransfer.getInstance(),
122 LocalSelectionTransfer.getTransfer()};
123 viewer.addDragSupport(ops, transfers, new FeatureNodeDragListener(viewer));
124 viewer.addDropSupport(ops, transfers, new FeatureTreeDropAdapter(this, viewer, sync));
125 viewer.addSelectionChangedListener(this);
126 viewer.getTree().addKeyListener(new KeyAdapter() {
127 @Override
128 public void keyPressed(KeyEvent e) {
129 if(e.stateMask == SWT.MOD1 && e.keyCode == 'c'){
130 copy(viewer.getStructuredSelection());
131 }
132 else if(e.stateMask == SWT.MOD1 && e.keyCode == 'v'){
133 paste(viewer.getStructuredSelection());
134 }
135 }
136 });
137
138 List<FeatureTree> trees = CdmStore.getService(IFeatureTreeService.class).list(FeatureTree.class, null, null, null, null);
139 Collections.sort(trees, (tree1, tree2) -> tree1.getTitleCache().compareTo(tree2.getTitleCache()));
140 viewer.setInput(trees);
141
142 //create context menu
143 menuService.registerContextMenu(viewer.getControl(), AppModelId.POPUPMENU_EU_ETAXONOMY_TAXEDITOR_STORE_POPUPMENU_FEATURETREEEDITOR);
144 }
145
146 public void paste(IStructuredSelection selection) {
147 if (StoreUtil.promptCheckIsDirty(this)) {
148 return;
149 }
150
151 ISelection clipBoardSelection = LocalSelectionTransfer.getTransfer().getSelection();
152 Object firstElement = selection.getFirstElement();
153 FeatureNode parentNode = null;
154 if(firstElement instanceof FeatureNode){
155 parentNode = (FeatureNode) firstElement;
156 }
157 else if(firstElement instanceof FeatureTree){
158 parentNode = ((FeatureTree)firstElement).getRoot();
159 }
160 if(parentNode!=null){
161 FeatureNode copiedNode = (FeatureNode) ((IStructuredSelection)clipBoardSelection).getFirstElement();
162
163 AddFeatureOperation operation = new AddFeatureOperation(copiedNode.getTerm().getUuid(), parentNode, this, this);
164 AbstractUtility.executeOperation(operation, sync);
165 }
166
167 }
168
169 public void copy(IStructuredSelection selection) {
170 LocalSelectionTransfer.getTransfer().setSelection(selection);
171 }
172
173 private void initSession(){
174 if(conversation == null){
175 conversation = CdmStore.createConversation();
176 }
177 if(cdmEntitySession==null){
178 cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
179 }
180 }
181
182 private void clearSession() {
183 if(conversation!=null){
184 conversation.close();
185 conversation = null;
186 }
187 if(cdmEntitySession != null) {
188 cdmEntitySession.dispose();
189 cdmEntitySession = null;
190 }
191 dirty.setDirty(false);
192 }
193
194 public void setDirty(boolean isDirty){
195 this.dirty.setDirty(isDirty);
196 }
197
198 @Override
199 public boolean isDirty(){
200 return dirty.isDirty();
201 }
202
203 @Override
204 public void selectionChanged(SelectionChangedEvent event) {
205 //propagate selection
206 selService.setSelection(event.getSelection());
207 }
208
209 @Focus
210 public void focus(){
211 if(viewer!=null){
212 viewer.getControl().setFocus();
213 }
214 if(conversation!=null && !conversation.isBound()){
215 conversation.bind();
216 }
217 if(cdmEntitySession != null) {
218 cdmEntitySession.bind();
219 }
220 }
221
222 @Override
223 public void refresh(){
224 viewer.refresh();
225 }
226
227 public TreeViewer getViewer(){
228 return viewer;
229 }
230
231 @Override
232 public IStructuredSelection getSelection() {
233 return (IStructuredSelection) viewer.getSelection();
234 }
235
236 @Override
237 public ConversationHolder getConversationHolder() {
238 return conversation;
239 }
240
241 @Override
242 @Persist
243 public void save(IProgressMonitor monitor){
244 if (!conversation.isBound()) {
245 conversation.bind();
246 }
247
248 // commit the conversation and start a new transaction immediately
249 conversation.commit(true);
250
251 CdmStore.getService(IFeatureTreeService.class).saveOrUpdate(getRootEntities());
252
253 List<FeatureTree> rootEntities = getRootEntities();
254 for (FeatureTree featureTree : rootEntities) {
255 if(featureTree.getTermType().equals(TermType.Character)){
256 FeatureTree<Character> characterTree = featureTree;
257 //save characters because they can be modified in this editor
258 characterTree.getDistinctFeatures().forEach(character->CdmStore.getService(ITermService.class).merge(character,true));
259 }
260 }
261
262 initializeTrees();
263
264 this.setDirty(false);
265 }
266
267 private void initializeTrees() {
268 Object[] expandedElements = viewer.getExpandedElements();
269 viewer.getTree().removeAll();
270 List<FeatureTree> trees = CdmStore.getService(IFeatureTreeService.class).list(FeatureTree.class, null, null, null, null);
271 viewer.setInput(trees);
272 viewer.setExpandedElements(expandedElements);
273 }
274
275 @PreDestroy
276 public void dispose(){
277 selService.setSelection(null);
278 clearSession();
279 }
280
281 @Override
282 public ICdmEntitySession getCdmEntitySession() {
283 return cdmEntitySession;
284 }
285
286 @Override
287 public Map<Object, List<String>> getPropertyPathsMap() {
288 List<String> propertyPaths = Arrays.asList(new String[] {
289 "children", //$NON-NLS-1$
290 "feature", //$NON-NLS-1$
291 "featureTree", //$NON-NLS-1$
292 });
293 Map<Object, List<String>> propertyPathMap =
294 new HashMap<Object, List<String>>();
295 propertyPathMap.put(FeatureNode.class,propertyPaths);
296 return propertyPathMap;
297 }
298
299 @Override
300 public List<FeatureTree> getRootEntities() {
301 return (List<FeatureTree>) viewer.getInput();
302 }
303
304 @Override
305 public void contextAboutToStop(IMemento memento, IProgressMonitor monitor) {
306 }
307
308 @Override
309 public void contextStop(IMemento memento, IProgressMonitor monitor) {
310 //close view when workbench closes
311 try{
312 thisPart.getContext().get(EPartService.class).hidePart(thisPart);
313 }
314 catch(Exception e){
315 //nothing
316 }
317 }
318
319 @Override
320 public void contextStart(IMemento memento, IProgressMonitor monitor) {
321 }
322
323 @Override
324 public void contextRefresh(IProgressMonitor monitor) {
325 }
326
327 @Override
328 public void workbenchShutdown(IMemento memento, IProgressMonitor monitor) {
329 }
330
331 @Override
332 public void update(CdmDataChangeMap arg0) {
333 }
334
335 @Override
336 public void changed(Object element) {
337 dirty.setDirty(true);
338 viewer.refresh();
339 }
340
341 @Override
342 public void forceDirty() {
343 dirty.setDirty(true);
344 }
345
346 @Override
347 public boolean postOperation(Object objectAffectedByOperation) {
348 initializeTrees();
349 viewer.refresh();
350 if(objectAffectedByOperation instanceof FeatureNode){
351 FeatureNode node = (FeatureNode)objectAffectedByOperation;
352 viewer.expandToLevel(node.getFeatureTree(), 1);
353 }
354 if(objectAffectedByOperation!=null){
355 StructuredSelection selection = new StructuredSelection(objectAffectedByOperation);
356 viewer.setSelection(selection);
357 }
358 return true;
359 }
360
361 @Override
362 public boolean onComplete() {
363 return false;
364 }
365
366 }