Gridarta Editor
NamedTreeNode.java
Go to the documentation of this file.
1 /*
2  * Gridarta MMORPG map editor for Crossfire, Daimonin and similar games.
3  * Copyright (C) 2000-2015 The Gridarta Developers.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 package net.sf.gridarta.model.data;
21 
22 import java.io.Serializable;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.Enumeration;
28 import java.util.SortedMap;
29 import java.util.TreeMap;
30 import javax.swing.tree.TreeNode;
31 import javax.swing.tree.TreePath;
32 import org.jetbrains.annotations.NotNull;
33 import org.jetbrains.annotations.Nullable;
34 
40 public class NamedTreeNode<E extends NamedObject> implements TreeNode, Comparable<NamedTreeNode<E>>, Serializable {
41 
45  private static final long serialVersionUID = 1L;
46 
51  @NotNull
52  private final SortedMap<String, NamedTreeNode<E>> childNodes = new TreeMap<>();
53 
60  @Nullable
62 
67  @Nullable
68  private final NamedTreeNode<E> parent;
69 
74  @NotNull
75  private final String name;
76 
81  @Nullable
82  private final NamedObject namedObject;
83 
89  private final boolean dir;
90 
95  public NamedTreeNode() {
96  this(true, null, "/");
97  }
98 
108  private NamedTreeNode(final boolean dir, @Nullable final NamedTreeNode<E> parent, @NotNull final String name) {
109  this.dir = dir;
110  this.parent = parent;
111  this.name = name;
112  namedObject = null;
113  }
114 
123  private NamedTreeNode(final boolean dir, @Nullable final NamedTreeNode<E> parent, @NotNull final NamedObject namedObject) {
124  this.dir = dir;
125  this.parent = parent;
126  name = namedObject.getName();
127  this.namedObject = namedObject;
128  }
129 
135  public void append(@NotNull final NamedObject namedObject) throws IllegalNamedObjectException {
136  if (parent != null) {
137  throw new IllegalNamedObjectException("node '" + namedObject.getPath() + "' is not a root node");
138  }
139  append(namedObject.getPath(), namedObject);
140  }
141 
148  private void append(@NotNull final String path, @NotNull final NamedObject namedObject) throws IllegalNamedObjectException {
149  childNodeArray = null;
150  if (!dir) {
151  throw new IllegalNamedObjectException("cannot insert '" + path + "' into non-directory node for '" + namedObject.getPath() + "'");
152  }
153  String realName = path.startsWith("/") ? path.substring(1) : path;
154  // Now we have the child node name in realName
155  if (realName.contains("/")) {
156  // Find directory node and append there
157  final String dirName = realName.substring(0, realName.indexOf('/'));
158  realName = realName.substring(realName.indexOf('/'));
159  NamedTreeNode<E> dirNode = childNodes.get(dirName);
160  if (dirNode == null) {
161  dirNode = new NamedTreeNode<>(true, this, dirName);
162  childNodes.put(dirName, dirNode);
163  }
164  dirNode.append(realName, namedObject);
165  } else {
166  // Append face node to this
167  //realName = realName.substring(0, realName.length() - 4);
168  final NamedTreeNode<E> faceNode = new NamedTreeNode<>(false, this, namedObject);
169  childNodes.put(realName, faceNode);
170  }
171  }
172 
176  private void initLazyArray() {
177  if (childNodeArray == null) {
178  childNodeArray = childNodes.values().toArray(new NamedTreeNode<?>[childNodes.size()]);
179  }
180  }
181 
182  // --Commented out by Inspection START (09.06.05 04:00):
183  // /** Check whether this is a directory node.
184  // * @return {@code true} for directory nodes, {@code false} for face nodes
185  // */
186  // public final boolean isDir() {
187  // return dir;
188  // }
189  // --Commented out by Inspection STOP (09.06.05 04:00)
190 
197  @Nullable
198  public NamedObject getNamedObject() {
199  return namedObject;
200  }
201 
206  @NotNull
207  public String getName() {
208  return name;
209  }
210 
211  @NotNull
212  @Override
213  public Enumeration<NamedTreeNode<E>> children() {
214  return Collections.enumeration(childNodes.values());
215  }
216 
220  @Override
221  public boolean getAllowsChildren() {
222  return dir;
223  }
224 
225  @NotNull
226  @Override
227  public TreeNode getChildAt(final int childIndex) {
228  initLazyArray();
229  assert childNodeArray != null;
230  return childNodeArray[childIndex];
231  }
232 
233  @Override
234  public int getChildCount() {
235  return childNodes.size();
236  }
237 
238  @Override
239  public int getIndex(@NotNull final TreeNode node) {
240  initLazyArray();
241  final int result = Arrays.binarySearch(childNodeArray, node);
242  return result < 0 ? -1 : result;
243  }
244 
245  @Nullable
246  @Override
247  public NamedTreeNode<E> getParent() {
248  return parent;
249  }
250 
254  @Override
255  public boolean isLeaf() {
256  return !dir;
257  }
258 
259  @Override
260  public boolean equals(@Nullable final Object obj) {
261  if (obj == this) {
262  return true;
263  }
264  if (obj == null || obj.getClass() != getClass()) {
265  return false;
266  }
267  final NamedTreeNode<?> namedTreeNode = (NamedTreeNode<?>) obj;
268  return dir == namedTreeNode.dir && name.equals(namedTreeNode.name);
269  }
270 
271  @Override
272  public int hashCode() {
273  return (dir ? 1 : 0) ^ name.hashCode();
274  }
275 
276  @Override
277  public int compareTo(@NotNull final NamedTreeNode<E> o) {
278  return dir ^ !o.dir ? name.compareTo(o.name) : dir ? -1 : 1;
279  }
280 
286  @NotNull
287  public TreePath getPathFor(@NotNull final String path) {
288  final Collection<NamedTreeNode<E>> nodes = new ArrayList<>();
289  String currentPath = path;
290  // XXX This is ugly but it works, no time to think about it now.
291  String dirPart;
292  for (NamedTreeNode<E> currentNode = this; currentNode != null; currentNode = currentNode.childNodes.get(dirPart)) {
293  nodes.add(currentNode);
294  if (currentPath.indexOf('/', 1) >= 0) {
295  dirPart = currentPath.substring(1, currentPath.indexOf('/', 1));
296  currentPath = currentPath.substring(currentPath.indexOf('/', 1));
297  } else if (currentPath.indexOf('/') >= 0) {
298  dirPart = currentPath.substring(1);
299  currentPath = "";
300  } else {
301  break;
302  }
303  }
304  return new TreePath(nodes.toArray());
305  }
306 
307  @NotNull
308  @Override
309  public String toString() {
310  return name;
311  }
312 
313 }
final NamedTreeNode< E > parent
The parent node, which may be.
NamedTreeNode(final boolean dir, @Nullable final NamedTreeNode< E > parent, @NotNull final String name)
Create a NamedTreeNode.
NamedTreeNode<?> [] childNodeArray
The node array.
static final long serialVersionUID
The serial version UID.
void initLazyArray()
Makes sure that the variable childNodeArray points to a valid array.
final String name
The node name.
final SortedMap< String, NamedTreeNode< E > > childNodes
The children.
String getPath()
Get the path of this AbstractNamedObject.
final NamedObject namedObject
The node object.
final boolean dir
Directory state,.
Exception thrown to indicate that a named object is not acceptable.
NamedTreeNode(final boolean dir, @Nullable final NamedTreeNode< E > parent, @NotNull final NamedObject namedObject)
Create a NamedTreeNode.
void append(@NotNull final NamedObject namedObject)
Append a node.
void append(@NotNull final String path, @NotNull final NamedObject namedObject)
Appends a node.
TreeNode implementation for Named Objects (like arches, faces, animations, artifacts etc...