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