/******************************************************************************* * Copyright (c) 2004, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.gef.examples.text; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.eclipse.jface.util.Assert; import org.eclipse.gef.EditPart; import org.eclipse.gef.tools.ToolUtilities; import org.eclipse.gef.examples.text.edit.TextEditPart; public class SelectionRange { public final TextLocation begin; public final TextLocation end; public final boolean isForward; public final boolean trailing; private List selectedParts; private List leafParts; /** * Constructs a selection range which starts and ends at the given location. The direction * of the range is forward. * @since 3.1 * @param location */ public SelectionRange(TextLocation location) { this(location, location, true); } /** * Constructs a selection range which starts and ends at the given locations. The * direction of the range is forward. * @since 3.1 * @param begin * @param end */ public SelectionRange(TextLocation begin, TextLocation end) { this(begin, end, true); } /** * Constructs a selection range which starts and ends at the given locations with the * given direction. If a range is forward, the caret will be placed at the end of the * range. Otherwise, it is placed at the beginning. * @since 3.1 * @param begin * @param end * @param forward */ public SelectionRange(TextLocation begin, TextLocation end, boolean forward) { this(begin, end, forward, true); } public SelectionRange(TextLocation begin, TextLocation end, boolean forward, boolean trailing) { Assert.isNotNull(begin); Assert.isNotNull(end); this.begin = begin; this.end = end; this.isForward = forward; this.trailing = trailing; } public SelectionRange(TextEditPart part, int offset) { this(new TextLocation(part, offset)); } public SelectionRange(TextEditPart begin, int bo, TextEditPart end, int eo) { this(new TextLocation(begin, bo), new TextLocation(end, eo)); } private void depthFirstTraversal(EditPart part, ArrayList result) { if (part.getChildren().isEmpty()) result.add(part); else for (int i = 0; i < part.getChildren().size(); i++) depthFirstTraversal((EditPart)part.getChildren().get(i), result); } public boolean equals(Object obj) { if (obj instanceof SelectionRange) { SelectionRange other = (SelectionRange)obj; return other.begin == begin && other.end == end && other.isForward == isForward; } return false; } private List findLeavesBetweenInclusive(EditPart left, EditPart right) { if (left == right) return Collections.singletonList(left); EditPart commonAncestor = ToolUtilities.findCommonAncestor(left, right); EditPart nextLeft = left.getParent(); List children; ArrayList result = new ArrayList(); if (nextLeft == commonAncestor) result.add(left); while (nextLeft != commonAncestor) { children = nextLeft.getChildren(); for (int i = children.indexOf(left); i < children.size(); i++) depthFirstTraversal((EditPart)children.get(i), result); left = nextLeft; nextLeft = nextLeft.getParent(); } ArrayList rightSide = new ArrayList(); EditPart nextRight = right.getParent(); if (nextRight == commonAncestor) rightSide.add(right); while (nextRight != commonAncestor) { children = nextRight.getChildren(); int end = children.indexOf(right); for (int i = 0; i <= end; i++) depthFirstTraversal((EditPart)children.get(i), rightSide); right = nextRight; nextRight = nextRight.getParent(); } children = commonAncestor.getChildren(); int start = children.indexOf(left) + 1; int end = children.indexOf(right); for (int i = start; i < end; i++) depthFirstTraversal((EditPart)children.get(i), result); result.addAll(rightSide); return result; } private List findNodesBetweenInclusive(EditPart left, EditPart right) { if (left == right) return Collections.singletonList(left); EditPart commonAncestor = ToolUtilities.findCommonAncestor(left, right); EditPart nextLeft = left.getParent(); List children; ArrayList result = new ArrayList(); //if (nextLeft == commonAncestor) result.add(left); while (nextLeft != commonAncestor) { children = nextLeft.getChildren(); for (int i = children.indexOf(left) + 1; i < children.size(); i++) result.add(children.get(i)); left = nextLeft; nextLeft = nextLeft.getParent(); } ArrayList rightSide = new ArrayList(); EditPart nextRight = right.getParent(); rightSide.add(right); while (nextRight != commonAncestor) { children = nextRight.getChildren(); int end = children.indexOf(right); for (int i = 0; i < end; i++) rightSide.add(children.get(i)); right = nextRight; nextRight = nextRight.getParent(); } children = commonAncestor.getChildren(); int start = children.indexOf(left) + 1; int end = children.indexOf(right); if (end > start) result.addAll(children.subList(start, end)); result.addAll(rightSide); return result; } public List getLeafParts() { if (leafParts == null) { List list = findLeavesBetweenInclusive(begin.part, end.part); leafParts = Collections.unmodifiableList(list); } return leafParts; } /** * @return the list of selected EditParts. There is no guarantee as to the order of * EditParts. */ public List getSelectedParts() { if (selectedParts == null) { List list = findNodesBetweenInclusive(begin.part, end.part); selectedParts = Collections.unmodifiableList(list); } return selectedParts; } public boolean isEmpty() { return begin.equals(end); } }