2 * Copyright (C) 2015 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
.navigation
.navigator
.e4
;
11 import java
.util
.ArrayList
;
12 import java
.util
.EnumSet
;
13 import java
.util
.HashSet
;
14 import java
.util
.Iterator
;
15 import java
.util
.List
;
17 import java
.util
.UUID
;
19 import javax
.inject
.Inject
;
21 import org
.apache
.log4j
.Logger
;
22 import org
.eclipse
.core
.commands
.operations
.IUndoContext
;
23 import org
.eclipse
.e4
.ui
.workbench
.modeling
.EPartService
;
24 import org
.eclipse
.jface
.dialogs
.MessageDialog
;
25 import org
.eclipse
.jface
.util
.LocalSelectionTransfer
;
26 import org
.eclipse
.jface
.viewers
.ISelection
;
27 import org
.eclipse
.jface
.viewers
.TreeSelection
;
28 import org
.eclipse
.jface
.viewers
.ViewerDropAdapter
;
29 import org
.eclipse
.swt
.dnd
.DND
;
30 import org
.eclipse
.swt
.dnd
.DropTargetEvent
;
31 import org
.eclipse
.swt
.dnd
.TransferData
;
32 import org
.eclipse
.swt
.widgets
.Display
;
34 import eu
.etaxonomy
.cdm
.api
.application
.CdmApplicationState
;
35 import eu
.etaxonomy
.cdm
.api
.service
.ITaxonNodeService
;
36 import eu
.etaxonomy
.cdm
.api
.service
.UpdateResult
;
37 import eu
.etaxonomy
.cdm
.common
.monitor
.IRemotingProgressMonitor
;
38 import eu
.etaxonomy
.cdm
.model
.metadata
.SecReferenceHandlingEnum
;
39 import eu
.etaxonomy
.cdm
.model
.permission
.CRUD
;
40 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
41 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
42 import eu
.etaxonomy
.cdm
.persistence
.dto
.TaxonNodeDto
;
43 import eu
.etaxonomy
.taxeditor
.event
.EventUtility
;
44 import eu
.etaxonomy
.taxeditor
.event
.WorkbenchEventConstants
;
45 import eu
.etaxonomy
.taxeditor
.model
.AbstractUtility
;
46 import eu
.etaxonomy
.taxeditor
.model
.MessagingUtils
;
47 import eu
.etaxonomy
.taxeditor
.navigation
.l10n
.Messages
;
48 import eu
.etaxonomy
.taxeditor
.operation
.IPostMoniteredOperationEnabled
;
49 import eu
.etaxonomy
.taxeditor
.preference
.PreferencesUtil
;
50 import eu
.etaxonomy
.taxeditor
.store
.CdmStore
;
51 import eu
.etaxonomy
.taxeditor
.ui
.dialog
.selection
.ReferenceSelectionDialog
;
57 public class TreeNodeDropAdapterE4
extends ViewerDropAdapter
implements IPostMoniteredOperationEnabled
{
59 protected static final String TREE_NODE_DROP_ADAPTER_UNSAVED_PARENT_MESSAGE
= Messages
.TreeNodeDropAdapter_UNSAVED_PARENT_MESSAGE
;
60 protected static final String TREE_NODE_DROP_ADAPTER_UNSAVED_PARENT
= Messages
.TreeNodeDropAdapter_UNSAVED_PARENT
;
61 protected static final String TREE_NODE_DROP_ADAPTER_MOVE_TAXON
= Messages
.TreeNodeDropAdapter_MOVE_TAXON
;
62 protected static final String TREE_NODE_DROP_ADAPTER_CANCEL
= Messages
.TreeNodeDropAdapter_CANCEL
;
63 protected static final String TREE_NODE_DROP_ADAPTER_BEHIND
= Messages
.TreeNodeDropAdapter_BEHIND
;
64 protected static final String TREE_NODE_DROP_ADAPTER_CHILD
= Messages
.TreeNodeDropAdapter_CHILD
;
65 protected static final String DO_YOU_WANT_TO_MOVE_THE_TAXONNODE_AS_CHILD_OR_BEHIND_THE_TARGET_NODE
= Messages
.TreeNodeDropAdapter_MOVE_BEHIND
;
66 protected static final String TARGET_NODE
= Messages
.TreeNodeDropAdapter_TARGET_NODE
;
68 private static final Logger logger
= Logger
.getLogger(TreeNodeDropAdapterE4
.class);
70 private TaxonNavigatorE4 taxonNavigator
;
72 TaxonNodeDto targetITaxonTreeNode
;
73 HashSet
<TaxonNodeDto
> taxonNodes
;
74 SecReferenceHandlingEnum secHandling
;
76 public static final String ID
= "eu.etaxonomy.taxeditor.navigation.navigator.dropassistant"; //$NON-NLS-1$
78 private static final EnumSet
<CRUD
> UPDATE
= EnumSet
.of(CRUD
.UPDATE
);
81 private EPartService partService
;
83 public enum MovingType
{
84 CHILD
, PREVIOUS
, BEHIND
87 protected TreeNodeDropAdapterE4(TaxonNavigatorE4 navigator
) {
88 super(navigator
.getViewer());
89 this.taxonNavigator
= navigator
;
93 public boolean performDrop(Object data
) {
94 Object target
= getCurrentTarget();
95 if (getCurrentTarget() instanceof TaxonNodeDto
) {
96 Set
<TaxonNodeDto
> taxonNodes
= getSelectedTaxa();
97 TaxonNodeDto targetTreeNode
= (TaxonNodeDto
) target
;
99 if(taxonNodes
!= null) {
100 boolean success
= moveTaxon(taxonNodes
, targetTreeNode
);
107 private Set
<TaxonNodeDto
> getSelectedTaxa(){
108 taxonNodes
= new HashSet
<>();
110 ISelection selection
= LocalSelectionTransfer
.getTransfer().getSelection();
111 if (selection
instanceof TreeSelection
) {
113 Iterator
<?
> selectionIterator
= ((TreeSelection
) selection
).iterator();
115 while (selectionIterator
.hasNext()){
116 Object object
= selectionIterator
.next();
117 if(object
instanceof TaxonNodeDto
){
118 TaxonNodeDto taxonNode
= (TaxonNodeDto
) object
;
119 taxonNodes
.add(taxonNode
);
127 public boolean validateDrop(Object target
, int operation
,
128 TransferData transferType
) {
130 if (target
instanceof TaxonNodeDto
) {
132 // check users permissions with target taxonnode and taxon
133 if (target
instanceof TaxonNodeDto
) {
134 TaxonNodeDto targetNode
= (TaxonNodeDto
)target
;
135 TaxonNode node
= CdmStore
.getService(ITaxonNodeService
.class).load(targetNode
.getUuid());
136 boolean hasTargetNodePermission
= CdmStore
.currentAuthentiationHasPermission(node
, UPDATE
);
137 boolean hasTargetTaxonPermission
= node
.getTaxon() == null ?
139 CdmStore
.currentAuthentiationHasPermission(node
.getTaxon(), UPDATE
);
141 if(!hasTargetNodePermission
|| ! hasTargetNodePermission
){
142 if(logger
.isDebugEnabled()){
143 logger
.debug("CANCEL_STATUS for target node: " + hasTargetNodePermission
+ " " + hasTargetTaxonPermission
+ " "); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
149 // do not allow to drop onto itself and
150 // check users permissions with all selected taxon nodes and taxa
151 List
<UUID
> nodeUuids
= new ArrayList
<>();
152 boolean isNotSameTaxonNode
= true;
153 boolean isNotSameParent
= true;
154 for(TaxonNodeDto taxonNode
: getSelectedTaxa()){
155 if (logger
.isDebugEnabled()){
156 logger
.debug("selectedTaxa: " + (taxonNode
.getTaxonUuid() == null?
"-" : taxonNode
.getTitleCache())); //$NON-NLS-1$
158 boolean isClassification
= taxonNode
.getTaxonUuid()== null;
159 if (isClassification
) {
160 if(logger
.isDebugEnabled()){
161 logger
.debug("CANCEL_STATUS for selected classification " + taxonNode
.getClassificationUUID()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
165 isNotSameTaxonNode
= isNotSameTaxonNode
&& !taxonNode
.equals(target
);
166 isNotSameParent
= isNotSameParent
&& !taxonNode
.getParentUUID().equals(((TaxonNodeDto
) target
).getUuid());
167 nodeUuids
.add(taxonNode
.getUuid());
170 List
<TaxonNode
> nodes
= CdmStore
.getService(ITaxonNodeService
.class).load(nodeUuids
, null);
171 boolean hasPermission
= true;
172 for (TaxonNode node
: nodes
){
173 hasPermission
= hasPermission
&& CdmStore
.currentAuthentiationHasPermission(node
, UPDATE
) && CdmStore
.currentAuthentiationHasPermission(node
.getTaxon(), UPDATE
);
182 if(logger
.isDebugEnabled()){
183 logger
.debug("CANCEL_STATUS for selected " + isNotSameTaxonNode
+ Messages
.TreeNodeDropAdapter_10
+ hasPermission
+ " "); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
188 logger
.debug("OK_STATUS"); //$NON-NLS-1$
192 private boolean moveTaxon(Set
<TaxonNodeDto
> taxonNodes
, TaxonNodeDto targetITaxonTreeNode
) {
193 Iterator
<TaxonNodeDto
> taxIterator
= taxonNodes
.iterator();
194 this.targetITaxonTreeNode
= targetITaxonTreeNode
;
195 UUID parentSecUuid
= targetITaxonTreeNode
.getSecUuid();
196 Set
<UUID
> uuids
= new HashSet
<UUID
>();
197 TaxonNodeDto node
= null;
198 boolean targetIsPublish
= targetITaxonTreeNode
.isPublish();
199 boolean isPublishEqual
= true;
200 Set
<UUID
> secReferences
= new HashSet
<>();
201 while(taxIterator
.hasNext()){
202 node
= taxIterator
.next();
203 uuids
.add(node
.getUuid());
204 isPublishEqual
&= targetIsPublish
== node
.isPublish();
205 secReferences
.add(node
.getSecUuid());
208 if (!isPublishEqual
){
209 MessageDialog
.openWarning(null, "Publish status differ", Messages
.RemotingChangeAcceptedTaxonToSynonym_warning_publish
);
211 secHandling
= PreferencesUtil
.getSecReferenceHandlingPreference();
213 if ( secHandling
.equals(SecReferenceHandlingEnum
.AlwaysSelect
) || (secReferences
.size() > 1 && secHandling
.equals(SecReferenceHandlingEnum
.KeepOrWarn
) || secHandling
.equals(SecReferenceHandlingEnum
.KeepOrSelect
)) || (secReferences
.size() == 1 && (secHandling
.equals(SecReferenceHandlingEnum
.KeepOrWarn
) ||secHandling
.equals(SecReferenceHandlingEnum
.KeepOrSelect
)) && !secReferences
.contains(parentSecUuid
))){
214 //The moved nodes have different secundum references
215 String message
= null;
216 String
[] options
= null;
217 if (secHandling
.equals(SecReferenceHandlingEnum
.AlwaysSelect
) && (parentSecUuid
!= null && secReferences
.contains(parentSecUuid
))){
218 message
= Messages
.TreeNodeDropAdapter_Select_Sec_Reference_Handling_message_always_select
;
219 options
= new String
[]{Messages
.RemotingChangeAcceptedTaxonToSynonymHandler_Select_Sec_Reference_Keep
, Messages
.RemotingChangeAcceptedTaxonToSynonymHandler_Select_Sec_Reference_Select
};
221 message
= Messages
.TreeNodeDropAdapter_Select_Sec_Reference_Handling_message
;
222 options
= new String
[]{Messages
.RemotingChangeAcceptedTaxonToSynonymHandler_Select_Sec_Reference_Keep
, Messages
.RemotingChangeAcceptedTaxonToSynonymHandler_Select_Sec_Reference_Select
, Messages
.TreeNodeDropAdapter_Select_Sec_Reference_Parent
, };
225 if (secHandling
.equals(SecReferenceHandlingEnum
.KeepOrWarn
) ){
226 MessageDialog
.openWarning(null, "Secundum references differ", Messages
.MoveTaxon_Different_Secundum_References
);
228 result
= MessagingUtils
.confirmDialog(Messages
.RemotingChangeAcceptedTaxonToSynonymHandler_Select_Sec_Reference_Handling_title
, message
, options
);
231 // int result = MessagingUtils.confirmDialog(Messages.RemotingChangeAcceptedTaxonToSynonymHandler_Select_Sec_Reference_Handling_title, Messages.RemotingChangeAcceptedTaxonToSynonymHandler_Select_Sec_Reference_Handling_message,
232 // new String[]{Messages.RemotingChangeAcceptedTaxonToSynonymHandler_Select_Sec_Reference_Keep, Messages.RemotingChangeAcceptedTaxonToSynonymHandler_Select_Sec_Reference_Parent, Messages.RemotingChangeAcceptedTaxonToSynonymHandler_Select_Sec_Reference_Select});
234 //select new reference
235 Reference sec
= ReferenceSelectionDialog
.select(AbstractUtility
.getShell(), null);
236 newSecUuid
= sec
!= null? sec
.getUuid(): null;
237 }else if (result
== 2){
239 secHandling
= SecReferenceHandlingEnum
.UseNewParentSec
;
240 newSecUuid
= parentSecUuid
;
241 }else if (result
== 0){
242 //keep sec (also homotypic synonyms with different sec will keep the secundum)
243 secHandling
= SecReferenceHandlingEnum
.KeepOrWarn
;
249 IUndoContext workspaceUndoContext
= taxonNavigator
.getUndoContext();
250 int movingTypeInt
= 0;
251 if (PreferencesUtil
.isNodesSortedNaturally()){
252 String
[] buttonLables
= {TREE_NODE_DROP_ADAPTER_CHILD
, TREE_NODE_DROP_ADAPTER_BEHIND
,TREE_NODE_DROP_ADAPTER_CANCEL
};
253 MessageDialog dialog
= new MessageDialog(null, TARGET_NODE
, null, DO_YOU_WANT_TO_MOVE_THE_TAXONNODE_AS_CHILD_OR_BEHIND_THE_TARGET_NODE
, MessageDialog
.QUESTION_WITH_CANCEL
, buttonLables
, 0);
255 int returnCode
= dialog
.getReturnCode();
257 if (returnCode
== 0){
258 if (workspaceUndoContext
== null) {
259 logger
.error("Workspace undo context is null. DND operation cancelled"); //$NON-NLS-1$
263 }else if (returnCode
== 1){
264 if (workspaceUndoContext
== null) {
265 logger
.error("Workspace undo context is null. DND operation cancelled"); //$NON-NLS-1$
274 moveNodes(uuids
, targetITaxonTreeNode
.getUuid(), movingTypeInt
);
278 private void moveNodes(Set
<UUID
> taxonNodesToMoveUuid
, UUID newParentTreeNodeUuid
, int movingTypeInt
){
279 UUID uuid
= CdmApplicationState
.getLongRunningTasksService().monitLongRunningTask(taxonNodesToMoveUuid
,
280 newParentTreeNodeUuid
, movingTypeInt
, secHandling
, newSecUuid
);
282 Display
.getDefault().asyncExec(new Runnable() {
285 AbstractUtility
.executeMoniteredOperation("Move Taxon to new parent: ",
289 TreeNodeDropAdapterE4
.this,
298 public void dragOver(DropTargetEvent event
) {
299 super.dragOver(event
);
300 event
.feedback
= DND
.FEEDBACK_SELECT
| DND
.FEEDBACK_INSERT_AFTER
| DND
.FEEDBACK_SCROLL
;
304 public void postOperation(IRemotingProgressMonitor monitor
) {
305 EventUtility
.postEvent(WorkbenchEventConstants
.REFRESH_NAVIGATOR
, targetITaxonTreeNode
);
306 taxonNodes
.forEach(nodeDto
->EventUtility
.postEvent(WorkbenchEventConstants
.REFRESH_NAME_EDITOR
, nodeDto
.getTaxonUuid()));
307 EventUtility
.postEvent(WorkbenchEventConstants
.REFRESH_NAME_EDITOR
, targetITaxonTreeNode
.getTaxonUuid());