2 * Copyright (C) 2017 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
9 package eu
.etaxonomy
.taxeditor
.view
.e4
;
11 import java
.util
.Collection
;
14 import javax
.annotation
.PreDestroy
;
15 import javax
.inject
.Inject
;
16 import javax
.inject
.Named
;
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
;
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
;
63 public abstract class AbstractCdmEditorPart
<V
extends Viewer
>
64 implements IDirtyMarkable
, ISelectionElementEditingPart
, IPostOperationEnabled
{
66 private static final Logger logger
= LogManager
.getLogger();
68 private DelaySelection delaySelection
= null;
71 * This is the monitor for the DelaySelection runnable.
72 * If it is <code>true</code> then it is currently delaying a selection.
74 private boolean isInDelay
;
75 private boolean isEnabled
= true;
78 * This class invokes internal_selectionChanged() in a separate thread.
79 * This allows an asynchronous and/or delayed handling of selection changes
81 private class DelaySelection
implements Runnable
{
82 private Object selection
;
83 private MPart activePart
;
84 private MPart thisPart
;
85 private EPartService partService
;
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
;
96 //multiple selections are not supported
99 && !activePart
.equals(thisPart
)
100 && selection
instanceof IStructuredSelection
101 && ((IStructuredSelection
) selection
).size()>1){
106 // no active editor found
107 if(activePart
== thisPart
&& WorkbenchUtility
.getActiveEditorPart(partService
) == null && showEmptyIfNoActiveEditor()){
112 if (viewer
!= null && viewer
.getControl()!= null && viewer
.getInput() != null && !viewer
.getControl().isDisposed()){
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
);
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
))
134 selectionChanged_internal(selection
, activePart
, thisPart
);
135 }catch (Exception ex
){
136 logger
.error("Error during selectionChanged_internal", ex
);
139 previousSelection
= selection
;
144 public synchronized void setSelection(Object selection
) {
145 this.selection
= selection
;
148 public synchronized void setActivePart(MPart activePart
) {
149 this.activePart
= activePart
;
152 public synchronized void setThisPart(MPart thisPart
) {
153 this.thisPart
= thisPart
;
156 public synchronized void setThisPartService(EPartService partService
) {
157 this.partService
= partService
;
163 protected MPart thisPart
;
165 protected MPart selectionProvidingPart
;
167 protected Object previousSelection
;
169 protected ISelectionChangedListener selectionChangedListener
;
171 public ISelectionChangedListener
getSelectionChangedListener() {
172 return selectionChangedListener
;
176 protected ESelectionService selService
;
179 protected IEclipseContext context
;
181 protected abstract void selectionChanged_internal(Object selection
, MPart activePart
, MPart thisPart
);
183 protected boolean showEmptyIfNoActiveEditor(){
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
){
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
);
197 delaySelection
.setSelection(selection
);
198 delaySelection
.setActivePart(activePart
);
199 delaySelection
.setThisPart(thisPart
);
200 delaySelection
.setThisPartService(partService
);
203 //as long as the delay thread is running,
206 sync
.asyncExec(delaySelection
);
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
);
217 if (part
instanceof IBulkEditor
){
218 ((IBulkEditor
)part
).setSelection(createSelection(object
));
224 public V
getViewer() {
228 public boolean isEnabled() {
232 public void setEnabled(boolean isEnabled
) {
233 this.isEnabled
= isEnabled
;
236 protected void showViewer(IStructuredSelection selection
, MPart activePart
, Viewer viewer
){
237 if(CdmStore
.getCurrentSessionManager().getActiveSession() == null){
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()){
246 viewer
.getControl().setEnabled(true);
248 if (element
instanceof Taxon
){
250 Taxon taxon
= HibernateProxyHelper
.deproxy(element
, Taxon
.class);
251 if (part
instanceof ITaxonEditor
){
252 TaxonNode node
= ((ITaxonEditor
) part
).getTaxonNode();
254 boolean doEnable
= CdmStore
.currentAuthentiationHasPermission(node
,
255 RequiredPermissions
.TAXON_EDIT
);
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;
265 if (!taxonnodePermissionExists
){
270 //TODO: differ between the views
271 this.isEnabled
= doEnable
;
275 if (taxon
.isMisapplication() || taxon
.isProparteSynonym() ){
277 if(part
instanceof ITaxonEditor
){
278 Taxon accepted
= ((ITaxonEditor
) part
).getTaxon();
280 Set
<TaxonRelationship
> rels
= taxon
.getTaxonRelations(accepted
);
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
;
295 if(element
instanceof TermDto
){
296 element
= CdmStore
.getService(ITermService
.class).load(((TermDto
) element
).getUuid());
298 else if(element
instanceof TermVocabularyDto
){
299 element
= CdmStore
.getService(IVocabularyService
.class).load(((TermVocabularyDto
) element
).getUuid());
302 selectionProvidingPart
= activePart
;
303 if (viewer
instanceof DetailsViewerE4
){
305 if (selectionProvidingPart
.getElementId().equals("eu.etaxonomy.taxeditor.editor.view.checklist.e4.DistributionEditorPart")){
306 ((DetailsViewerE4
)viewer
).setDetailsEnabled(false);
308 ((DetailsViewerE4
)viewer
).setDetailsEnabled(isEnabled
);
310 ((DetailsViewerE4
)viewer
).setInput(element
, part
);
313 if(element
instanceof TermNodeDto
){
314 element
= CdmStore
.getService(ITermNodeService
.class).load(((TermNodeDto
) element
).getUuid());
316 if (activePart
.getObject() instanceof DetailsPartE4
&& element
instanceof TaxonName
){
317 selectionProvidingPart
= ((DetailsPartE4
)activePart
.getObject()).getSelectionProvidingPart();
320 viewer
.setInput(element
);
321 viewer
.getControl().setEnabled(isEnabled
);
327 protected Object
getPartObject(MPart activePart
) {
328 Object partObject
= activePart
;
329 Object wrappedPart
= WorkbenchUtility
.getE4WrappedPart(activePart
);
330 if(wrappedPart
!= null){
331 partObject
= wrappedPart
;
336 protected void showEmptyPage() {
337 if(viewer
!=null && viewer
.getControl()!=null && !viewer
.getControl().isDisposed() ){
338 viewer
.setInput(null);
340 if (!viewer
.getControl().isDisposed()){
341 viewer
.getControl().setEnabled(false);
343 }catch(SWTException e
){
344 if (PreferencesUtil
.isShowUpWidgetIsDisposedMessages() && e
.getMessage().equals("Widget is disposed")){
345 MessagingUtils
.errorDialog("Widget is disposed",
347 MessagingUtils
.WIDGET_IS_DISPOSED_MESSAGE
,
357 thisPart
.setLabel(getViewName());
361 protected IStructuredSelection
createSelection(Object selection
) {
365 IStructuredSelection structuredSelection
;
366 if(!(selection
instanceof IStructuredSelection
)){
367 structuredSelection
= new StructuredSelection(selection
);
370 structuredSelection
= (IStructuredSelection
) selection
;
372 return structuredSelection
;
377 public boolean postOperation(Object objectAffectedByOperation
) {
378 changed(objectAffectedByOperation
);
383 public boolean onComplete() {
389 public MPart
getSelectionProvidingPart() {
390 return selectionProvidingPart
;
394 private void dispose() {
397 private void reset(){
398 previousSelection
= null;
399 selectionProvidingPart
= null;
400 delaySelection
= null;
401 context
.deactivate();
405 private void persistState(){
410 public void forceDirty() {
413 protected abstract String
getViewName();