001: /*******************************************************************************
002: * Copyright (c) 2005, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jface.viewers;
011:
012: import org.eclipse.core.runtime.Assert;
013:
014: /**
015: * A tree path denotes a model element in a tree viewer. Tree path objects have
016: * value semantics. A model element is represented by a path of elements in the
017: * tree from the root element to the leaf element.
018: * <p>
019: * Clients may instantiate this class. Not intended to be subclassed.
020: * </p>
021: *
022: * @since 3.2
023: */
024: public final class TreePath {
025:
026: /**
027: * Constant for representing an empty tree path.
028: */
029: public static final TreePath EMPTY = new TreePath(new Object[0]);
030:
031: private Object[] segments;
032:
033: private int hash;
034:
035: /**
036: * Constructs a path identifying a leaf node in a tree.
037: *
038: * @param segments
039: * path of elements to a leaf node in a tree, starting with the
040: * root element
041: */
042: public TreePath(Object[] segments) {
043: Assert.isNotNull(segments);
044: for (int i = 0; i < segments.length; i++) {
045: Assert.isNotNull(segments[i]);
046: }
047: this .segments = segments;
048: }
049:
050: /**
051: * Returns the element at the specified index in this path.
052: *
053: * @param index
054: * index of element to return
055: * @return element at the specified index
056: */
057: public Object getSegment(int index) {
058: return segments[index];
059: }
060:
061: /**
062: * Returns the number of elements in this path.
063: *
064: * @return the number of elements in this path
065: */
066: public int getSegmentCount() {
067: return segments.length;
068: }
069:
070: /**
071: * Returns the first element in this path, or <code>null</code> if this
072: * path has no segments.
073: *
074: * @return the first element in this path
075: */
076: public Object getFirstSegment() {
077: if (segments.length == 0) {
078: return null;
079: }
080: return segments[0];
081: }
082:
083: /**
084: * Returns the last element in this path, or <code>null</code> if this
085: * path has no segments.
086: *
087: * @return the last element in this path
088: */
089: public Object getLastSegment() {
090: if (segments.length == 0) {
091: return null;
092: }
093: return segments[segments.length - 1];
094: }
095:
096: /*
097: * (non-Javadoc)
098: *
099: * @see java.lang.Object#equals(java.lang.Object)
100: */
101: public boolean equals(Object other) {
102: if (!(other instanceof TreePath)) {
103: return false;
104: }
105: return equals((TreePath) other, null);
106: }
107:
108: /**
109: * (non-Javadoc)
110: *
111: * @see java.lang.Object#hashCode()
112: */
113: public int hashCode() {
114: if (hash == 0) {
115: hash = hashCode(null);
116: }
117: return hash;
118: }
119:
120: /**
121: * Returns a hash code computed from the hash codes of the segments, using
122: * the given comparer to compute the hash codes of the segments.
123: *
124: * @param comparer
125: * comparer to use or <code>null</code> if the segments' hash
126: * codes should be computed by calling their hashCode() methods.
127: * @return the computed hash code
128: */
129: public int hashCode(IElementComparer comparer) {
130: int result = 0;
131: for (int i = 0; i < segments.length; i++) {
132: if (comparer == null) {
133: result += segments[i].hashCode();
134: } else {
135: result += comparer.hashCode(segments[i]);
136: }
137: }
138: return result;
139: }
140:
141: /**
142: * Returns whether this path is equivalent to the given path using the
143: * specified comparer to compare individual elements.
144: *
145: * @param otherPath
146: * tree path to compare to
147: * @param comparer
148: * comparator to use or <code>null</code> if segments should be
149: * compared using equals()
150: * @return whether the paths are equal
151: */
152: public boolean equals(TreePath otherPath, IElementComparer comparer) {
153: if (otherPath == null) {
154: return false;
155: }
156: if (segments.length != otherPath.segments.length) {
157: return false;
158: }
159: for (int i = 0; i < segments.length; i++) {
160: if (comparer == null) {
161: if (!segments[i].equals(otherPath.segments[i])) {
162: return false;
163: }
164: } else {
165: if (!comparer
166: .equals(segments[i], otherPath.segments[i])) {
167: return false;
168: }
169: }
170: }
171: return true;
172: }
173:
174: /**
175: * Returns whether this path starts with the same segments as the given
176: * path, using the given comparer to compare segments.
177: *
178: * @param treePath
179: * path to compare to
180: * @param comparer
181: * the comparer to use, or <code>null</code> if equals() should
182: * be used to compare segments
183: * @return whether the given path is a prefix of this path, or the same as
184: * this path
185: */
186: public boolean startsWith(TreePath treePath,
187: IElementComparer comparer) {
188: int this SegmentCount = getSegmentCount();
189: int otherSegmentCount = treePath.getSegmentCount();
190: if (otherSegmentCount == this SegmentCount) {
191: return equals(treePath, comparer);
192: }
193: if (otherSegmentCount > this SegmentCount) {
194: return false;
195: }
196: for (int i = 0; i < otherSegmentCount; i++) {
197: Object otherSegment = treePath.getSegment(i);
198: if (comparer == null) {
199: if (!otherSegment.equals(segments[i])) {
200: return false;
201: }
202: } else {
203: if (!comparer.equals(otherSegment, segments[i])) {
204: return false;
205: }
206: }
207: }
208: return true;
209: }
210:
211: /**
212: * Returns a copy of this tree path with one segment removed from the end,
213: * or <code>null</code> if this tree path has no segments.
214: * @return a tree path
215: */
216: public TreePath getParentPath() {
217: int segmentCount = getSegmentCount();
218: if (segmentCount < 1) {
219: return null;
220: } else if (segmentCount == 1) {
221: return EMPTY;
222: }
223: Object[] parentSegments = new Object[segmentCount - 1];
224: System.arraycopy(segments, 0, parentSegments, 0,
225: segmentCount - 1);
226: return new TreePath(parentSegments);
227: }
228:
229: /**
230: * Returns a copy of this tree path with the given segment added at the end.
231: * @param newSegment
232: * @return a tree path
233: */
234: public TreePath createChildPath(Object newSegment) {
235: int segmentCount = getSegmentCount();
236: Object[] childSegments = new Object[segmentCount + 1];
237: if (segmentCount > 0) {
238: System.arraycopy(segments, 0, childSegments, 0,
239: segmentCount);
240: }
241: childSegments[segmentCount] = newSegment;
242: return new TreePath(childSegments);
243: }
244: }
|