]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.browsing.ui/src/org/simantics/browsing/ui/NodeContextPath.java
6b5fcbf874fd9736699abdaa7bb3826f8bfca44d
[simantics/platform.git] / bundles / org.simantics.browsing.ui / src / org / simantics / browsing / ui / NodeContextPath.java
1 /*******************************************************************************\r
2  * Copyright (c) 2005, 2007 IBM Corporation and others.\r
3  * All rights reserved. This program and the accompanying materials\r
4  * are made available under the terms of the Eclipse Public License v1.0\r
5  * which accompanies this distribution, and is available at\r
6  * http://www.eclipse.org/legal/epl-v10.html\r
7  *\r
8  * Contributors:\r
9  *     IBM Corporation - initial API and implementation\r
10  *******************************************************************************/\r
11 package org.simantics.browsing.ui;\r
12 \r
13 import java.util.Arrays;\r
14 \r
15 import org.eclipse.core.runtime.Assert;\r
16 import org.eclipse.core.runtime.IAdaptable;\r
17 \r
18 /**\r
19  * A {@link GraphExplorer} tree {@link NodeContext} path denotes a model element\r
20  * in a tree viewer. Tree path objects have value semantics. A model element is\r
21  * represented by a path of elements in the tree from the root element to the\r
22  * leaf element.\r
23  * <p>\r
24  * Clients may instantiate this class. Not intended to be subclassed.\r
25  * </p>\r
26  * \r
27  * <p>\r
28  * Directly imitated for the Simantics browsing framework from JFace\r
29  * <code>org.eclipse.jface.viewer.TreePath</code> class.\r
30  * </p>\r
31  * \r
32  * @author Tuukka Lehtonen\r
33  */\r
34 public final class NodeContextPath implements IAdaptable {\r
35 \r
36     public static final NodeContextPath[] NONE  = {};\r
37 \r
38     /**\r
39      * Constant for representing an empty tree path.\r
40      */\r
41     public static final NodeContextPath   EMPTY = new NodeContextPath(NodeContext.NONE);\r
42 \r
43     private final NodeContext[]           segments;\r
44 \r
45     private int                           hash;\r
46 \r
47     /**\r
48      * Constructs a path identifying a leaf node in a tree.\r
49      * \r
50      * @param segments\r
51      *            path of elements to a leaf node in a tree, starting with the\r
52      *            root element\r
53      */\r
54     public NodeContextPath(NodeContext... segments) {\r
55         Assert.isNotNull(segments);\r
56         for (int i = 0; i < segments.length; i++) {\r
57             Assert.isNotNull(segments[i]);\r
58         }\r
59         this.segments = segments;\r
60     }\r
61 \r
62     /**\r
63      * Returns the element at the specified index in this path.\r
64      * \r
65      * @param index\r
66      *            index of element to return\r
67      * @return element at the specified index\r
68      */\r
69     public NodeContext getSegment(int index) {\r
70         return segments[index];\r
71     }\r
72 \r
73     /**\r
74      * Returns the number of elements in this path.\r
75      * \r
76      * @return the number of elements in this path\r
77      */\r
78     public int getSegmentCount() {\r
79         return segments.length;\r
80     }\r
81 \r
82     /**\r
83      * Returns the first element in this path, or <code>null</code> if this\r
84      * path has no segments.\r
85      * \r
86      * @return the first element in this path\r
87      */\r
88     public NodeContext getFirstSegment() {\r
89         if (segments.length == 0) {\r
90             return null;\r
91         }\r
92         return segments[0];\r
93     }\r
94 \r
95     /**\r
96      * Returns the last element in this path, or <code>null</code> if this\r
97      * path has no segments.\r
98      * \r
99      * @return the last element in this path\r
100      */\r
101     public NodeContext getLastSegment() {\r
102         if (segments.length == 0) {\r
103             return null;\r
104         }\r
105         return segments[segments.length - 1];\r
106     }\r
107 \r
108     /**\r
109      * @return all the segments in the path as an array\r
110      */\r
111     public NodeContext[] getSegments() {\r
112         if (segments.length == 0)\r
113             return segments;\r
114         return Arrays.copyOf(segments, segments.length);\r
115     }\r
116 \r
117     /*\r
118      * (non-Javadoc)\r
119      * \r
120      * @see java.lang.Object#equals(java.lang.Object)\r
121      */\r
122     public boolean equals(Object other) {\r
123         if (!(other instanceof NodeContextPath)) {\r
124             return false;\r
125         }\r
126         return equals((NodeContextPath) other);\r
127     }\r
128 \r
129     /**\r
130      * (non-Javadoc)\r
131      * \r
132      * @see java.lang.Object#hashCode()\r
133      */\r
134     public int hashCode() {\r
135         if (hash == 0) {\r
136             hash = hashCode0();\r
137         }\r
138         return hash;\r
139     }\r
140 \r
141     /**\r
142      * Returns a hash code computed from the hash codes of the segments, using\r
143      * the given comparer to compute the hash codes of the segments.\r
144      * \r
145      * @param comparer\r
146      *            comparer to use or <code>null</code> if the segments' hash\r
147      *            codes should be computed by calling their hashCode() methods.\r
148      * @return the computed hash code\r
149      */\r
150     private int hashCode0() {\r
151         int result = 0;\r
152         for (int i = 0; i < segments.length; i++) {\r
153             result += segments[i].hashCode();\r
154         }\r
155         return result;\r
156     }\r
157 \r
158     /**\r
159      * Returns whether this path is equivalent to the given path using the\r
160      * specified comparer to compare individual elements.\r
161      * \r
162      * @param otherPath\r
163      *            tree path to compare to\r
164      * @param comparer\r
165      *            comparator to use or <code>null</code> if segments should be\r
166      *            compared using equals()\r
167      * @return whether the paths are equal\r
168      */\r
169     public boolean equals(NodeContextPath otherPath) {\r
170         if (otherPath == null) {\r
171             return false;\r
172         }\r
173         if (segments.length != otherPath.segments.length) {\r
174             return false;\r
175         }\r
176         for (int i = 0; i < segments.length; i++) {\r
177             if (!segments[i].equals(otherPath.segments[i])) {\r
178                 return false;\r
179             }\r
180         }\r
181         return true;\r
182     }\r
183 \r
184     /**\r
185      * Returns whether this path starts with the same segments as the given\r
186      * path, using the given comparer to compare segments.\r
187      * \r
188      * @param treePath\r
189      *            path to compare to\r
190      * @param comparer\r
191      *            the comparer to use, or <code>null</code> if equals() should\r
192      *            be used to compare segments\r
193      * @return whether the given path is a prefix of this path, or the same as\r
194      *         this path\r
195      */\r
196     public boolean startsWith(NodeContextPath treePath) {\r
197         int thisSegmentCount = getSegmentCount();\r
198         int otherSegmentCount = treePath.getSegmentCount();\r
199         if (otherSegmentCount == thisSegmentCount) {\r
200             return equals(treePath);\r
201         }\r
202         if (otherSegmentCount > thisSegmentCount) {\r
203             return false;\r
204         }\r
205         for (int i = 0; i < otherSegmentCount; i++) {\r
206             Object otherSegment = treePath.getSegment(i);\r
207             if (!otherSegment.equals(segments[i])) {\r
208                 return false;\r
209             }\r
210         }\r
211         return true;\r
212     }\r
213 \r
214     /**\r
215      * Returns a copy of this tree path with one segment removed from the end,\r
216      * or <code>null</code> if this tree path has no segments.\r
217      * @return a tree path\r
218      */\r
219     public NodeContextPath getParentPath() {\r
220         int segmentCount = getSegmentCount();\r
221         if (segmentCount < 1) {\r
222             return null;\r
223         } else if (segmentCount == 1) {\r
224             return EMPTY;\r
225         }\r
226         NodeContext[] parentSegments = new NodeContext[segmentCount - 1];\r
227         System.arraycopy(segments, 0, parentSegments, 0, segmentCount - 1);\r
228         return new NodeContextPath(parentSegments);\r
229     }\r
230 \r
231     /**\r
232      * Returns a copy of this tree path with the given segment added at the end.\r
233      * @param newSegment \r
234      * @return a tree path\r
235      */\r
236     public NodeContextPath createChildPath(NodeContext newSegment) {\r
237         int segmentCount = getSegmentCount();\r
238         NodeContext[] childSegments = new NodeContext[segmentCount + 1];\r
239         if(segmentCount>0) {\r
240             System.arraycopy(segments, 0, childSegments, 0, segmentCount);\r
241         }\r
242         childSegments[segmentCount] = newSegment;\r
243         return new NodeContextPath(childSegments);\r
244     }\r
245 \r
246     @SuppressWarnings("rawtypes")\r
247     @Override\r
248     public Object getAdapter(Class adapter) {\r
249         if (NodeContext.class == adapter)\r
250             return getLastSegment();\r
251         NodeContext last = getLastSegment();\r
252         if (last instanceof IAdaptable)\r
253             return ((IAdaptable) last).getAdapter(adapter);\r
254         return null;\r
255     }\r
256 \r
257 }\r