ref #10138: after parsing send event to update the details view
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / view / e4 / AbstractCdmEditorPart.java
1 /**
2 * Copyright (C) 2017 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 package eu.etaxonomy.taxeditor.view.e4;
10
11 import java.util.Collection;
12 import java.util.Set;
13
14 import javax.annotation.PreDestroy;
15 import javax.inject.Inject;
16 import javax.inject.Named;
17
18 import org.apache.logging.log4j.LogManager;
19 import org.apache.logging.log4j.Logger;
20 import org.eclipse.e4.core.contexts.IEclipseContext;
21 import org.eclipse.e4.core.di.annotations.Optional;
22 import org.eclipse.e4.ui.di.PersistState;
23 import org.eclipse.e4.ui.di.UISynchronize;
24 import org.eclipse.e4.ui.model.application.ui.basic.MPart;
25 import org.eclipse.e4.ui.services.IServiceConstants;
26 import org.eclipse.e4.ui.workbench.modeling.EPartService;
27 import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
28 import org.eclipse.jface.viewers.ISelectionChangedListener;
29 import org.eclipse.jface.viewers.IStructuredSelection;
30 import org.eclipse.jface.viewers.StructuredSelection;
31 import org.eclipse.jface.viewers.Viewer;
32 import org.eclipse.swt.SWTException;
33 import org.springframework.security.core.GrantedAuthority;
34
35 import eu.etaxonomy.cdm.api.service.ITermNodeService;
36 import eu.etaxonomy.cdm.api.service.ITermService;
37 import eu.etaxonomy.cdm.api.service.IVocabularyService;
38 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
39 import eu.etaxonomy.cdm.model.name.TaxonName;
40 import eu.etaxonomy.cdm.model.taxon.Taxon;
41 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
42 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
43 import eu.etaxonomy.cdm.persistence.dto.TermDto;
44 import eu.etaxonomy.cdm.persistence.dto.TermNodeDto;
45 import eu.etaxonomy.cdm.persistence.dto.TermVocabularyDto;
46 import eu.etaxonomy.taxeditor.editor.IBulkEditor;
47 import eu.etaxonomy.taxeditor.editor.ITaxonEditor;
48 import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
49 import eu.etaxonomy.taxeditor.model.MessagingUtils;
50 import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
51 import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
52 import eu.etaxonomy.taxeditor.security.RequiredPermissions;
53 import eu.etaxonomy.taxeditor.store.CdmStore;
54 import eu.etaxonomy.taxeditor.view.e4.details.DetailsPartE4;
55 import eu.etaxonomy.taxeditor.view.e4.details.DetailsViewerE4;
56 import eu.etaxonomy.taxeditor.workbench.WorkbenchUtility;
57 import eu.etaxonomy.taxeditor.workbench.part.ISelectionElementEditingPart;
58
59 /**
60 * @author pplitzner
61 * @since Aug 10, 2017
62 */
63 public abstract class AbstractCdmEditorPart<V extends Viewer>
64 implements IDirtyMarkable, ISelectionElementEditingPart, IPostOperationEnabled{
65
66 private static final Logger logger = LogManager.getLogger();
67
68 private DelaySelection delaySelection = null;
69
70 /**
71 * This is the monitor for the DelaySelection runnable.
72 * If it is <code>true</code> then it is currently delaying a selection.
73 */
74 private boolean isInDelay;
75 private boolean isEnabled = true;
76
77 /**
78 * This class invokes internal_selectionChanged() in a separate thread.
79 * This allows an asynchronous and/or delayed handling of selection changes
80 */
81 private class DelaySelection implements Runnable{
82 private Object selection;
83 private MPart activePart;
84 private MPart thisPart;
85 private EPartService partService;
86
87 public DelaySelection(Object selection, MPart activePart, MPart thisPart, EPartService partService) {
88 this.selection = selection;
89 this.activePart= activePart;
90 this.thisPart = thisPart;
91 this.partService = partService;
92 }
93
94 @Override
95 public void run() {
96 //multiple selections are not supported
97 if(activePart != null
98 && thisPart != null
99 && !activePart.equals(thisPart)
100 && selection instanceof IStructuredSelection
101 && ((IStructuredSelection) selection).size()>1){
102 showEmptyPage();
103 return;
104 }
105
106 // no active editor found
107 if(activePart == thisPart && WorkbenchUtility.getActiveEditorPart(partService) == null && showEmptyIfNoActiveEditor()){
108 showEmptyPage();
109 return;
110 }
111
112 if (viewer != null && viewer.getControl()!= null && viewer.getInput() != null && !viewer.getControl().isDisposed()){
113 try{
114 viewer.getControl().setEnabled(isEnabled);
115 }catch(SWTException e){
116 System.out.println("...exception3 ("+ (thisPart == null? "":thisPart.getLabel()) + ")");
117 logger.debug("Something went wrong for viewer.getControl().setEnabled(true) in " + this.getClass().getSimpleName(), e);
118 }
119 }
120
121 //same as previous selection? => return
122 if((previousSelection != null && selection != null)
123 && (activePart != null && selectionProvidingPart != null
124 && activePart.equals(selectionProvidingPart))
125 && (previousSelection == selection
126 || previousSelection.equals(selection)
127 || new StructuredSelection(selection).equals(previousSelection))
128 ) {
129 isInDelay = false;
130 return;
131 }
132
133 try{
134 selectionChanged_internal(selection, activePart, thisPart);
135 }catch (Exception ex){
136 logger.error("Error during selectionChanged_internal", ex);
137 }
138 finally{
139 previousSelection = selection;
140 isInDelay = false;
141 }
142 }
143
144 public synchronized void setSelection(Object selection) {
145 this.selection = selection;
146 }
147
148 public synchronized void setActivePart(MPart activePart) {
149 this.activePart = activePart;
150 }
151
152 public synchronized void setThisPart(MPart thisPart) {
153 this.thisPart = thisPart;
154 }
155
156 public synchronized void setThisPartService(EPartService partService) {
157 this.partService = partService;
158 }
159 }
160
161 protected V viewer;
162
163 protected MPart thisPart;
164
165 protected MPart selectionProvidingPart;
166
167 protected Object previousSelection;
168
169 protected ISelectionChangedListener selectionChangedListener;
170
171 public ISelectionChangedListener getSelectionChangedListener() {
172 return selectionChangedListener;
173 }
174
175 @Inject
176 protected ESelectionService selService;
177
178 @Inject
179 protected IEclipseContext context;
180
181 protected abstract void selectionChanged_internal(Object selection, MPart activePart, MPart thisPart);
182
183 protected boolean showEmptyIfNoActiveEditor(){
184 return true;
185 }
186
187 @Inject
188 public void selectionChanged(
189 @Optional@Named(IServiceConstants.ACTIVE_SELECTION)Object selection,
190 @Optional@Named(IServiceConstants.ACTIVE_PART)MPart activePart,
191 MPart thisPart, UISynchronize sync, EPartService partService){
192
193 //set the delay selection which puts the change handling to the end
194 if(delaySelection == null){
195 delaySelection = new DelaySelection(selection, activePart, thisPart, partService);
196 }else{
197 delaySelection.setSelection(selection);
198 delaySelection.setActivePart(activePart);
199 delaySelection.setThisPart(thisPart);
200 delaySelection.setThisPartService(partService);
201 }
202
203 //as long as the delay thread is running,
204 if(!isInDelay){
205 isInDelay = true;
206 sync.asyncExec(delaySelection);
207 }
208 }
209
210 @Override
211 public void changed(Object object) {
212 if(selectionProvidingPart != null){
213 Object part = selectionProvidingPart.getObject();
214 if(part instanceof IDirtyMarkable){
215 ((IDirtyMarkable) part).changed(object);
216 }
217 if (part instanceof IBulkEditor){
218 ((IBulkEditor)part).setSelection(createSelection(object));
219 }
220
221 }
222 }
223
224 public V getViewer() {
225 return viewer;
226 }
227
228 public boolean isEnabled() {
229 return isEnabled;
230 }
231
232 public void setEnabled(boolean isEnabled) {
233 this.isEnabled = isEnabled;
234 }
235
236 protected void showViewer(IStructuredSelection selection, MPart activePart, Viewer viewer){
237 if(CdmStore.getCurrentSessionManager().getActiveSession() == null){
238 return;
239 }
240 if(viewer != null && viewer.getControl() != null && !viewer.getControl().isDisposed()){
241 Object element = selection.getFirstElement();
242 Object part = getPartObject(activePart);
243 if (viewer.getControl().isDisposed()){
244 return;
245 }
246 viewer.getControl().setEnabled(true);
247 if(element != null){
248 if (element instanceof Taxon){
249
250 Taxon taxon = HibernateProxyHelper.deproxy(element, Taxon.class);
251 if (part instanceof ITaxonEditor){
252 TaxonNode node = ((ITaxonEditor) part).getTaxonNode();
253 if (node != null){
254 boolean doEnable = CdmStore.currentAuthentiationHasPermission(node,
255 RequiredPermissions.TAXON_EDIT);
256 if (!doEnable){
257 //check whether there are explicit TaxonNode rights
258 boolean taxonnodePermissionExists = false;
259 Collection<? extends GrantedAuthority> authorities = CdmStore.getCurrentAuthentiation().getAuthorities();
260 for (GrantedAuthority grantedAuthority: authorities){
261 if (grantedAuthority.getAuthority().startsWith("TAXONNODE")){
262 taxonnodePermissionExists = true;
263 }
264 }
265 if (!taxonnodePermissionExists){
266 doEnable = true;
267 }
268 }
269
270 //TODO: differ between the views
271 this.isEnabled = doEnable;
272 }
273 }
274
275 if (taxon.isMisapplication() || taxon.isProparteSynonym() ){
276
277 if(part instanceof ITaxonEditor){
278 Taxon accepted = ((ITaxonEditor) part).getTaxon();
279
280 Set<TaxonRelationship> rels = taxon.getTaxonRelations(accepted);
281
282 if (rels != null && rels.iterator().hasNext() && !taxon.equals(accepted)){
283 TaxonRelationship rel = rels.iterator().next();
284 if ((rel.getType().isMisappliedName() || rel.getType().isAnySynonym()) && !rel.getFromTaxon().equals(((ITaxonEditor) part).getTaxon())){
285 viewer.setInput(rel);
286 selectionProvidingPart = activePart;
287 return;
288 }
289 }
290 }
291 }
292 }
293
294 //unwrap term DTOs
295 if(element instanceof TermDto){
296 element = CdmStore.getService(ITermService.class).load(((TermDto) element).getUuid());
297 }
298 else if(element instanceof TermVocabularyDto){
299 element = CdmStore.getService(IVocabularyService.class).load(((TermVocabularyDto) element).getUuid());
300 }
301
302 selectionProvidingPart = activePart;
303 if (viewer instanceof DetailsViewerE4){
304
305 if (selectionProvidingPart.getElementId().equals("eu.etaxonomy.taxeditor.editor.view.checklist.e4.DistributionEditorPart")){
306 ((DetailsViewerE4)viewer).setDetailsEnabled(false);
307 }else{
308 ((DetailsViewerE4)viewer).setDetailsEnabled(isEnabled);
309 }
310 ((DetailsViewerE4)viewer).setInput(element, part);
311 }
312 else{
313 if(element instanceof TermNodeDto){
314 element = CdmStore.getService(ITermNodeService.class).load(((TermNodeDto) element).getUuid());
315 }
316 if (activePart.getObject() instanceof DetailsPartE4 && element instanceof TaxonName){
317 selectionProvidingPart = ((DetailsPartE4)activePart.getObject()).getSelectionProvidingPart();
318 }
319
320 viewer.setInput(element);
321 viewer.getControl().setEnabled(isEnabled);
322 }
323 }
324 }
325 }
326
327 protected Object getPartObject(MPart activePart) {
328 Object partObject = activePart;
329 Object wrappedPart = WorkbenchUtility.getE4WrappedPart(activePart);
330 if(wrappedPart != null){
331 partObject = wrappedPart;
332 }
333 return partObject;
334 }
335
336 protected void showEmptyPage() {
337 if(viewer!=null && viewer.getControl()!=null && !viewer.getControl().isDisposed() ){
338 viewer.setInput(null);
339 try{
340 if (!viewer.getControl().isDisposed()){
341 viewer.getControl().setEnabled(false);
342 }
343 }catch(SWTException e){
344 if (PreferencesUtil.isShowUpWidgetIsDisposedMessages() && e.getMessage().equals("Widget is disposed")){
345 MessagingUtils.errorDialog("Widget is disposed",
346 null,
347 MessagingUtils.WIDGET_IS_DISPOSED_MESSAGE,
348 null,
349 e,
350 true);
351 }
352 }
353 }
354
355 reset();
356 if(thisPart!=null){
357 thisPart.setLabel(getViewName());
358 }
359 }
360
361 protected IStructuredSelection createSelection(Object selection) {
362 if(selection==null){
363 return null;
364 }
365 IStructuredSelection structuredSelection;
366 if(!(selection instanceof IStructuredSelection)){
367 structuredSelection = new StructuredSelection(selection);
368 }
369 else{
370 structuredSelection = (IStructuredSelection) selection;
371 }
372 return structuredSelection;
373 }
374
375
376 @Override
377 public boolean postOperation(Object objectAffectedByOperation) {
378 changed(objectAffectedByOperation);
379 return true;
380 }
381
382 @Override
383 public boolean onComplete() {
384 viewer.refresh();
385 return true;
386 }
387
388 @Override
389 public MPart getSelectionProvidingPart() {
390 return selectionProvidingPart;
391 }
392
393 @PreDestroy
394 private void dispose() {
395 }
396
397 private void reset(){
398 previousSelection = null;
399 selectionProvidingPart = null;
400 delaySelection = null;
401 context.deactivate();
402 }
403
404 @PersistState
405 private void persistState(){
406
407 }
408
409 @Override
410 public void forceDirty() {
411 }
412
413 protected abstract String getViewName();
414
415 }