/* ****************************************************************************** * 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.branch; import java.util.Iterator; import java.util.List; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.PositionConstants; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Insets; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; import org.xmind.gef.GEF; import org.xmind.gef.draw2d.IReferencedFigure; import org.xmind.gef.draw2d.geometry.ITransformer; import org.xmind.gef.draw2d.geometry.VerticalFlipper; import org.xmind.gef.part.IPart; import org.xmind.ui.branch.AbstractBranchStructure; import org.xmind.ui.branch.BoundaryLayoutHelper; import org.xmind.ui.branch.IInsertion; import org.xmind.ui.branch.Insertion; import org.xmind.ui.mindmap.IBoundaryPart; import org.xmind.ui.mindmap.IBranchPart; import org.xmind.ui.mindmap.IBranchRangePart; import org.xmind.ui.mindmap.IPlusMinusPart; import org.xmind.ui.mindmap.ISummaryPart; import org.xmind.ui.mindmap.ITopicPart; import org.xmind.ui.mindmap.MindMapUI; import org.xmind.ui.tools.ParentSearchKey; public class UpDownStructure extends AbstractBranchStructure { private boolean upwards; private ITransformer t = new VerticalFlipper(); public UpDownStructure(boolean upwards) { this.upwards = upwards; this.t.setEnabled(upwards); } public boolean isUpwards() { return upwards; } protected void doFillPlusMinus(IBranchPart branch, IPlusMinusPart plusMinus, LayoutInfo info) { Point ref = info.getReference(); t.setOrigin(ref); int x = ref.x; Rectangle topicBounds = info.getCheckedClientArea(); topicBounds = t.tr(topicBounds); int y = topicBounds.bottom(); IFigure pmFigure = plusMinus.getFigure(); Dimension size = pmFigure.getPreferredSize(); Rectangle r = new Rectangle(x - size.width / 2, y, size.width, size.height); info.put(pmFigure, t.rr(r)); } protected void doFillSubBranches(IBranchPart branch, List<IBranchPart> subBranches, LayoutInfo info) { int majorSpacing = getMajorSpacing(branch); int minorSpacing = getMinorSpacing(branch); Point ref = info.getReference(); t.setOrigin(ref); Rectangle refBounds = info.getCheckedClientArea(); refBounds = t.tr(refBounds); int y = refBounds.bottom() + majorSpacing; int num = subBranches.size(); int totalWidth = calcTotalChildrenWidth(branch, minorSpacing, true); int left = totalWidth / 2; int x = ref.x - left; IInsertion insertion = getCurrentInsertion(branch); BoundaryLayoutHelper helper = getBoundaryLayoutHelper(branch); for (int i = 0; i < num; i++) { if (insertion != null && i == insertion.getIndex()) { Rectangle r = insertion.createRectangle(x, y); info.add(t.rr(r)); x += r.width + minorSpacing; } IBranchPart subBranchPart = subBranches.get(i); IFigure subBranchFigure = subBranchPart.getFigure(); Insets ins = helper.getInsets(subBranchPart); Dimension size = subBranchFigure.getPreferredSize(); Rectangle r = new Rectangle(x + ins.left, y + ins.top, size.width, size.height); info.put(subBranchFigure, t.rr(r)); x += size.width + ins.getWidth() + minorSpacing; } if (insertion != null && num == insertion.getIndex()) { Dimension insSize = insertion.getSize(); if (insSize != null) { Rectangle r = new Rectangle(x, y, insSize.width, insSize.height); info.add(t.rr(r)); } } } // public Object calcNavigation(IBranchPart branch, int direction) { // switch (direction) { // case PositionConstants.WEST: // return NAVI_PREV; // case PositionConstants.EAST: // return NAVI_NEXT; // case PositionConstants.NORTH: // return isUpwards() ? NAVI_CHILD : NAVI_PARENT; // case PositionConstants.SOUTH: // return isUpwards() ? NAVI_PARENT : NAVI_CHILD; // } // return NAVI_SELF; // } public IPart calcChildNavigation(IBranchPart branch, IBranchPart sourceChild, String navReqType, boolean sequential) { if (GEF.REQ_NAV_LEFT.equals(navReqType)) { return getSubTopicPart(branch, sourceChild.getBranchIndex() - 1); } else if (GEF.REQ_NAV_RIGHT.equals(navReqType)) { return getSubTopicPart(branch, sourceChild.getBranchIndex() + 1); } else if (!sequential) { if (isUpwards()) { if (GEF.REQ_NAV_DOWN.equals(navReqType)) { return branch.getTopicPart(); } } else { if (GEF.REQ_NAV_UP.equals(navReqType)) { return branch.getTopicPart(); } } } return super.calcChildNavigation(branch, sourceChild, navReqType, sequential); } public IPart calcNavigation(IBranchPart branch, String navReqType) { if (!branch.getSubBranches().isEmpty()) { if (isUpwards()) { if (GEF.REQ_NAV_UP.equals(navReqType)) { return getSubTopicPart(branch, 0); } } else { if (GEF.REQ_NAV_DOWN.equals(navReqType)) { return getSubTopicPart(branch, 0); } } } return super.calcNavigation(branch, navReqType); } public int getSourceOrientation(IBranchPart branch) { if (isUpwards()) return PositionConstants.NORTH; return PositionConstants.SOUTH; } public int getChildTargetOrientation(IBranchPart branch, IBranchPart subBranch) { return calcChildTargetOrientation(); } // public int calcChildTargetOrientation(IBranchPart branch, // IReferencedFigure childFigure) { // return calcChildTargetOrientation(); // } private int calcChildTargetOrientation() { if (isUpwards()) return PositionConstants.SOUTH; return PositionConstants.NORTH; } public int calcChildDistance(IBranchPart branch, ParentSearchKey key) { IFigure branchFigure = branch.getFigure(); IReferencedFigure topicFigure = (IReferencedFigure) branch .getTopicPart().getFigure(); Point ref = topicFigure.getReference(); t.setOrigin(ref); Point childRef = t.tp(getChildRef(branch, ref, key)); Rectangle branchBounds = t.tr(branchFigure.getBounds()); Rectangle topicBounds = t.tr(topicFigure.getBounds()); int dy = childRef.y - topicBounds.bottom(); if (dy > 0) { if (childRef.x >= branchBounds.x && childRef.x < branchBounds.right() && dy < MindMapUI.SEARCH_RANGE) { return dy; } int dx = childRef.x - ref.x; int d = dx * dx + dy * dy; return d; } return super.calcChildDistance(branch, key); } protected int calcInsIndex(IBranchPart branch, ParentSearchKey key, boolean withDisabled) { if (branch.getSubBranches().isEmpty() || branch.isFolded()) return withDisabled ? 0 : -1; ITopicPart topic = branch.getTopicPart(); if (topic == null) return withDisabled ? 0 : -1; IFigure topicFigure = topic.getFigure(); Point ref = ((IReferencedFigure) topicFigure).getReference(); t.setOrigin(ref); Point childRef = t.tp(getChildRef(branch, ref, key)); Dimension insSize = calcInsSize(branch, key); int insWidth = insSize.width; int minorSpacing = getMinorSpacing(branch); int totalChildrenWidth = calcTotalChildrenWidth(branch, minorSpacing, false); int totalWidth = totalChildrenWidth + insWidth + minorSpacing; int x = ref.x - totalWidth / 2; return calcInsIndex(branch, x, childRef, minorSpacing, insWidth, withDisabled); } private int calcInsIndex(IBranchPart branch, int x, Point childRef, int spacing, int childWidth, boolean withDisabled) { int ret = 0; int sum = 0; List<IBranchPart> subBranches = branch.getSubBranches(); int num = subBranches.size(); for (IBranchPart subBranch : subBranches) { IFigure subFigure = subBranch.getFigure(); int w = subFigure.getPreferredSize().width; int hint = x + sum + (childWidth + w + spacing) / 2; if (childRef.x < hint) { return ret; } sum += w + spacing; if (withDisabled || subFigure.isEnabled()) ret++; } return withDisabled ? num : -1; } private Dimension calcInsSize(IBranchPart branch, ParentSearchKey key) { return key.getFigure().getSize().scale(0.8); } private int calcTotalChildrenWidth(IBranchPart branch, int minorSpacing, boolean withInsertion) { int totalWidth = 0; Iterator<IBranchPart> it = branch.getSubBranches().iterator(); while (it.hasNext()) { IBranchPart subBranch = it.next(); totalWidth += subBranch.getFigure().getPreferredSize().width; if (it.hasNext()) { totalWidth += minorSpacing; } } if (withInsertion) { IInsertion ins = getCurrentInsertion(branch); if (ins != null) { Dimension insSize = ins.getSize(); if (insSize != null) { totalWidth += minorSpacing + insSize.width; } } } return totalWidth; } public IInsertion calcInsertion(IBranchPart branch, ParentSearchKey key) { return new Insertion(branch, calcInsIndex(branch, key, true), calcInsSize(branch, key)); } public int getSummaryDirection(IBranchPart branch, ISummaryPart summary) { return upwards ? PositionConstants.NORTH : PositionConstants.SOUTH; } public int getRangeGrowthDirection(IBranchPart branch, IBranchRangePart range) { return PositionConstants.EAST; } public int getQuickMoveOffset(IBranchPart branch, IBranchPart child, int direction) { if (direction == PositionConstants.EAST) return 1; if (direction == PositionConstants.WEST) return -1; return super.getQuickMoveOffset(branch, child, direction); } protected Point calcInsertPosition(IBranchPart branch, IBranchPart child, ParentSearchKey key) { List<IBranchPart> subBranches = branch.getSubBranches(); if (subBranches.isEmpty()) return calcFirstChildPosition(branch, key); int minorSpacing = getMinorSpacing(branch); int index = calcInsIndex(branch, key, true); Dimension insSize = key.getFigure().getSize(); Dimension inventSize = key.getInvent().getSize(); List<IBoundaryPart> boundaries = branch.getBoundaries(); if (index == 0) { IBranchPart sub = subBranches.get(0); Rectangle bounds = sub.getFigure().getBounds(); if (!boundaries.isEmpty()) { for (IBoundaryPart boundary : boundaries) { Rectangle bBounds = boundary.getFigure().getBounds(); List<IBranchPart> enclosingBranches = boundary .getEnclosingBranches(); if ((!enclosingBranches.isEmpty()) && sub.equals(enclosingBranches.get(0))) bounds = bBounds.contains(bounds) ? bBounds : bounds; } } int x = bounds.x - minorSpacing - insSize.width / 2; int y; if (isUpwards()) y = bounds.bottom() - inventSize.width / 2; else y = bounds.y + inventSize.width / 2; return new Point(x, y); } if (index == subBranches.size()) { IBranchPart sub = subBranches.get(subBranches.size() - 1); Rectangle bounds = sub.getFigure().getBounds(); if (!boundaries.isEmpty()) { for (IBoundaryPart boundary : boundaries) { Rectangle bBounds = boundary.getFigure().getBounds(); List<IBranchPart> enclosingBranches = boundary .getEnclosingBranches(); if ((!enclosingBranches.isEmpty()) && sub.equals(enclosingBranches .get(enclosingBranches.size() - 1))) bounds = bBounds.contains(bounds) ? bBounds : bounds; } } int x = bounds.right() + minorSpacing + insSize.width / 2; int y; if (isUpwards()) y = bounds.bottom() - inventSize.width / 2; else y = bounds.y + inventSize.width / 2; return new Point(x, y); } return calcInventPosition(subBranches.get(index - 1), subBranches.get(index), key, isUpwards()); } protected Point calcMovePosition(IBranchPart branch, IBranchPart child, ParentSearchKey key) { List<IBranchPart> subBranches = branch.getSubBranches(); List<Integer> disables = getDisableBranches(branch); int index = calcInsIndex(branch, key, true); int oldIndex = getOldIndex(branch, child); if (disables != null) { if (disables.contains(index - 1)) { index--; oldIndex = index; } else if (disables.contains(index)) { oldIndex = index; } } Dimension inventSize = key.getInvent().getSize(); if (index == oldIndex) { IBranchPart sub = subBranches.get(index); int delta = sub.getTopicPart().getFigure().getSize().height / 2 - inventSize.height / 2; return getFigureLocation(sub.getFigure()).getTranslated(0, isUpwards() ? delta : -delta); } return calcInsertPosition(branch, child, key); } @Override protected Point calcFirstChildPosition(IBranchPart branch, ParentSearchKey key) { int y = branch.getFigure().getSize().height / 2 + getMajorSpacing(branch) + key.getInvent().getSize().height / 2; return getFigureLocation(branch.getFigure()).getTranslated(0, isUpwards() ? -y : y); } @Override protected Point calcInventPosition(IBranchPart orientation, IBranchPart assist, ParentSearchKey key, boolean isRightOrUp) { int minorSpacing = getMinorSpacing(orientation.getParentBranch()); Dimension insSize = key.getFigure().getSize(); Dimension inventSize = key.getInvent().getSize(); Rectangle oriBounds = orientation.getFigure().getBounds(); Rectangle assBounds = assist.getFigure().getBounds(); Rectangle lBounds = oriBounds; Rectangle rBounds = assBounds; List<IBoundaryPart> boundaries = orientation.getParentBranch() .getBoundaries(); if (!boundaries.isEmpty()) { for (IBoundaryPart boundary : boundaries) { List<IBranchPart> enclosingBranches = boundary .getEnclosingBranches(); Rectangle bBounds = boundary.getFigure().getBounds(); if ((!enclosingBranches.isEmpty()) && orientation.equals( enclosingBranches.get(enclosingBranches.size() - 1))) lBounds = bBounds.contains(lBounds) ? bBounds : lBounds; if ((!enclosingBranches.isEmpty()) && assist.equals(enclosingBranches.get(0))) rBounds = bBounds.contains(rBounds) ? bBounds : rBounds; } } boolean isBefourBounds; Rectangle bounds; if (lBounds.equals(oriBounds)) { bounds = lBounds; isBefourBounds = false; } else if (rBounds.equals(assBounds)) { bounds = rBounds; isBefourBounds = true; } else { if (isRightOrUp) { if (lBounds.bottom() < rBounds.bottom()) { bounds = lBounds; isBefourBounds = false; } else { bounds = rBounds; isBefourBounds = true; } } else { if (lBounds.y > rBounds.y) { bounds = lBounds; isBefourBounds = false; } else { bounds = rBounds; isBefourBounds = true; } } } int x; if (isBefourBounds) x = bounds.x - minorSpacing - insSize.width / 2; else x = bounds.right() + minorSpacing + insSize.width / 2; int y; if (isRightOrUp) y = bounds.bottom() - inventSize.height / 2; else y = bounds.y + inventSize.height / 2; return new Point(x, y); } }