fix setPublishFlagForSubtree in editor
[taxeditor.git] / eu.etaxonomy.taxeditor.navigation / src / main / java / eu / etaxonomy / taxeditor / navigation / navigator / e4 / TaxonNavigatorE4.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.navigation.navigator.e4;
11
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.Comparator;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Observable;
20 import java.util.Observer;
21 import java.util.Set;
22 import java.util.UUID;
23
24 import javax.annotation.PostConstruct;
25 import javax.annotation.PreDestroy;
26 import javax.inject.Inject;
27
28 import org.eclipse.core.runtime.IAdaptable;
29 import org.eclipse.core.runtime.IProgressMonitor;
30 import org.eclipse.e4.ui.di.Focus;
31 import org.eclipse.e4.ui.services.EMenuService;
32 import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
33 import org.eclipse.jface.viewers.ISelection;
34 import org.eclipse.jface.viewers.ISelectionChangedListener;
35 import org.eclipse.jface.viewers.IStructuredSelection;
36 import org.eclipse.jface.viewers.TreePath;
37 import org.eclipse.jface.viewers.TreeViewer;
38 import org.eclipse.swt.SWT;
39 import org.eclipse.swt.layout.FillLayout;
40 import org.eclipse.swt.widgets.Composite;
41 import org.eclipse.ui.IMemento;
42
43 import eu.etaxonomy.cdm.api.application.CdmApplicationState;
44 import eu.etaxonomy.cdm.api.application.CdmChangeEvent;
45 import eu.etaxonomy.cdm.api.application.ICdmChangeListener;
46 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
47 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
48 import eu.etaxonomy.cdm.api.service.IClassificationService;
49 import eu.etaxonomy.cdm.model.common.CdmBase;
50 import eu.etaxonomy.cdm.model.common.ICdmBase;
51 import eu.etaxonomy.cdm.model.common.ITreeNode;
52 import eu.etaxonomy.cdm.model.taxon.Classification;
53 import eu.etaxonomy.cdm.model.taxon.TaxonNaturalComparator;
54 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
55 import eu.etaxonomy.cdm.model.taxon.TaxonNodeByNameComparator;
56 import eu.etaxonomy.cdm.model.taxon.TaxonNodeByRankAndNameComparator;
57 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
58 import eu.etaxonomy.taxeditor.model.DataChangeBridge;
59 import eu.etaxonomy.taxeditor.model.IContextListener;
60 import eu.etaxonomy.taxeditor.model.IDataChangeBehavior;
61 import eu.etaxonomy.taxeditor.navigation.NavigationUtil;
62 import eu.etaxonomy.taxeditor.navigation.l10n.Messages;
63 import eu.etaxonomy.taxeditor.navigation.navigator.EmptyRoot;
64 import eu.etaxonomy.taxeditor.navigation.navigator.Root;
65 import eu.etaxonomy.taxeditor.navigation.navigator.TaxonNodeNavigatorComparator;
66 import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
67 import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
68 import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
69 import eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled;
70 import eu.etaxonomy.taxeditor.store.CdmStore;
71 import eu.etaxonomy.taxeditor.store.LoginManager;
72 import eu.etaxonomy.taxeditor.ui.element.LayoutConstants;
73
74 /**
75 *
76 * @author pplitzner
77 * @since Sep 7, 2017
78 *
79 */
80 public class TaxonNavigatorE4 implements
81 IPostOperationEnabled, IConversationEnabled, Observer,
82 ICdmEntitySessionEnabled, ICdmChangeListener, IContextListener {
83
84 private static final String RESTORING_TAXON_NAVIGATOR = Messages.TaxonNavigator_RESTORE;
85
86 private static final String TREE_PATH = "treepath"; //$NON-NLS-1$
87
88 private static final String TREE_PATHS = "treepaths"; //$NON-NLS-1$
89
90 private ConversationHolder conversation;
91
92 private ICdmEntitySession cdmEntitySession;
93
94 private IDataChangeBehavior dataChangeBehavior;
95
96 private Root root;
97
98 private TreeViewer viewer;
99
100 @Inject
101 private ESelectionService selService;
102
103 private ISelectionChangedListener selectionChangedListener;
104
105 @Inject
106 public TaxonNavigatorE4() {
107 CdmStore.getContextManager().addContextListener(this);
108 }
109
110 @PostConstruct
111 private void create(Composite parent, EMenuService menuService){
112 FillLayout layout = new FillLayout();
113 layout.marginHeight = 0;
114 layout.marginWidth = 0;
115 layout.type = SWT.VERTICAL;
116
117 parent.setLayout(layout);
118 viewer = new TreeViewer(parent);
119 viewer.getControl().setLayoutData(LayoutConstants.FILL());
120
121 viewer.setContentProvider(new TaxonNavigatorContentProviderE4());
122 viewer.setLabelProvider(new TaxonNavigatorLabelProviderE4());
123 viewer.addDoubleClickListener(event->{
124 ISelection selection = event.getSelection();
125 if(selection instanceof IStructuredSelection){
126 Object firstElement = ((IStructuredSelection) selection).getFirstElement();
127 if(firstElement instanceof ICdmBase){
128 NavigationUtil.openEditor((ICdmBase) firstElement, viewer.getControl().getShell());
129 }
130 }
131 });
132
133 //propagate selection
134 selectionChangedListener = (event -> selService.setSelection(event.getSelection()));
135 viewer.addSelectionChangedListener(selectionChangedListener);
136
137 //create context menu
138 menuService.registerContextMenu(viewer.getControl(), "eu.etaxonomy.taxeditor.navigator.popupmenu.taxonnavigator");
139 menuService.registerContextMenu(viewer.getControl(), "eu.etaxonomy.taxeditor.store.menu.import");
140
141 init();
142 }
143
144 /** {@inheritDoc} */
145 protected IAdaptable getInitialInput() {
146 Comparator<TaxonNode> comparator;
147 if (PreferencesUtil.getSortNodesNaturally()){
148 comparator = new TaxonNaturalComparator();
149 } else if (PreferencesUtil.getSortNodesStrictlyAlphabetically()){
150 comparator = new TaxonNodeByNameComparator();
151 }else {
152 comparator = new TaxonNodeByRankAndNameComparator();
153 }
154 TaxonNodeNavigatorComparator viewerComparator = new TaxonNodeNavigatorComparator(comparator);
155 viewer.setComparator(viewerComparator);
156 //FIXME E4 migrate linking with editor
157 // setLinkingEnabled(true);
158
159 if (CdmStore.isActive()) {
160
161 // TODO when closing and reopening the taxon navigator
162 // we do not preserve state. Closing the view, in contrary to
163 // closing the whole application
164 // should be handled by the state manager too
165 root = new Root(conversation);
166
167 return root;
168 }
169 return new EmptyRoot();
170 }
171
172 public void init() {
173 if (CdmStore.isActive() && conversation == null) {
174 conversation = CdmStore.createConversation();
175 conversation.registerForDataStoreChanges(TaxonNavigatorE4.this);
176 }
177 if (CdmStore.isActive()) {
178 cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
179 CdmApplicationState.getCurrentDataChangeService().register(this);
180 }
181 CdmStore.getLoginManager().addObserver(this);
182 viewer.setInput(getInitialInput());
183 }
184
185 /**
186 * Refresh this navigators viewer
187 */
188 public void refresh() {
189 if(getConversationHolder() != null){
190 getConversationHolder().bind();
191 //FIXME : Need to make sure this is a stable fix (ticket 3822)
192 if(!getConversationHolder().isCompleted()){
193 getConversationHolder().commit();
194 }
195 }
196 if(!viewer.getTree().isDisposed()){
197 viewer.refresh();
198 }
199 }
200
201 /**
202 * Refresh this navigators viewer
203 */
204 public void refresh(Set<?> objects) {
205 for(Object obj : objects) {
206 viewer.refresh(obj);
207 }
208 }
209
210 /**
211 * Removes all content
212 */
213 public void clear() {
214 viewer.setInput(new EmptyRoot());
215 }
216
217 public void restore(IMemento memento, IProgressMonitor monitor) {
218 root = new Root(conversation);
219 if (memento == null) {
220 viewer.setInput(root);
221 return;
222 }
223 int mementoWork = 0;
224 Set<TreePath> treePaths = new HashSet<TreePath>();
225 IMemento[] treePathMementos = null;
226
227 IMemento treePathsMemento = memento.getChild(TREE_PATHS);
228
229 if (treePathsMemento != null) {
230 treePathMementos = treePathsMemento.getChildren(TREE_PATH);
231 mementoWork = treePathMementos.length;
232 }
233 // begin the monitor with steps for all tree paths and steps for
234 // creating
235 // conversation s.o., refreshing the tree and setting the paths
236 IProgressMonitor subProgressMonitor = NavigationUtil
237 .getSubProgressMonitor(monitor, 1);
238
239 subProgressMonitor.beginTask(RESTORING_TAXON_NAVIGATOR,
240 1 + mementoWork + 5);
241 subProgressMonitor.subTask(RESTORING_TAXON_NAVIGATOR);
242 subProgressMonitor.worked(1);
243
244 conversation = CdmStore.createConversation();
245 subProgressMonitor.worked(1);
246 conversation.registerForDataStoreChanges(TaxonNavigatorE4.this);
247 subProgressMonitor.worked(1);
248 viewer.setInput(root);
249 subProgressMonitor.worked(1);
250 viewer.refresh();
251 subProgressMonitor.worked(1);
252
253 if (treePathMementos != null && treePathMementos.length > 0) {
254 for (IMemento treePathMemento : treePathMementos) {
255 TreePath treePath = createTreePathFromString(treePathMemento
256 .getID());
257 if (!subProgressMonitor.isCanceled() && treePath != null) {
258 treePaths.add(treePath);
259 subProgressMonitor.worked(1);
260 }
261 }
262 }
263 if (treePaths.size() > 0) {
264 TaxonNavigatorE4.this.viewer.setExpandedTreePaths(
265 treePaths.toArray(new TreePath[0]));
266 subProgressMonitor.worked(1);
267 }
268 subProgressMonitor.done();
269 }
270
271 private TreePath createTreePathFromString(String string) {
272
273 List<CdmBase> pathList = new ArrayList<CdmBase>();
274
275 if (string.length() == 0) {
276 return null;
277 }
278
279 for (String uuid : string.split(" ")) { //$NON-NLS-1$
280 CdmBase cdmBaseObject = CdmStore.getService(
281 IClassificationService.class).getTaxonNodeByUuid(
282 UUID.fromString(uuid));
283 if (cdmBaseObject == null) {
284 // is this a tree uuid?
285 cdmBaseObject = CdmStore.getService(
286 IClassificationService.class).load(
287 UUID.fromString(uuid));
288
289 if (cdmBaseObject == null) {
290 return null;
291 }
292 }
293 pathList.add(cdmBaseObject);
294 }
295 return new TreePath(pathList.toArray());
296 }
297
298 @Override
299 public ConversationHolder getConversationHolder() {
300 return conversation;
301 }
302
303 /** {@inheritDoc} */
304 @PreDestroy
305 public void dispose() {
306 dataChangeBehavior = null;
307 if (conversation != null) {
308 conversation.unregisterForDataStoreChanges(this);
309 }
310 if(cdmEntitySession != null) {
311 cdmEntitySession.dispose();
312 }
313 if(CdmApplicationState.getCurrentDataChangeService() != null) {
314 CdmApplicationState.getCurrentDataChangeService().unregister(this);
315 }
316 }
317
318 /** {@inheritDoc} */
319 @Focus
320 public void setFocus() {
321 if (getConversationHolder() != null) {
322 getConversationHolder().bind();
323 }
324 if(cdmEntitySession != null) {
325 cdmEntitySession.bind();
326 }
327 }
328
329 /** {@inheritDoc} */
330 @Override
331 public boolean postOperation(CdmBase objectAffectedByOperation) {
332 // nothing to do here
333 return true;
334 }
335
336 @Override
337 public boolean onComplete() {
338 return true;
339 }
340
341 @Override
342 public void update(Observable o, Object arg) {
343 if(o instanceof LoginManager){
344 refresh();
345 }
346 }
347 /** {@inheritDoc} */
348 @Override
349 public void update(CdmDataChangeMap changeEvents) {
350 if (dataChangeBehavior == null) {
351 dataChangeBehavior = new TaxonNavigatorDataChangeBehaviorE4(this);
352 }
353
354 DataChangeBridge.handleDataChange(changeEvents, dataChangeBehavior);
355 }
356
357 @Override
358 public ICdmEntitySession getCdmEntitySession() {
359 return cdmEntitySession;
360 }
361
362 @Override
363 public List<ITreeNode> getRootEntities() {
364 if(root != null) {
365 return root.getParentBeans();
366 }
367 return null;
368 }
369
370 @Override
371 public void onChange(CdmChangeEvent event) {
372 refresh();
373 for(CdmBase cb : event.getChangedObjects()) {
374 if(cb instanceof TaxonNode) {
375 TaxonNode tn = (TaxonNode)cb;
376 if(tn.getTaxon() == null) {
377 viewer.refresh(tn.getClassification());
378 } else {
379 viewer.refresh(cb);
380 }
381 } else if (cb instanceof Classification) {
382 viewer.refresh();
383 }
384 }
385 }
386
387 @Override
388 public Map<Object, List<String>> getPropertyPathsMap() {
389 Map<Object, List<String>> propertyPathsMap = new HashMap<Object, List<String>>();
390 List<String> taxonNodePropertyPaths = Arrays.asList(new String[] {
391 "taxon.name" //$NON-NLS-1$
392 });
393 propertyPathsMap.put("childNodes", taxonNodePropertyPaths); //$NON-NLS-1$
394 return propertyPathsMap;
395 }
396
397 /**
398 * {@inheritDoc}
399 */
400 @Override
401 public void contextAboutToStop(IMemento memento, IProgressMonitor monitor) {
402 // TODO Auto-generated method stub
403
404 }
405
406 /**
407 * {@inheritDoc}
408 */
409 @Override
410 public void contextStop(IMemento memento, IProgressMonitor monitor) {
411 }
412
413 /**
414 * {@inheritDoc}
415 */
416 @Override
417 public void contextStart(IMemento memento, IProgressMonitor monitor) {
418 if(viewer!=null){
419 init();
420 }
421 }
422
423 /**
424 * {@inheritDoc}
425 */
426 @Override
427 public void contextRefresh(IProgressMonitor monitor) {
428 }
429
430 /**
431 * {@inheritDoc}
432 */
433 @Override
434 public void workbenchShutdown(IMemento memento, IProgressMonitor monitor) {
435 }
436 }