Project

General

Profile

Download (14.2 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2015 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.navigation.navigator.e4;
10

    
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;
16
import java.util.Set;
17
import java.util.UUID;
18

    
19
import javax.inject.Inject;
20

    
21
import org.apache.logging.log4j.LogManager;import org.apache.logging.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;
33

    
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;
52

    
53
/**
54
 * @author k.luther
55
 * @date 02.06.2015
56
 */
57
public class TreeNodeDropAdapterE4 extends ViewerDropAdapter implements IPostMoniteredOperationEnabled{
58

    
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;
67

    
68
    private static final Logger logger = LogManager.getLogger(TreeNodeDropAdapterE4.class);
69

    
70
    private TaxonNavigatorE4 taxonNavigator;
71
    UpdateResult result;
72
    TaxonNodeDto targetITaxonTreeNode;
73
    HashSet<TaxonNodeDto> taxonNodes;
74
    SecReferenceHandlingEnum secHandling;
75
    UUID newSecUuid;
76
	public static final String ID = "eu.etaxonomy.taxeditor.navigation.navigator.dropassistant"; //$NON-NLS-1$
77

    
78
	private static final EnumSet<CRUD> UPDATE = EnumSet.of(CRUD.UPDATE);
79

    
80
	@Inject
81
	private EPartService partService;
82

    
83
	public enum MovingType{
84
	    CHILD, PREVIOUS, BEHIND
85
	}
86

    
87
	protected TreeNodeDropAdapterE4(TaxonNavigatorE4 navigator) {
88
	    super(navigator.getViewer());
89
	    this.taxonNavigator = navigator;
90
	}
91

    
92
	@Override
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;
98

    
99
			if(taxonNodes != null) {
100
			    boolean success = moveTaxon(taxonNodes, targetTreeNode);
101
				return success;
102
            }
103
		}
104
		return false;
105
	}
106

    
107
	private Set<TaxonNodeDto> getSelectedTaxa(){
108
		taxonNodes = new HashSet<>();
109

    
110
		ISelection selection = LocalSelectionTransfer.getTransfer().getSelection();
111
		if (selection instanceof TreeSelection) {
112

    
113
			Iterator<?> selectionIterator = ((TreeSelection) selection).iterator();
114

    
115
			while (selectionIterator.hasNext()){
116
				Object object = selectionIterator.next();
117
				if(object instanceof TaxonNodeDto){
118
					TaxonNodeDto taxonNode = (TaxonNodeDto) object;
119
					taxonNodes.add(taxonNode);
120
				}
121
			}
122
		}
123
		return taxonNodes;
124
	}
125

    
126
	@Override
127
	public boolean validateDrop(Object target, int operation,
128
			TransferData transferType) {
129

    
130
		if (target instanceof TaxonNodeDto) {
131

    
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 ?
138
		        			true :
139
		        			CdmStore.currentAuthentiationHasPermission(node.getTaxon(), UPDATE);
140

    
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$
144
		            }
145
		            return false;
146
		        }
147
		    }
148

    
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$
157
			    }
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$
162
	                    }
163
	                    return false;
164
	                }
165
			    isNotSameTaxonNode = isNotSameTaxonNode && !taxonNode.equals(target);
166
			    isNotSameParent = isNotSameParent && !taxonNode.getParentUUID().equals(((TaxonNodeDto) target).getUuid());
167
			    nodeUuids.add(taxonNode.getUuid());
168

    
169
		    }
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);
174
			    }
175

    
176
                if (
177
			        !isNotSameTaxonNode
178
			        || !isNotSameParent
179
			        || !hasPermission
180

    
181
    	            ) {
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$
184
                    }
185
					return false;
186
				}
187
			}
188
			logger.debug("OK_STATUS"); //$NON-NLS-1$
189
			return true;
190
	}
191

    
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
       
199

    
200
        IUndoContext workspaceUndoContext = taxonNavigator.getUndoContext();
201
         int movingTypeInt = 0;
202
		if (PreferencesUtil.isNodesSortedNaturally()){
203
			String[] buttonLables = {TREE_NODE_DROP_ADAPTER_CHILD, TREE_NODE_DROP_ADAPTER_BEHIND,TREE_NODE_DROP_ADAPTER_CANCEL};
204
			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);
205
			dialog.open();
206
			int returnCode = dialog.getReturnCode();
207

    
208
			if (returnCode == 0){
209
				if (workspaceUndoContext == null) {
210
					logger.error("Workspace undo context is null. DND operation cancelled"); //$NON-NLS-1$
211
					return false;
212
				}
213

    
214
			}else if (returnCode == 1){
215
				if (workspaceUndoContext == null) {
216
					logger.error("Workspace undo context is null. DND operation cancelled"); //$NON-NLS-1$
217
					return false;
218
				}
219
				movingTypeInt = 2;
220

    
221
			} else {
222
				return false;
223
			}
224
		}
225
		
226
		 boolean targetIsPublish = targetITaxonTreeNode.isPublish();
227
	        boolean isPublishEqual = true;
228
	        Set<UUID> secReferences = new HashSet<>();
229
	        while(taxIterator.hasNext()){
230
	            node = taxIterator.next();
231
	            uuids.add(node.getUuid());
232
	            isPublishEqual &= targetIsPublish == node.isPublish();
233
	            secReferences.add(node.getSecUuid());
234
	        }
235

    
236
	        if (!isPublishEqual){
237
	            MessageDialog.openWarning(null, "Publish status differ", Messages.RemotingChangeAcceptedTaxonToSynonym_warning_publish);
238
	        }
239
	        secHandling = PreferencesUtil.getSecReferenceHandlingPreference();
240
	        newSecUuid = null;
241

    
242
	        boolean testForDifferentParent = (secReferences.size() == 1 && (secHandling.equals(SecReferenceHandlingEnum.KeepOrWarn) ||secHandling.equals(SecReferenceHandlingEnum.KeepOrSelect)) && !secReferences.contains(parentSecUuid));
243
	        boolean testForAlwaysSelect = secHandling.equals(SecReferenceHandlingEnum.AlwaysSelect);
244

    
245
	        if ( testForAlwaysSelect || (secReferences.size() > 1 && (secHandling.equals(SecReferenceHandlingEnum.KeepOrWarn) || secHandling.equals(SecReferenceHandlingEnum.KeepOrSelect))) || testForDifferentParent){
246
	            //The moved nodes have different secundum references
247
	            String message = null;
248
	            String[] options = null;
249
	            if (secHandling.equals(SecReferenceHandlingEnum.AlwaysSelect) && (parentSecUuid != null && secReferences.contains(parentSecUuid))){
250
	                message = Messages.TreeNodeDropAdapter_Select_Sec_Reference_Handling_message_always_select;
251
	                options = new String[]{Messages.RemotingChangeAcceptedTaxonToSynonymHandler_Select_Sec_Reference_Keep, Messages.RemotingChangeAcceptedTaxonToSynonymHandler_Select_Sec_Reference_Select};
252
	            }else {
253
	                message = Messages.TreeNodeDropAdapter_Select_Sec_Reference_Handling_message;
254
	                options = new String[]{Messages.RemotingChangeAcceptedTaxonToSynonymHandler_Select_Sec_Reference_Keep,  Messages.RemotingChangeAcceptedTaxonToSynonymHandler_Select_Sec_Reference_Select, Messages.TreeNodeDropAdapter_Select_Sec_Reference_Parent, };
255
	            }
256
	            int result = 0;
257
	            if (secHandling.equals(SecReferenceHandlingEnum.KeepOrWarn) ){
258
	                MessageDialog.openWarning(null, "Secundum references differ", Messages.MoveTaxon_Different_Secundum_References);
259
	            }else{
260
	                result = MessagingUtils.confirmDialog(Messages.RemotingChangeAcceptedTaxonToSynonymHandler_Select_Sec_Reference_Handling_title, message, options);
261
	            }
262

    
263
//	            int result = MessagingUtils.confirmDialog(Messages.RemotingChangeAcceptedTaxonToSynonymHandler_Select_Sec_Reference_Handling_title, Messages.RemotingChangeAcceptedTaxonToSynonymHandler_Select_Sec_Reference_Handling_message,
264
//	                    new String[]{Messages.RemotingChangeAcceptedTaxonToSynonymHandler_Select_Sec_Reference_Keep, Messages.RemotingChangeAcceptedTaxonToSynonymHandler_Select_Sec_Reference_Parent, Messages.RemotingChangeAcceptedTaxonToSynonymHandler_Select_Sec_Reference_Select});
265
	            if (result == 1){
266
	                //select new reference
267
	                Reference sec = ReferenceSelectionDialog.select(AbstractUtility.getShell(), null);
268
	                newSecUuid = sec != null? sec.getUuid(): null;
269
	            }else if (result == 2){
270
	                //use parent sec
271
	                secHandling = SecReferenceHandlingEnum.UseNewParentSec;
272
	                newSecUuid = parentSecUuid;
273
	            }else if (result == 0){
274
	                //keep sec (also homotypic synonyms with different sec will keep the secundum)
275
	                secHandling = SecReferenceHandlingEnum.KeepOrWarn;
276
	            }else{
277
	                return false;
278
	            }
279
	        }
280
		moveNodes(uuids, targetITaxonTreeNode.getUuid(), movingTypeInt);
281
        return true;
282
	}
283

    
284
	private void moveNodes(Set<UUID> taxonNodesToMoveUuid, UUID newParentTreeNodeUuid, int movingTypeInt){
285
	    UUID uuid = CdmApplicationState.getLongRunningTasksService().monitLongRunningTask(taxonNodesToMoveUuid,
286
                newParentTreeNodeUuid, movingTypeInt, secHandling, newSecUuid);
287

    
288
        Display.getDefault().asyncExec(new Runnable() {
289
            @Override
290
            public void run() {
291
                AbstractUtility.executeMoniteredOperation("Move Taxon to new parent: ",
292
                        uuid,
293
                        1000,
294
                        false,
295
                        TreeNodeDropAdapterE4.this,
296
                        null,
297
                        false,
298
                        true);
299
            }
300
        });
301
	}
302

    
303
	@Override
304
	public void dragOver(DropTargetEvent event) {
305
		super.dragOver(event);
306
		event.feedback = DND.FEEDBACK_SELECT | DND.FEEDBACK_INSERT_AFTER | DND.FEEDBACK_SCROLL;
307
	}
308

    
309
    @Override
310
    public void postOperation(IRemotingProgressMonitor monitor) {
311
        EventUtility.postEvent(WorkbenchEventConstants.REFRESH_NAVIGATOR, targetITaxonTreeNode);
312
        taxonNodes.forEach(nodeDto->EventUtility.postEvent(WorkbenchEventConstants.REFRESH_NAME_EDITOR, nodeDto.getTaxonUuid()));
313
        EventUtility.postEvent(WorkbenchEventConstants.REFRESH_NAME_EDITOR, targetITaxonTreeNode.getTaxonUuid());
314

    
315
    }
316
}
(6-6/6)