/* ****************************************************************************** * 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.DecoratedShapeFigure; 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.decoration.IDecoration; import org.xmind.gef.draw2d.decoration.IShapeDecoration; 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 && !specialConnection) { 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; private boolean specialConnection = false; 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) { update(targetParent, true, key, -1); } private void updateCalloutConnection(IBranchPart parent, int index, IBranchPart feedback) { IDecoration originConnection = parent.getCalloutConnections() .getDecoration(index); if (!(originConnection instanceof IBranchConnectionDecoration)) return; IBranchConnectionDecoration branchConnectionDecoration = (IBranchConnectionDecoration) originConnection; String connectionId = originConnection.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, branchConnectionDecoration.getLineStyle()); connection.setLineWidth(connectionFigure, branchConnectionDecoration.getLineWidth()); connection.setLineColor(connectionFigure, ColorUtils.getColor(COLOR_WARNING)); connection.setSourceOrientation(connectionFigure, PositionConstants.CENTER); connection.setSourceExpansion(connectionFigure, branchConnectionDecoration.getSourceExpansion()); connection.setTargetOrientation(connectionFigure, PositionConstants.NONE); connection.setTargetExpansion(connectionFigure, 0); if (connection instanceof IShapeDecoration) { ((IShapeDecoration) connection).setFillColor(connectionFigure, ColorUtils.getColor(COLOR_WARNING)); } if (connectionFigure.getParent() instanceof IUseTransparency) { connection.setAlpha(connectionFigure, ((IUseTransparency) connectionFigure.getParent()) .getMainAlpha()); } if (connection instanceof ICorneredDecoration && (branchConnectionDecoration instanceof ICorneredDecoration)) { ((ICorneredDecoration) connection).setCornerSize( connectionFigure, ((ICorneredDecoration) branchConnectionDecoration) .getCornerSize()); } connection.setVisible(connectionFigure, !cursorOverParent && connectionFigure.isVisible() && connection.getSourceAnchor() != null && connection.getTargetAnchor() != null); connection.reroute(connectionFigure); } } 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, ParentSearchKey key) { IBranchPart feedback = key.getFeedback(); 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); } IFigure fig = key.getInvent(); if (fig == null) fig = key.getFigure(); IShapeDecoration shape = ((DecoratedShapeFigure) fig) .getDecoration(); shape.setFillColor(fig, ColorUtils.getColor(COLOR_WARNING)); targetAnchor.setOwner(fig); 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(); } } public void update(IBranchPart targetParent, boolean moved, ParentSearchKey key, int specialIndex) { 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()); specialConnection = specialIndex > -1; if (specialIndex > -1) { setSourceAnchor(targetParent == null ? null : ((IBranchConnectionDecoration) targetParent .getCalloutConnections() .getDecoration(specialIndex)).getSourceAnchor()); } else { setSourceAnchor(targetParent == null ? null : targetParent .getConnections().getSourceAnchor()); } if (connectionFigure != null) { if (parentTopicFigure != null) { Rectangle bounds; if (specialIndex <= -1 && key.getInvent() != null) bounds = parentTopicFigure.getBounds() .getUnion(key.getInvent().getBounds()) .expand(10, 10); else bounds = parentTopicFigure.getBounds() .getUnion(key.getFigure().getBounds()) .expand(10, 10); connectionFigure.setBounds(bounds); connectionFigure.setVisible(targetParent != null); } else { connectionFigure.setVisible(false); } if (targetParent != null) { if (specialIndex > -1) { updateCalloutConnection(targetParent, specialIndex, key.getFeedback()); } else { updateConnection(targetParent, key); } } } 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); } if (moved) { IInsertion oldInsertion = this.insertion; IInsertion newInsertion = calcInsertion(parent, key); if (oldInsertion != newInsertion && (newInsertion == null || !newInsertion .equals(oldInsertion))) { this.insertion = newInsertion; animInsertion(oldInsertion, newInsertion); } } else { IInsertion oldiIInsertion = this.insertion; this.insertion = null; animInsertion(oldiIInsertion, null); } } }