/* ****************************************************************************** * 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 java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.core.runtime.Assert; import org.eclipse.draw2d.PositionConstants; import org.eclipse.draw2d.geometry.Insets; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; import org.xmind.gef.Request; import org.xmind.gef.draw2d.geometry.Geometry; import org.xmind.gef.graphicalpolicy.IStructure; import org.xmind.gef.part.IGraphicalEditPart; import org.xmind.gef.service.IBendPointsFeedback; import org.xmind.gef.service.IFeedback; import org.xmind.gef.tool.ISourceTool; import org.xmind.ui.branch.IBranchStructureExtension; import org.xmind.ui.mindmap.IBranchPart; import org.xmind.ui.mindmap.IBranchRangePart; import org.xmind.ui.mindmap.ITopicPart; import org.xmind.ui.mindmap.MindMapUI; public class RangeResizeTool extends FeedbackResizeTool implements ISourceTool { private Set<IBranchPart> newRange; private IBranchPart parentBranch; private int minLength; private int maxLength; private IBranchRangePart source; public void setSource(IGraphicalEditPart source) { Assert.isTrue(source instanceof IBranchRangePart); this.source = (IBranchRangePart) source; parentBranch = this.source.getOwnedBranch(); newRange = new HashSet<IBranchPart>(this.source.getEnclosingBranches()); } public IGraphicalEditPart getSource() { return (IGraphicalEditPart) source; } public IBranchRangePart getRangeSourcePart() { return source; } protected Rectangle getSourceArea() { return getSource().getFigure().getBounds(); } protected IFeedback getSourceFeedback() { return (IFeedback) getSource().getAdapter(IFeedback.class); } protected void initFeedback(IBendPointsFeedback feedback) { super.initFeedback(feedback); minLength = calcMinLength(getOrientation()); maxLength = calcMaxLength(getOrientation()); updateRange(getResultArea()); } protected int calcMaxLength(int orientation) { Rectangle parentBounds = parentBranch.getFigure().getBounds(); Insets insets = getRangeSourcePart().getFigure().getInsets(); if (orientation == PositionConstants.SOUTH) { return parentBounds.bottom() - getInitArea().y + insets.bottom; } else if (orientation == PositionConstants.NORTH) { return getInitArea().bottom() - parentBounds.y + insets.top; } else if (orientation == PositionConstants.WEST) { return getInitArea().right() - parentBounds.x + insets.left; } else { return parentBounds.right() - getInitArea().x + insets.right; } } protected int calcMinLength(int orientation) { int length = 3; IBranchPart last = calcLastBranch(orientation); if (last != null) { ITopicPart topicPart = last.getTopicPart(); if (topicPart != null) { if (orientation == PositionConstants.SOUTH || orientation == PositionConstants.NORTH) { length += topicPart.getFigure().getBounds().height; } else { length += topicPart.getFigure().getBounds().width; } } } if (orientation == PositionConstants.SOUTH) { length += getRangeSourcePart().getFigure().getInsets().top; } else if (orientation == PositionConstants.NORTH) { length += getRangeSourcePart().getFigure().getInsets().bottom; } else if (orientation == PositionConstants.WEST) { length += getRangeSourcePart().getFigure().getInsets().right; } else { length += getRangeSourcePart().getFigure().getInsets().left; } return length; } private IBranchPart calcLastBranch(int orientation) { List<IBranchPart> enclosingBranches = getRangeSourcePart() .getEnclosingBranches(); if (enclosingBranches.isEmpty()) return null; IStructure structure = parentBranch.getBranchPolicy().getStructure( parentBranch); if (structure instanceof IBranchStructureExtension) { int direction = ((IBranchStructureExtension) structure) .getRangeGrowthDirection(parentBranch, getRangeSourcePart()); if (direction == orientation) return first(enclosingBranches); if (direction == Geometry.getOppositePosition(orientation)) return last(enclosingBranches); } return null; } private IBranchPart first(List<IBranchPart> branches) { return branches.get(0); } private IBranchPart last(List<IBranchPart> branches) { return branches.get(branches.size() - 1); } protected void updateAreaBounds(Rectangle area, Point cursorPosition) { super.updateAreaBounds(area, cursorPosition); Rectangle resultArea = getResultArea(); updateRange(resultArea); addMissingBranches(); } private void updateRange(Rectangle area) { for (IBranchPart branch : parentBranch.getSubBranches()) { ITopicPart topicPart = branch.getTopicPart(); if (topicPart != null) { Point pt = topicPart.getFigure().getBounds().getCenter(); if (area.contains(pt)) { newRange.add(branch); topicPart.getStatus().preSelect(); } else { newRange.remove(branch); topicPart.getStatus().dePreSelect(); } } } } private void addMissingBranches() { List<IBranchPart> subBranches = parentBranch.getSubBranches(); List<Integer> optedBranches = null; for (int i = 0; i < subBranches.size(); i++) { IBranchPart subBranch = subBranches.get(i); ITopicPart topicPart = subBranch.getTopicPart(); if (topicPart != null) { boolean preSelected = topicPart.getStatus().isPreSelected(); if (preSelected) { if (optedBranches == null) optedBranches = new ArrayList<Integer>(); optedBranches.add(i); } } } for (int j = optedBranches.get(0); j <= optedBranches.get(optedBranches .size() - 1); j++) { ITopicPart topicPart = subBranches.get(j).getTopicPart(); if (topicPart != null) { boolean preSelected = topicPart.getStatus().isPreSelected(); if (!preSelected) topicPart.getStatus().preSelect(); } } } protected void removeFeedback(IBendPointsFeedback feedback) { super.removeFeedback(feedback); clearRange(); } public void finish() { ArrayList<Object> range = new ArrayList<Object>(newRange); super.finish(); sendRequest(range); } private void sendRequest(List<Object> newRange) { IBranchRangePart rangeSource = getRangeSourcePart(); Request request = new Request(MindMapUI.REQ_MODIFY_RANGE); request.setViewer(getTargetViewer()); request.setPrimaryTarget(rangeSource); request.setParameter(MindMapUI.PARAM_RANGE, newRange.toArray()); getDomain().handleRequest(request); } private void clearRange() { for (IBranchPart branch : parentBranch.getSubBranches()) { ITopicPart topicPart = branch.getTopicPart(); if (topicPart != null) { topicPart.getStatus().dePreSelect(); } } newRange = null; } protected int constrainWidth(int w) { if (getOrientation() == PositionConstants.EAST || getOrientation() == PositionConstants.WEST) { return Math.max(Math.min(w, maxLength), minLength); } return super.constrainWidth(w); } protected int constrainHeight(int h) { if (getOrientation() == PositionConstants.NORTH || getOrientation() == PositionConstants.SOUTH) { return Math.max(Math.min(h, maxLength), minLength); } return super.constrainHeight(h); } }