smaller changes for drag & dop with natural order in taxonnavigator
[taxeditor.git] / eu.etaxonomy.taxeditor.navigation / src / main / java / eu / etaxonomy / taxeditor / navigation / navigator / TreeNodeDropAdapter.java
1 // $Id$
2 /**
3 * Copyright (C) 2015 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
9 */
10
11 package eu.etaxonomy.taxeditor.navigation.navigator;
12
13 import java.util.EnumSet;
14 import java.util.HashSet;
15 import java.util.Iterator;
16 import java.util.Set;
17 import java.util.UUID;
18
19 import org.apache.log4j.Logger;
20 import org.eclipse.core.commands.operations.IUndoContext;
21 import org.eclipse.jface.dialogs.MessageDialog;
22 import org.eclipse.jface.util.LocalSelectionTransfer;
23 import org.eclipse.jface.viewers.ISelection;
24 import org.eclipse.jface.viewers.TreeSelection;
25 import org.eclipse.jface.viewers.ViewerDropAdapter;
26 import org.eclipse.swt.dnd.DND;
27 import org.eclipse.swt.dnd.DropTargetEvent;
28 import org.eclipse.swt.dnd.TransferData;
29
30 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
31 import eu.etaxonomy.cdm.model.common.CdmBase;
32 import eu.etaxonomy.cdm.model.taxon.Classification;
33 import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode;
34 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
35 import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
36 import eu.etaxonomy.taxeditor.navigation.NavigationUtil;
37 import eu.etaxonomy.taxeditor.navigation.navigator.operation.MoveTaxonOperation;
38 import eu.etaxonomy.taxeditor.operation.AbstractPostOperation;
39 import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
40 import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
41 import eu.etaxonomy.taxeditor.store.CdmStore;
42
43 /**
44 * <p>TreeNodeDropAdapter class.</p>
45 *
46 * @author k.luther
47 * @date 02.06.2015
48 * @version 1.0
49 */
50 public class TreeNodeDropAdapter extends ViewerDropAdapter implements IPostOperationEnabled {
51
52 /**
53 * @param viewer
54 */
55 protected TreeNodeDropAdapter(TaxonNavigatorViewer navigatorViewer) {
56 super(navigatorViewer);
57 this.navigatorViewer = navigatorViewer;
58
59 }
60
61 private final TaxonNavigatorViewer navigatorViewer;
62 private static final Logger logger = Logger.getLogger(TreeNodeDropAdapter.class);
63
64 /** Constant <code>ID="eu.etaxonomy.taxeditor.navigation.navig"{trunked}</code> */
65 public static final String ID = "eu.etaxonomy.taxeditor.navigation.navigator.dropassistant"; //$NON-NLS-1$
66
67 private static final EnumSet<CRUD> UPDATE = EnumSet.of(CRUD.UPDATE);
68
69 public enum MovingType{
70 CHILD, PREVIOUS, BEHIND
71 }
72
73
74
75 /* (non-Javadoc)
76 * @see org.eclipse.ui.navigator.CommonDropAdapterAssistant#handleDrop(org.eclipse.ui.navigator.CommonDropAdapter, org.eclipse.swt.dnd.DropTargetEvent, java.lang.Object)
77 */
78 /** {@inheritDoc} */
79 @Override
80 public boolean performDrop(Object target) {
81
82
83 if (target instanceof ITaxonTreeNode) {
84 Set<TaxonNode> taxonNodes = getSelectedTaxa();
85 ITaxonTreeNode targetTreeNode = (ITaxonTreeNode) target;
86 if (targetTreeNode instanceof Classification){
87 targetTreeNode = ((Classification)targetTreeNode).getRootNode();
88 targetTreeNode = HibernateProxyHelper.deproxy(targetTreeNode, TaxonNode.class);
89 }
90 if(taxonNodes != null) {
91 if (taxonNodes.size() == 1){
92 return moveTaxon(taxonNodes, targetTreeNode);
93 } else{
94 if( MessageDialog.openConfirm(null, "Moving taxon", "The operation move accepted taxon to other parent is available only for a single taxon.")){
95 return true;
96 }
97 }
98 }
99 }
100
101 return false;
102 }
103
104 private Set<TaxonNode> getSelectedTaxa(){
105 HashSet<TaxonNode> taxonNodes = new HashSet<TaxonNode>();
106
107 ISelection selection = LocalSelectionTransfer.getTransfer().getSelection();
108 if (selection instanceof TreeSelection) {
109
110 Iterator selectionIterator = ((TreeSelection) selection).iterator();
111
112 while (selectionIterator.hasNext()){
113 Object object = selectionIterator.next();
114 if(object instanceof TaxonNode){
115 TaxonNode taxonNode = (TaxonNode) object;
116 taxonNodes.add(taxonNode);
117 }
118 }
119 }
120 return taxonNodes.size() > 0 ? taxonNodes : null;
121 }
122
123 /* (non-Javadoc)
124 * @see org.eclipse.ui.navigator.CommonDropAdapter#validateDrop(java.lang.Object, int, org.eclipse.swt.dnd.TransferData)
125 */
126 /** {@inheritDoc} */
127 @Override
128 public boolean validateDrop(Object target, int operation,
129 TransferData transferType) {
130
131 if (target instanceof ITaxonTreeNode) {
132
133 // check users permissions with target taxonnode and taxon
134 if (target instanceof TaxonNode) {
135 TaxonNode targetNode = (TaxonNode)target;
136 Boolean hasTargetNodePermission = CdmStore.currentAuthentiationHasPermission(targetNode, UPDATE);
137 Boolean hasTargetTaxonPermission = CdmStore.currentAuthentiationHasPermission(targetNode.getTaxon(), UPDATE);
138
139 if(logger.isDebugEnabled()){
140 logger.debug("target: " + targetNode.getTaxon().getTitleCache());
141 }
142
143 if(!hasTargetNodePermission || ! hasTargetNodePermission){
144 if(logger.isDebugEnabled()){
145 logger.debug("CANCEL_STATUS for target node: " + hasTargetNodePermission.toString() + " " + hasTargetTaxonPermission.toString() + " ");
146 }
147 return false;
148 }
149 }
150
151 // do not allow to drop onto itself and
152 // check users permissions with all selected taxon nodes and taxa
153 for(TaxonNode taxonNode : getSelectedTaxa()){
154 logger.debug("selectedTaxa: " + taxonNode.getTaxon().getTitleCache());
155 Boolean isSameTaxonNode = taxonNode.equals(target);
156 Boolean hasTaxonNodePermission = CdmStore.currentAuthentiationHasPermission(taxonNode, UPDATE);
157 Boolean hasTaxonPermission = CdmStore.currentAuthentiationHasPermission(taxonNode.getTaxon(), UPDATE);
158 if (
159 isSameTaxonNode
160 || !hasTaxonNodePermission
161 || !hasTaxonPermission
162 ) {
163 if(logger.isDebugEnabled()){
164 logger.debug("CANCEL_STATUS for selected " + isSameTaxonNode.toString() + " " + hasTaxonNodePermission.toString() + " " + hasTaxonPermission.toString() + " ");
165 }
166 return false;
167 }
168 }
169 logger.debug("OK_STATUS");
170 return true;
171 }
172 logger.debug("CANCEL_STATUS");
173 return false;
174 }
175
176
177 /**
178 * @param childTaxonNode
179 * @param parentTaxon
180 * @return
181 */
182 private boolean moveTaxon(Set<TaxonNode> taxonNodes, ITaxonTreeNode targetITaxonTreeNode) {
183
184 TaxonNavigator taxonNavigator;
185 taxonNavigator = (TaxonNavigator) NavigationUtil.showView(TaxonNavigator.ID);
186
187 if(targetITaxonTreeNode instanceof TaxonNode){
188
189 TaxonNode targetTaxonNode = (TaxonNode) targetITaxonTreeNode;
190 // Make sure parent taxon does not have unsaved changes
191 if (NavigationUtil.isDirty(targetTaxonNode)){
192 MessageDialog.openWarning(NavigationUtil.getShell(), "Unsaved Parent Taxon", "There are unsaved " +
193 "changes in the parent taxon. Pleas save first.");
194 return false;
195 }
196
197 }
198 Iterator<TaxonNode> taxIterator = taxonNodes.iterator();
199 Set<UUID> uuids = new HashSet<UUID>();
200 TaxonNode node = null;
201 while(taxIterator.hasNext()){
202 node = taxIterator.next();
203 uuids.add(node.getUuid());
204 }
205 if (!PreferencesUtil.getSortNodesNaturally()){
206 IUndoContext workspaceUndoContext = NavigationUtil.getWorkbenchUndoContext();
207 if (workspaceUndoContext == null) {
208 logger.error("Workspace undo context is null. DND operation cancelled");
209 return false;
210 }
211
212 AbstractPostOperation operation = new MoveTaxonOperation
213 ("Move Taxon", workspaceUndoContext, uuids, targetITaxonTreeNode, this, taxonNavigator, MovingType.CHILD);
214 NavigationUtil.executeOperation(operation);
215
216 logger.info("Moved taxa to new parent " + targetITaxonTreeNode);
217 return true;
218 }else{
219 String[] buttonLables = {"Child", "Behind","Cancel"};
220 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);
221 dialog.open();
222 int returnCode = dialog.getReturnCode();
223 if (returnCode == 0){
224 IUndoContext workspaceUndoContext = NavigationUtil.getWorkbenchUndoContext();
225 if (workspaceUndoContext == null) {
226 logger.error("Workspace undo context is null. DND operation cancelled");
227 return false;
228 }
229
230 AbstractPostOperation operation = new MoveTaxonOperation
231 ("Move Taxon", workspaceUndoContext, uuids, targetITaxonTreeNode, this, taxonNavigator, MovingType.CHILD);
232 NavigationUtil.executeOperation(operation);
233
234 logger.info("Moved taxa to new parent " + targetITaxonTreeNode);
235 return true;
236 }else if (returnCode == 1){
237 IUndoContext workspaceUndoContext = NavigationUtil.getWorkbenchUndoContext();
238 if (workspaceUndoContext == null) {
239 logger.error("Workspace undo context is null. DND operation cancelled");
240 return false;
241 }
242 TaxonNode targetNode = (TaxonNode) targetITaxonTreeNode;
243
244 AbstractPostOperation operation = new MoveTaxonOperation
245 ("Move Taxon", workspaceUndoContext, uuids, targetNode, this, taxonNavigator, MovingType.PREVIOUS);
246 NavigationUtil.executeOperation(operation);
247
248 logger.info("Moved taxa to new parent " + targetITaxonTreeNode);
249 return true;
250 }
251 // } else if (returnCode == 2){
252 // IUndoContext workspaceUndoContext = NavigationUtil.getWorkbenchUndoContext();
253 // if (workspaceUndoContext == null) {
254 // logger.error("Workspace undo context is null. DND operation cancelled");
255 // return false;
256 // }
257 // TaxonNode targetNode = (TaxonNode) targetITaxonTreeNode;
258 //
259 // AbstractPostOperation operation = new MoveTaxonOperation
260 // ("Move Taxon", workspaceUndoContext, uuids, targetNode, this, taxonNavigator, MovingType.BEHIND);
261 // NavigationUtil.executeOperation(operation);
262 //
263 // logger.info("Moved taxa to new parent " + targetITaxonTreeNode);
264 // return true;
265 // }
266 else{
267 return false;
268 }
269
270
271 }
272 }
273
274 /* (non-Javadoc)
275 * @see eu.etaxonomy.taxeditor.operations.IPostOperationEnabled#postOperation(eu.etaxonomy.cdm.model.common.CdmBase)
276 */
277 /** {@inheritDoc} */
278 @Override
279 public boolean postOperation(CdmBase objectAffectedByOperation) {
280 return true;
281 }
282
283 /**
284 * <p>onComplete</p>
285 *
286 * @return a boolean.
287 */
288 @Override
289 public boolean onComplete() {
290 // TODO Auto-generated method stub
291 return false;
292 }
293 @Override
294 public void dragOver(DropTargetEvent event) {
295 super.dragOver(event);
296 event.feedback = DND.FEEDBACK_SELECT | DND.FEEDBACK_INSERT_AFTER;
297
298 }
299
300 }