/** * Copyright (c) 2014 by Brainwy Software Ltda. All Rights Reserved. * Licensed under the terms of the Eclipse Public License (EPL). * Please see the license.txt included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ package org.python.pydev.tree; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DragSource; import org.eclipse.swt.dnd.DragSourceEvent; import org.eclipse.swt.dnd.DragSourceListener; import org.eclipse.swt.dnd.DropTarget; import org.eclipse.swt.dnd.DropTargetAdapter; import org.eclipse.swt.dnd.DropTargetEvent; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; import org.python.pydev.plugin.PydevPlugin; import org.python.pydev.shared_core.callbacks.ICallback; public class EnabledTreeDragReorder { public static final String DRAG_IMAGE_DATA_KEY = "DRAG_IMAGE"; public static class DragData { public final String text; public final String image; public DragData(String text, String image) { this.text = text; this.image = image; } public void update(TreeItem item) { item.setText(text); if (image != null) { item.setImage(PydevPlugin.getImageCache().get(image)); item.setData(DRAG_IMAGE_DATA_KEY, image); } } } /** * Based on SWT Snippet91. */ public static void enableDrag(final Tree tree, final boolean acceptDropInTree, final ICallback<Object, Object> onDNDFinished) { Transfer[] types = new Transfer[] { TreeItemDragDataTransfer.getInstance() }; int operations = DND.DROP_MOVE;// | DND.DROP_COPY | DND.DROP_LINK; //Note: disable copy and link. final DragSource source = new DragSource(tree, operations); source.setTransfer(types); final TreeItem[] dragSourceItem = new TreeItem[1]; source.addDragListener(new DragSourceListener() { @Override public void dragStart(DragSourceEvent event) { TreeItem[] selection = tree.getSelection(); if (selection.length > 0 && selection[0].getItemCount() == 0) { event.doit = true; dragSourceItem[0] = selection[0]; } else { event.doit = false; } }; @Override public void dragSetData(DragSourceEvent event) { TreeItem treeItem = dragSourceItem[0]; if (treeItem != null) { event.data = new DragData(treeItem.getText(), (String) treeItem.getData(DRAG_IMAGE_DATA_KEY)); } } @Override public void dragFinished(DragSourceEvent event) { if (event.detail == DND.DROP_MOVE && dragSourceItem[0] != null) { dragSourceItem[0].dispose(); onDNDFinished.call(null); } dragSourceItem[0] = null; } }); DropTarget target = new DropTarget(tree, operations); target.setTransfer(types); target.addDropListener(new DropTargetAdapter() { @Override public void dropAccept(DropTargetEvent event) { TreeItem item = (TreeItem) event.item; if (item != null) { TreeItem parent = item.getParentItem(); if (!acceptDropInTree) { if (parent == null) { if (dragSourceItem[0] != null) { dragSourceItem[0] = null; //Don't dispose of it! } } } } } @Override public void dragOver(DropTargetEvent event) { event.feedback = DND.FEEDBACK_EXPAND | DND.FEEDBACK_SCROLL; event.detail = DND.DROP_NONE; //This is what prevents a drop when it can't happen. if (event.item != null) { TreeItem item = (TreeItem) event.item; if (item.getParentItem() == null && !acceptDropInTree) { event.feedback = DND.FEEDBACK_NONE; return; } event.detail = DND.DROP_MOVE; //Enable the drop to happen as we have a valid item. Point pt = tree.getDisplay().map(null, tree, event.x, event.y); Rectangle bounds = item.getBounds(); if (pt.y < bounds.y + bounds.height / 3) { event.feedback |= DND.FEEDBACK_INSERT_BEFORE; } else if (pt.y > bounds.y + 2 * bounds.height / 3) { event.feedback |= DND.FEEDBACK_INSERT_AFTER; } else { event.feedback |= DND.FEEDBACK_SELECT; } } } @Override public void drop(DropTargetEvent event) { System.out.println("dropDone"); if (event.data == null) { event.detail = DND.DROP_NONE; return; } DragData data = (DragData) event.data; if (event.item == null) { TreeItem item = new TreeItem(tree, SWT.NONE); data.update(item); } else { TreeItem item = (TreeItem) event.item; TreeItem parent = item.getParentItem(); Point pt = tree.getDisplay().map(null, tree, event.x, event.y); Rectangle bounds = item.getBounds(); if (parent != null) { TreeItem[] items = parent.getItems(); int index = 0; for (int i = 0; i < items.length; i++) { if (items[i] == item) { index = i; break; } } if (pt.y < bounds.y + bounds.height / 3) { TreeItem newItem = new TreeItem(parent, SWT.NONE, index); data.update(newItem); } else if (pt.y > bounds.y + 2 * bounds.height / 3) { TreeItem newItem = new TreeItem(parent, SWT.NONE, index + 1); data.update(newItem); } else { TreeItem newItem = new TreeItem(item, SWT.NONE); data.update(newItem); } } else { if (!acceptDropInTree) { return; } TreeItem[] items = tree.getItems(); int index = 0; for (int i = 0; i < items.length; i++) { if (items[i] == item) { index = i; break; } } if (pt.y < bounds.y + bounds.height / 3) { TreeItem newItem = new TreeItem(tree, SWT.NONE, index); data.update(newItem); } else if (pt.y > bounds.y + 2 * bounds.height / 3) { TreeItem newItem = new TreeItem(tree, SWT.NONE, index + 1); data.update(newItem); } else { TreeItem newItem = new TreeItem(item, SWT.NONE); data.update(newItem); } } } } }); } }