/* ****************************************************************************** * 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.IAnchor; import org.xmind.gef.draw2d.IReferencedFigure; import org.xmind.gef.draw2d.geometry.HorizontalFlipper; import org.xmind.gef.draw2d.geometry.ITransformer; 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.internal.mindmap.TopicPart; 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 LeftRightStructure extends AbstractBranchStructure { private boolean leftwards; private ITransformer t = new HorizontalFlipper(); protected LeftRightStructure(boolean leftwards) { this.leftwards = leftwards; this.t.setEnabled(leftwards); } public boolean isLeftwards() { return leftwards; } protected void doFillPlusMinus(IBranchPart branch, IPlusMinusPart plusMinus, LayoutInfo info) { Point ref = info.getReference(); t.setOrigin(ref); int y = ref.y; // IFigure tf = branch.getTopicPart().getFigure(); // ITopicDecoration shape = ((TopicFigure) tf).getDecoration(); // if (Styles.TOPIC_SHAPE_UNDERLINE.equals(shape.getId())) // y += tf.getPreferredSize().height / 2; Rectangle topicBounds = info.getCheckedClientArea(); topicBounds = t.tr(topicBounds); int x = topicBounds.right(); IFigure pmFigure = plusMinus.getFigure(); Dimension size = pmFigure.getPreferredSize(); Rectangle r = new Rectangle(x, y - size.height / 2, size.width, size.height); info.put(pmFigure, t.r(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 x = refBounds.right() + majorSpacing; int num = subBranches.size(); int anchorHeight = 0; TopicPart topicPart = (TopicPart) branch.getTopicPart(); if (topicPart != null) { IAnchor anchor = topicPart.getSourceAnchor(null); anchorHeight = (int) anchor .getLocation(leftwards ? PositionConstants.EAST : PositionConstants.WEST, 0) .getDifference(anchor.getReferencePoint()).height; } // int totalHeight = calcTotalChildrenHeight(branch, minorSpacing, true); // int top = totalHeight / 2; // int y = ref.y - top; int distanceTop = calcDistanceTop(branch, minorSpacing, true); int y = ref.y + (int) anchorHeight - distanceTop; 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)); y += r.height + minorSpacing; } IBranchPart subBranch = subBranches.get(i); IFigure subBranchFigure = subBranch.getFigure(); Insets ins = helper.getInsets(subBranch); ins = t.ti(ins); Dimension size = subBranchFigure.getPreferredSize(); Rectangle r = new Rectangle(x + ins.left, y + ins.top, size.width, size.height); info.put(subBranchFigure, t.rr(r)); y += size.height + ins.getHeight() + 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 IPart calcNavigation(IBranchPart branch, String navReqType) { if (!branch.getSubBranches().isEmpty()) { if (isLeftwards()) { if (GEF.REQ_NAV_LEFT.equals(navReqType)) { return getSubTopicPart(branch, 0); } } else { if (GEF.REQ_NAV_RIGHT.equals(navReqType)) { return getSubTopicPart(branch, 0); } } } return super.calcNavigation(branch, navReqType); } public IPart calcChildNavigation(IBranchPart branch, IBranchPart sourceChild, String navReqType, boolean sequential) { if (GEF.REQ_NAV_UP.equals(navReqType)) { return getSubTopicPart(branch, sourceChild.getBranchIndex() - 1); } else if (GEF.REQ_NAV_DOWN.equals(navReqType)) { return getSubTopicPart(branch, sourceChild.getBranchIndex() + 1); } else if (!sequential) { if (isLeftwards()) { if (GEF.REQ_NAV_RIGHT.equals(navReqType)) { return branch.getTopicPart(); } } else { if (GEF.REQ_NAV_LEFT.equals(navReqType)) { return branch.getTopicPart(); } } } return super.calcChildNavigation(branch, sourceChild, navReqType, sequential); } public int getSourceOrientation(IBranchPart branch) { if (isLeftwards()) return PositionConstants.WEST; return PositionConstants.EAST; } public int getChildTargetOrientation(IBranchPart branch, IBranchPart subBranch) { return calcChildTargetOrientation(); } private int calcChildTargetOrientation() { if (isLeftwards()) return PositionConstants.EAST; return PositionConstants.WEST; } 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 dx = childRef.x - topicBounds.right(); if (dx > 0) { if (childRef.y >= branchBounds.y && childRef.y < branchBounds.bottom() && dx < MindMapUI.SEARCH_RANGE) { return dx; } int dy = childRef.y - ref.y; int d = dy * dy + dx * dx; 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(key.getFigure()); int insHeight = insSize.height; int minorSpacing = getMinorSpacing(branch); int totalChildrenHeight = calcTotalChildrenHeight(branch, minorSpacing, false); int totalHeight = totalChildrenHeight + insHeight + minorSpacing; int startY = ref.y - totalHeight / 2; return calcInsIndex(branch, startY, childRef, insHeight, minorSpacing, withDisabled); } private int calcInsIndex(IBranchPart branch, int startY, Point childRef, int childHeight, int spacing, 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 h = getBorderedSize(branch, subBranch).height;//subFigure.getPreferredSize().height; int hint = startY + sum + (childHeight + h + spacing) / 2; if (childRef.y < hint) { return ret; } sum += h + spacing; if (withDisabled || subFigure.isEnabled()) ret++; } return withDisabled ? num : -1; } private Dimension calcInsSize(IReferencedFigure child) { return child.getSize().scale(0.8); } private int calcDistanceTop(IBranchPart branch, int minorSpacing, boolean withInsertion) { int totalAnchorHeight = 0; int firstDistanceTop = 0; List<IBranchPart> subBranches = branch.getSubBranches(); int num = subBranches.size(); for (int i = 0; i < num; i++) { IBranchPart subBranch = subBranches.get(i); int h = getBorderedSize(branch, subBranch).height; TopicPart topicPart = (TopicPart) subBranch.getTopicPart(); int anchorDistanceTop = 0; if (topicPart != null) { IAnchor anchor = topicPart.getTargetAnchor(null); anchorDistanceTop = (int) anchor.getLocation(leftwards ? PositionConstants.EAST : PositionConstants.WEST, 0).y - subBranch.getFigure().getBounds().y; } if (i == 0) { firstDistanceTop = anchorDistanceTop; totalAnchorHeight += num == 1 ? 0 : h - anchorDistanceTop; continue; } totalAnchorHeight += minorSpacing; if (i == num - 1) { totalAnchorHeight += anchorDistanceTop; break; } totalAnchorHeight += h; } if (withInsertion) { IInsertion ins = getCurrentInsertion(branch); if (ins != null) { Dimension insSize = ins.getSize(); if (insSize != null) { totalAnchorHeight += minorSpacing + insSize.height; } } } return totalAnchorHeight / 2 + firstDistanceTop; } private int calcTotalChildrenHeight(IBranchPart branch, int minorSpacing, boolean withInsertion) { int totalHeight = 0; Iterator<IBranchPart> it = branch.getSubBranches().iterator(); while (it.hasNext()) { IBranchPart subBranch = it.next(); int h = getBorderedSize(branch, subBranch).height; // System.out.println(h); totalHeight += h;//subBranch.getFigure().getPreferredSize().height; if (it.hasNext()) { totalHeight += minorSpacing; } } if (withInsertion) { IInsertion ins = getCurrentInsertion(branch); if (ins != null) { Dimension insSize = ins.getSize(); if (insSize != null) { totalHeight += minorSpacing + insSize.height; } } } return totalHeight; } public IInsertion calcInsertion(IBranchPart branch, ParentSearchKey key) { int newIndex = calcInsIndex(branch, key, true); Dimension newSize = calcInsSize(key.getFigure()); return new Insertion(branch, newIndex, newSize); } public int getSummaryDirection(IBranchPart branch, ISummaryPart summary) { if (leftwards) return PositionConstants.WEST; return PositionConstants.EAST; } public int getRangeGrowthDirection(IBranchPart branch, IBranchRangePart range) { return PositionConstants.SOUTH; } public int getQuickMoveOffset(IBranchPart branch, IBranchPart child, int direction) { if (direction == PositionConstants.SOUTH) return 1; if (direction == PositionConstants.NORTH) return -1; return super.getQuickMoveOffset(branch, child, direction); } }