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