/* ****************************************************************************** * 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 static org.xmind.ui.mindmap.MindMapUI.COLOR_WARNING; import static org.xmind.ui.mindmap.MindMapUI.LINE_WIDTH_DUMMY; import static org.xmind.ui.style.StyleUtils.createBranchConnection; import static org.xmind.ui.style.StyleUtils.isSameDecoration; import org.eclipse.draw2d.Figure; import org.eclipse.draw2d.Graphics; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.Layer; import org.eclipse.draw2d.PositionConstants; import org.eclipse.draw2d.UpdateManager; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Display; import org.xmind.gef.EditDomain; import org.xmind.gef.GEF; import org.xmind.gef.IGraphicalViewer; import org.xmind.gef.IViewer; import org.xmind.gef.draw2d.IAnchor; import org.xmind.gef.draw2d.IAnchorListener; import org.xmind.gef.draw2d.IUseTransparency; import org.xmind.gef.draw2d.SelectionFigure; import org.xmind.gef.draw2d.decoration.ICorneredDecoration; import org.xmind.gef.draw2d.geometry.PrecisionPoint; import org.xmind.gef.draw2d.graphics.Path; import org.xmind.gef.graphicalpolicy.IStructure; import org.xmind.gef.service.IAnimationService; import org.xmind.gef.service.IFeedbackService; import org.xmind.ui.branch.IBranchStructureExtension; import org.xmind.ui.branch.IInsertableBranchStructureExtension; import org.xmind.ui.branch.IInsertion; import org.xmind.ui.decorations.IBranchConnectionDecoration; import org.xmind.ui.decorations.IBranchConnections; import org.xmind.ui.internal.mindmap.DecoratedAnchor; import org.xmind.ui.mindmap.IBranchPart; import org.xmind.ui.mindmap.MindMapUI; import org.xmind.ui.resources.ColorUtils; import org.xmind.ui.tools.ITopicMoveToolHelper; import org.xmind.ui.tools.ParentSearchKey; import org.xmind.ui.tools.ToolHelperBase; public class TopicMoveToolHelper extends ToolHelperBase implements ITopicMoveToolHelper { private class DummyConnectionFigure extends Figure { /** * @see org.eclipse.draw2d.Figure#paintFigure(org.eclipse.draw2d.Graphics) */ @Override public void paintFigure(Graphics graphics) { graphics.setAntialias(SWT.ON); if (parent != null) { if (connection != null) connection.paint(this, graphics); if (!cursorOverParent) paintExpandedLine(graphics, parent); } super.paintFigure(graphics); } private void paintExpandedLine(Graphics graphics, IBranchPart parent) { IBranchConnections connections = parent.getConnections(); if (connections == null) return; int orientation = connections.getSourceOrientation(); if (orientation == PositionConstants.NONE) return; IAnchor anc = connections.getSourceAnchor(); if (anc == null) return; PrecisionPoint p1 = anc.getLocation(orientation, 0); PrecisionPoint p2 = anc.getLocation(orientation, connections .getSourceExpansion()); graphics.setLineStyle(SWT.LINE_SOLID); graphics.setLineWidth(Math.max(LINE_WIDTH_DUMMY, connections .getLineWidth())); graphics.setForegroundColor(ColorUtils.getColor(COLOR_WARNING)); graphics.setAlpha(connections.getAlpha()); Path p = new Path(Display.getCurrent()); p.moveTo(p1); p.lineTo(p2); graphics.drawPath(p); p.dispose(); } } private class DummyAnchor extends DecoratedAnchor { public DummyAnchor() { super(null); } public void setOwner(IFigure figure) { super.setOwner(figure); } } private IBranchPart parent = null; private boolean showConnection = true; private IBranchConnectionDecoration connection = null; private IFigure connectionFigure = null; private boolean cursorOverParent = false; private IFeedbackService feedbackService = null; private IAnimationService animationService = null; private IInsertion insertion = null; private IAnchor sourceAnchor = null; private IAnchorListener sourceAnchorListener = null; private DummyAnchor targetAnchor = null; private IAnchorListener targetAnchorListener = null; public void activate(EditDomain domain, IViewer viewer) { super.activate(domain, viewer); feedbackService = (IFeedbackService) viewer .getService(IFeedbackService.class); Layer layer = ((IGraphicalViewer) viewer) .getLayer(GEF.LAYER_PRESENTATION); if (layer != null) { createConnectionFigure(layer); } animationService = (IAnimationService) viewer .getService(IAnimationService.class); if (animationService != null) { animationService.stop(); } } public void deactivate(EditDomain domain, IViewer viewer) { if (connectionFigure != null) { if (connectionFigure.getParent() != null) connectionFigure.getParent().remove(connectionFigure); connectionFigure = null; } if (feedbackService != null) { if (parent != null && parent.getStatus().isActive()) { feedbackService.removeSelection(parent.getTopicPart() .getFigure()); } feedbackService = null; } if (animationService != null) { animationService.stop(); animationService = null; } if (insertion != null) { insertion.pullOut(); insertion = null; } setSourceAnchor(null); if (targetAnchor != null) { if (targetAnchorListener != null) { targetAnchor.removeAnchorListener(targetAnchorListener); } targetAnchor.setOwner(null); targetAnchor = null; } connection = null; parent = null; super.deactivate(domain, viewer); } // public Request getAdaptedRequest(IBranchPart targetParent, // ParentSearchKey key, Request sourceRequest) { // return sourceRequest; // } public void update(IBranchPart targetParent, ParentSearchKey key) { IBranchPart oldParent = this.parent; this.parent = targetParent; if (feedbackService != null && oldParent != null && oldParent.getStatus().isActive()) { feedbackService.removeSelection(oldParent.getTopicPart() .getFigure()); } IFigure parentTopicFigure = targetParent == null ? null : targetParent .getTopicPart().getFigure(); cursorOverParent = parentTopicFigure != null && parentTopicFigure.containsPoint(key.getCursorPos()); setSourceAnchor(targetParent == null ? null : targetParent .getConnections().getSourceAnchor()); if (connectionFigure != null) { if (parentTopicFigure != null) { Rectangle bounds = parentTopicFigure.getBounds().getUnion( key.getFigure().getBounds()).expand(10, 10); connectionFigure.setBounds(bounds); connectionFigure.setVisible(targetParent != null); } else { connectionFigure.setVisible(false); } if (targetParent != null) { updateConnection(targetParent, key.getFeedback()); } } if (feedbackService != null && parentTopicFigure != null) { SelectionFigure selectionFigure = feedbackService .addSelection(parentTopicFigure); selectionFigure.setPreselectionColor(ColorUtils .getColor(COLOR_WARNING)); selectionFigure.setPreselectionFillColor(ColorUtils .getColor(COLOR_WARNING)); selectionFigure.setPreselectionFillAlpha(0x10); selectionFigure.setPreselected(true); } IInsertion oldInsertion = this.insertion; IInsertion newInsertion = calcInsertion(parent, key); if (oldInsertion != newInsertion && (newInsertion == null || !newInsertion.equals(oldInsertion))) { this.insertion = newInsertion; animInsertion(oldInsertion, newInsertion); } } private void setSourceAnchor(IAnchor anchor) { if (anchor == sourceAnchor) return; if (sourceAnchor != null && sourceAnchorListener != null) { sourceAnchor.removeAnchorListener(sourceAnchorListener); } sourceAnchor = anchor; if (anchor != null) { if (sourceAnchorListener == null) { sourceAnchorListener = new IAnchorListener() { public void anchorMoved(IAnchor anchor) { if (connection != null && connectionFigure != null) { connection.reroute(connectionFigure); } } }; } anchor.addAnchorListener(sourceAnchorListener); } } private void updateConnection(IBranchPart parent, IBranchPart feedback) { IBranchConnections connections = parent.getConnections(); String connectionId = connections.getId(); if (!isSameDecoration(connection, connectionId)) { connection = createBranchConnection(parent, connectionId); } if (connection != null) { connection.setId(connectionId); connection.setSourceAnchor(connectionFigure, sourceAnchor); if (targetAnchor == null) { targetAnchor = new DummyAnchor(); if (targetAnchorListener == null) { targetAnchorListener = new IAnchorListener() { public void anchorMoved(IAnchor anchor) { if (connection != null && connectionFigure != null) { connection.reroute(connectionFigure); } } }; } targetAnchor.addAnchorListener(targetAnchorListener); } targetAnchor.setOwner(feedback.getTopicPart().getFigure()); connection.setTargetAnchor(connectionFigure, targetAnchor); connection.setLineStyle(connectionFigure, connections .getLineStyle()); connection.setLineWidth(connectionFigure, Math.max( LINE_WIDTH_DUMMY, connections.getLineWidth())); connection.setSourceOrientation(connectionFigure, connections .getSourceOrientation()); connection.setSourceExpansion(connectionFigure, connections .getSourceExpansion()); int targetOrientation = PositionConstants.NONE; IStructure structure = parent.getBranchPolicy() .getStructure(parent); if (structure instanceof IBranchStructureExtension) { targetOrientation = ((IBranchStructureExtension) structure) .getChildTargetOrientation(parent, feedback); } connection .setTargetOrientation(connectionFigure, targetOrientation); connection.setTargetExpansion(connectionFigure, 0); connection.setLineColor(connectionFigure, ColorUtils .getColor(COLOR_WARNING)); if (connectionFigure.getParent() instanceof IUseTransparency) { connection.setAlpha(connectionFigure, ((IUseTransparency) connectionFigure.getParent()) .getMainAlpha()); } if (connection instanceof ICorneredDecoration) { ((ICorneredDecoration) connection).setCornerSize( connectionFigure, connections.getCornerSize()); } connection.setVisible(connectionFigure, !cursorOverParent && connectionFigure.isVisible() && connection.getSourceAnchor() != null && connection.getTargetAnchor() != null); connection.reroute(connectionFigure); } } public boolean isShowConnection() { return showConnection; } public void setShowConnection(boolean showConnection) { this.showConnection = showConnection; } protected void createConnectionFigure(IFigure layer) { if (layer != null && showConnection) { connectionFigure = new DummyConnectionFigure(); layer.add(connectionFigure); } } private IInsertion calcInsertion(IBranchPart parent, ParentSearchKey key) { UpdateManager um = key.getFigure().getUpdateManager(); if (um != null) um.performValidation(); if (parent != null) { IStructure structure = parent.getBranchPolicy() .getStructure(parent); if (structure instanceof IInsertableBranchStructureExtension) return ((IInsertableBranchStructureExtension) structure) .calcInsertion(parent, key); } return null; } private void animInsertion(final IInsertion oldInsertion, final IInsertion newInsertion) { Runnable job = new Runnable() { public void run() { if (oldInsertion != null) { oldInsertion.pullOut(); } if (newInsertion != null) { newInsertion.pushIn(); } } }; if (MindMapUI.isAnimationEnabled() && animationService != null && animationService.isActive()) { animationService.start(job, null, null); } else { job.run(); } } }