/* ****************************************************************************** * Copyright (c) 2006-2012 XMind Ltd. and others. * * This file is a part of XMind 3. XMind releases 3 and * above are dual-licensed under the Eclipse Public License (EPL), * which is available at http://www.eclipse.org/legal/epl-v10.html * and the GNU Lesser General Public License (LGPL), * which is available at http://www.gnu.org/licenses/lgpl.html * See http://www.xmind.net/license.html for details. * * Contributors: * XMind Ltd. - initial API and implementation *******************************************************************************/ package org.xmind.ui.internal.tools; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.geometry.Point; import org.eclipse.jface.util.Util; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.graphics.Image; import org.xmind.gef.GEF; import org.xmind.gef.Request; import org.xmind.gef.draw2d.IReferencedFigure; import org.xmind.gef.event.DragDropEvent; import org.xmind.gef.graphicalpolicy.IStructure; import org.xmind.gef.part.IPart; import org.xmind.gef.status.IStatusListener; import org.xmind.gef.status.StatusEvent; import org.xmind.gef.tool.GraphicalTool; import org.xmind.ui.branch.ILockableBranchStructureExtension; import org.xmind.ui.branch.IMovableBranchStructureExtension; import org.xmind.ui.mindmap.IBranchPart; import org.xmind.ui.mindmap.ISheetPart; import org.xmind.ui.mindmap.ITopicPart; import org.xmind.ui.mindmap.MindMapUI; import org.xmind.ui.style.Styles; import org.xmind.ui.tools.ITopicMoveToolHelper; import org.xmind.ui.tools.ParentSearchKey; import org.xmind.ui.tools.ParentSearcher; public class MindMapDndTool extends GraphicalTool implements IStatusListener { private static ITopicMoveToolHelper defaultHelper = null; private BranchDummy dummy = null; private IBranchPart targetParent = null; private ParentSearcher parentSearcher = null; private ParentSearchKey key = null; private boolean insideTopicAllowed = false; private ITopicMoveToolHelper helper = null; private Request request = null; private Image image = null; public MindMapDndTool() { getStatus().addStatusListener(this); } private boolean acceptEvent(DragDropEvent de) { if ((de.operations & DND.DROP_COPY) != 0) { de.detail = DND.DROP_COPY; return true; } else if ((de.operations & DND.DROP_MOVE) != 0) { de.detail = DND.DROP_MOVE; return true; } else if ((de.operations & DND.DROP_LINK) != 0) { de.detail = DND.DROP_LINK; return true; } return false; } protected boolean handleDragStarted(DragDropEvent de) { if (image != null) { image.dispose(); image = null; } targetParent = null; request = null; insideTopicAllowed = isInsideTopicAllowed(de); if (acceptEvent(de)) { createDummy(de); lockBranchStructures(getTargetViewer().getRootPart()); return true; } return false; } private void lockBranchStructures(IPart part) { if (part instanceof IBranchPart) { IBranchPart branch = (IBranchPart) part; IStructure sa = branch.getBranchPolicy().getStructure(branch); if (sa instanceof ILockableBranchStructureExtension) { ((ILockableBranchStructureExtension) sa).lock(branch); } } for (IPart child : part.getChildren()) { lockBranchStructures(child); } } private void unlockBranchStructures(IPart part) { if (part instanceof IBranchPart) { IBranchPart branch = (IBranchPart) part; IStructure sa = branch.getBranchPolicy().getStructure(branch); if (sa instanceof ILockableBranchStructureExtension) { ((ILockableBranchStructureExtension) sa).unlock(branch); } } for (IPart child : part.getChildren()) { unlockBranchStructures(child); } } private void createDummy(DragDropEvent de) { if (dummy != null) { dummy.dispose(); dummy = null; } dummy = new BranchDummy(getTargetViewer(), false); decorateDummy(dummy, de); } protected void decorateDummy(BranchDummy dummy, DragDropEvent de) { dummy.setStyle(Styles.ShapeClass, Styles.TOPIC_SHAPE_NO_BORDER); dummy.getTopic().setTitleText(""); //$NON-NLS-1$ dummy.getBranch().refresh(); } protected boolean isInsideTopicAllowed(DragDropEvent de) { return true; } protected boolean handleDragOver(DragDropEvent de) { if (acceptEvent(de)) { if (dummy != null) { key = new ParentSearchKey(null, (IReferencedFigure) dummy .getBranch().getTopicPart().getFigure(), getCursorPosition()); key.setFeedback(dummy.getBranch()); targetParent = updateTargetParent(); updateWithParent(targetParent); return true; } } return false; } private IBranchPart updateTargetParent() { return getParentSearcher().searchTargetParent( getTargetViewer().getRootPart(), key); } private void updateWithParent(IBranchPart parent) { updateDummyWithParent(parent); updateHelperWithParent(parent); } private void updateDummyWithParent(IBranchPart parent) { updateDummyPosition(getCursorPosition()); } protected void updateDummyPosition(Point pos) { IFigure fig = dummy.getBranch().getFigure(); if (fig != null) { if (fig instanceof IReferencedFigure) { ((IReferencedFigure) fig).setReference(pos); } else { fig.setLocation(pos); } } } private void updateHelperWithParent(IBranchPart parent) { ITopicMoveToolHelper oldHelper = this.helper; ITopicMoveToolHelper newHelper = getHelper(parent); if (newHelper != oldHelper) { if (oldHelper != null) oldHelper.deactivate(getDomain(), getTargetViewer()); if (newHelper != null) newHelper.activate(getDomain(), getTargetViewer()); this.helper = newHelper; } if (helper != null) { helper.update(parent, key); } } private ITopicMoveToolHelper getHelper(IBranchPart parent) { return getDefaultHelper(); } protected static ITopicMoveToolHelper getDefaultHelper() { if (defaultHelper == null) { defaultHelper = new TopicMoveToolHelper(); } return defaultHelper; } protected ParentSearcher getParentSearcher() { if (parentSearcher == null) { parentSearcher = new ParentSearcher(insideTopicAllowed); } return parentSearcher; } protected boolean handleDragDismissed(DragDropEvent de) { if (acceptEvent(de)) { createRequest(de); destroyDummy(); changeActiveTool(GEF.TOOL_DEFAULT); return true; } return false; } private IPart findDropTarget(IPart target) { if (target == null) return null; if (target.hasRole(GEF.ROLE_DROP_TARGET)) return target; return findDropTarget(target.getParent()); } private void createRequest(DragDropEvent de) { request = new Request(GEF.REQ_DROP); IPart target = findDropTarget(de.target); if (target == null) { target = (ISheetPart) getTargetViewer() .getAdapter(ISheetPart.class); } request.setPrimaryTarget(target); ITopicPart targetTopic = targetParent == null ? null : targetParent .getTopicPart(); if (targetTopic != null) { request.setParameter(GEF.PARAM_PARENT, targetTopic); int targetIndex = -1; if (!isFloatMove() && targetParent != null) { targetIndex = getParentSearcher().getIndex(targetParent, key); } request.setParameter(GEF.PARAM_INDEX, targetIndex); } if (isFloatMove() || targetParent == null) { Point position = getCursorPosition(); request.setParameter(GEF.PARAM_POSITION, position); } if (isCopyMove()) { request.setParameter(MindMapUI.PARAM_COPY, Boolean.TRUE); } if (targetParent != null) { IStructure structure = targetParent.getBranchPolicy().getStructure( targetParent); if (structure instanceof IMovableBranchStructureExtension) { ((IMovableBranchStructureExtension) structure) .decorateMoveInRequest(targetParent, key, null, request); } } } private void destroyDummy() { unlockBranchStructures(getTargetViewer().getRootPart()); if (helper != null) { helper.deactivate(getDomain(), getTargetViewer()); helper = null; } if (dummy != null) { dummy.dispose(); dummy = null; } if (image != null) { image.dispose(); image = null; } } private boolean isFloatMove() { return getStatus().isStatus(GEF.ST_SHIFT_PRESSED); } private boolean isCopyMove() { if (Util.isMac()) return getStatus().isStatus(GEF.ST_ALT_PRESSED); return getStatus().isStatus(GEF.ST_CONTROL_PRESSED); } protected boolean handleDrop(DragDropEvent de) { if (acceptEvent(de)) { if (request != null) { request.setParameter(MindMapUI.PARAM_DND_DATA, de.dndData); try { getDomain().handleRequest(request); } finally { request = null; } return true; } } return false; } public void statusChanged(StatusEvent event) { } }