Gridarta Editor
MapMenu.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.gui.mapmenu;
21 
22 import java.io.IOException;
23 import java.util.ArrayDeque;
24 import java.util.Deque;
25 import javax.swing.JTree;
26 import javax.swing.event.TreeModelEvent;
27 import javax.swing.event.TreeModelListener;
28 import javax.swing.tree.DefaultMutableTreeNode;
29 import javax.swing.tree.DefaultTreeModel;
30 import javax.swing.tree.MutableTreeNode;
31 import javax.swing.tree.TreeNode;
32 import javax.swing.tree.TreePath;
37 import org.apache.log4j.Category;
38 import org.apache.log4j.Logger;
39 import org.jetbrains.annotations.NotNull;
40 import org.jetbrains.annotations.Nullable;
41 
46 public class MapMenu {
47 
51  @NotNull
52  private static final Category LOG = Logger.getLogger(MapMenu.class);
53 
57  @NotNull
59 
63  @NotNull
64  private final DefaultMutableTreeNode root = new DefaultMutableTreeNode(new MapMenuEntryDir("Bookmarks"), true);
65 
69  @NotNull
70  private final DefaultTreeModel treeModel = new DefaultTreeModel(root);
71 
75  @NotNull
76  private final Deque<DeletedNode> deletedNodes = new ArrayDeque<>();
77 
81  private boolean treeModelModified;
82 
87  @NotNull
88  private final TreeModelListener treeModelListener = new TreeModelListener() {
89 
90  @Override
91  public void treeNodesChanged(final TreeModelEvent e) {
92  treeModelModified = true;
93  }
94 
95  @Override
96  public void treeNodesInserted(final TreeModelEvent e) {
97  treeModelModified = true;
98  }
99 
100  @Override
101  public void treeNodesRemoved(final TreeModelEvent e) {
102  treeModelModified = true;
103  }
104 
105  @Override
106  public void treeStructureChanged(final TreeModelEvent e) {
107  treeModelModified = true;
108  }
109 
110  };
111 
117  public MapMenu(@NotNull final String key, @NotNull final PathManager pathManager) {
118  if (LOG.isDebugEnabled()) {
119  //noinspection ThisEscapedInObjectConstruction
120  LOG.debug(System.identityHashCode(this) + " new " + key);
121  }
122  mapMenuLoader = new MapMenuLoader(key, pathManager);
123  treeModel.addTreeModelListener(treeModelListener);
124  }
125 
129  public void load() {
130  final int num = mapMenuLoader.loadNumEntries();
131  if (LOG.isDebugEnabled()) {
132  LOG.debug(System.identityHashCode(this) + " load: root.removeAllChildren");
133  }
134  root.removeAllChildren();
135  for (int i = 0; i < num; i++) {
136  final Result result;
137  try {
138  result = mapMenuLoader.loadEntry(i);
139  } catch (final IOException ex) {
140  LOG.warn("dropping invalid bookmark: " + ex.getMessage());
141  continue;
142  }
143  addMapMenuEntry(result.getDirectory(), result.getMapMenuEntry());
144  }
145  treeModelModified = false;
146  }
147 
151  public void save() {
152  if (!treeModelModified) {
153  return;
154  }
155  treeModelModified = false;
156 
157  saveAlways();
158  }
159 
163  public void saveAlways() {
164  final int prevNum = mapMenuLoader.loadNumEntries();
165  final int num = saveEntries(root, 0, "");
167  for (int i = num; i < prevNum; i++) {
169  }
170  }
171 
179  private int saveEntries(@NotNull final DefaultMutableTreeNode treeNode, final int startIndex, @NotNull final String directory) {
180  final int[] index = { startIndex };
181  for (int i = 0; i < treeModel.getChildCount(treeNode); i++) {
182  final DefaultMutableTreeNode childTreeNode = (DefaultMutableTreeNode) treeModel.getChild(treeNode, i);
183  final MapMenuEntry childMapMenuEntry = (MapMenuEntry) childTreeNode.getUserObject();
184  final String title = childMapMenuEntry.getTitle();
185  final MapMenuEntryVisitor mapMenuEntryVisitor = new MapMenuEntryVisitor() {
186 
187  @Override
188  public void visit(@NotNull final MapMenuEntryDir mapMenuEntry) {
189  mapMenuLoader.saveEntry(index[0]++, childMapMenuEntry.getTitle(), "", directory, Type.DIR);
190  index[0] = saveEntries(childTreeNode, index[0], directory.isEmpty() ? title : directory + "/" + title);
191  }
192 
193  @Override
194  public void visit(@NotNull final MapMenuEntryMap mapMenuEntry) {
195  final MapMenuEntryMap mapMenuEntryMap = (MapMenuEntryMap) childMapMenuEntry;
196  mapMenuLoader.saveEntry(index[0]++, title, mapMenuEntryMap.getMapFile().getFile().getPath(), directory, Type.MAP);
197  }
198 
199  };
200  childMapMenuEntry.visit(mapMenuEntryVisitor);
201  }
202  return index[0];
203  }
204 
210  public void addMapMenuEntry(@NotNull final String directory, @NotNull final MapMenuEntry mapMenuEntry) {
211  addMapMenuEntry(directory, new DefaultMutableTreeNode(mapMenuEntry, mapMenuEntry.allowsChildren()));
212  }
213 
220  @NotNull
221  @SuppressWarnings("TypeMayBeWeakened")
222  public TreePath addMapMenuEntry(@NotNull final String directory, @NotNull final DefaultMutableTreeNode treeNode) {
223  if (LOG.isDebugEnabled()) {
224  LOG.debug(System.identityHashCode(this) + " addMapMenuEntry(" + directory + ", " + treeNode + ")");
225  }
226  final String[] paths = StringUtils.PATTERN_SLASH.split(directory);
227  DefaultMutableTreeNode dir2 = root;
228  for (final String path : paths) {
229  if (!path.isEmpty()) {
230  dir2 = getOrCreateDirectory(dir2, path);
231  }
232  }
233  treeModel.insertNodeInto(treeNode, dir2, dir2.getChildCount());
234  return new TreePath(treeModel.getPathToRoot(treeNode));
235  }
236 
244  @NotNull
245  public DefaultMutableTreeNode getOrCreateDirectory(@NotNull final MutableTreeNode this2, @NotNull final String path) {
246  if (!MapMenuEntryDir.isValidDirectory(path)) {
247  if (LOG.isDebugEnabled()) {
248  LOG.debug(System.identityHashCode(this) + " getOrCreateDirectory(" + this2 + ", " + path + ")=invalid directory name");
249  }
250  throw new IllegalArgumentException("invalid directory name '" + path + "'");
251  }
252 
253  for (int i = this2.getChildCount() - 1; i >= 0; i--) {
254  final DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) this2.getChildAt(i);
255  final MapMenuEntry mapMenuEntry = (MapMenuEntry) treeNode.getUserObject();
256  if (mapMenuEntry.allowsChildren() && mapMenuEntry.getTitle().equals(path)) {
257  if (LOG.isDebugEnabled()) {
258  LOG.debug(System.identityHashCode(this) + " getOrCreateDirectory(" + this2 + ", " + path + ")=existing " + treeNode);
259  }
260  return treeNode;
261  }
262  }
263 
264  final DefaultMutableTreeNode new2 = new DefaultMutableTreeNode(new MapMenuEntryDir(path), true);
265  treeModel.insertNodeInto(new2, this2, this2.getChildCount());
266  if (LOG.isDebugEnabled()) {
267  LOG.debug(System.identityHashCode(this) + " getOrCreateDirectory(" + this2 + ", " + path + ")=new " + new2);
268  }
269  return new2;
270  }
271 
279  @NotNull
280  public TreePath insertNodeInto(@NotNull final MapMenuEntry mapEntry, @NotNull final DefaultMutableTreeNode parent, final int index) {
281  if (LOG.isDebugEnabled()) {
282  LOG.debug(System.identityHashCode(this) + " insertNodeInto(" + mapEntry + ", " + parent + ", " + index + ")");
283  }
284  final DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode(mapEntry, mapEntry.allowsChildren());
285  treeModel.insertNodeInto(treeNode, parent, index);
286  save();
287  return new TreePath(treeModel.getPathToRoot(treeNode));
288  }
289 
294  public void removeNode(@NotNull final DefaultMutableTreeNode treeNode) {
295  if (treeNode == root) {
296  if (LOG.isDebugEnabled()) {
297  LOG.debug(System.identityHashCode(this) + " removeNode: not removing root " + treeNode);
298  }
299  } else {
300  if (LOG.isDebugEnabled()) {
301  LOG.debug(System.identityHashCode(this) + " removeNode " + treeNode);
302  }
303  final String directory = getDirectory(treeNode);
304  treeModel.removeNodeFromParent(treeNode);
305  deletedNodes.addFirst(new DeletedNode(directory, treeNode));
306  while (deletedNodes.size() > 10) {
307  deletedNodes.removeLast();
308  }
309  save();
310  }
311  }
312 
318  @NotNull
319  private String getDirectory(@NotNull final TreeNode treeNode) {
320  final TreeNode[] treePath = treeModel.getPathToRoot(treeNode);
321  if (treePath == null) {
322  throw new IllegalArgumentException("tree node not found: " + treeNode);
323  }
324  final StringBuilder sb = new StringBuilder();
325  for (int i = 1; i + 1 < treePath.length; i++) {
326  final TreeNode tmp = treePath[i];
327  final MapMenuEntry mapMenuEntry = (MapMenuEntry) ((DefaultMutableTreeNode) tmp).getUserObject();
328  if (sb.length() > 0) {
329  sb.append('/');
330  }
331  sb.append(mapMenuEntry.getTitle());
332  }
333  return sb.toString();
334  }
335 
341  @Nullable
342  public DeletedNode getDeletedNode(final boolean delete) {
343  return delete ? deletedNodes.pollFirst() : deletedNodes.peekFirst();
344  }
345 
350  public int size() {
351  return size(root);
352  }
353 
359  private int size(@NotNull final TreeNode root) {
360  final int childCount = treeModel.getChildCount(root);
361  int result = childCount;
362  for (int i = 0; i < childCount; i++) {
363  final DefaultMutableTreeNode childTreeNode = (DefaultMutableTreeNode) treeModel.getChild(root, i);
364  final MapMenuEntry mapMenuEntry = (MapMenuEntry) childTreeNode.getUserObject();
365  if (mapMenuEntry.allowsChildren()) {
366  result += size(childTreeNode);
367  }
368  }
369  if (LOG.isDebugEnabled()) {
370  LOG.debug(System.identityHashCode(this) + " size(" + root + ")=" + result);
371  }
372  return result;
373  }
374 
379  @NotNull
380  public JTree newTree() {
381  return new AutoscrollJTree(treeModel);
382  }
383 
388  @NotNull
389  public DefaultMutableTreeNode getRoot() {
390  return root;
391  }
392 
398  public static class DeletedNode {
399 
403  @NotNull
404  private final String directory;
405 
409  @NotNull
410  private final DefaultMutableTreeNode treeNode;
411 
417  private DeletedNode(@NotNull final String directory, @NotNull final DefaultMutableTreeNode treeNode) {
418  this.directory = directory;
419  this.treeNode = treeNode;
420  }
421 
426  @NotNull
427  public String getDirectory() {
428  return directory;
429  }
430 
435  @NotNull
436  public DefaultMutableTreeNode getTreeNode() {
437  return treeNode;
438  }
439 
440  }
441 
442 }
net.sf.gridarta.gui.mapmenu.MapMenuLoader.Result
Definition: MapMenuLoader.java:225
net.sf.gridarta.gui.mapmenu.MapMenuLoader.saveNumEntries
void saveNumEntries(final int num)
Definition: MapMenuLoader.java:109
net.sf.gridarta.gui.mapmenu.MapMenu.DeletedNode.DeletedNode
DeletedNode(@NotNull final String directory, @NotNull final DefaultMutableTreeNode treeNode)
Definition: MapMenu.java:417
net.sf.gridarta.gui.mapmenu.MapMenu.deletedNodes
final Deque< DeletedNode > deletedNodes
Definition: MapMenu.java:76
net.sf.gridarta.utils.StringUtils.PATTERN_SLASH
static final Pattern PATTERN_SLASH
Definition: StringUtils.java:79
net.sf.gridarta.gui.mapmenu.MapMenuEntry
Definition: MapMenuEntry.java:29
net.sf.gridarta
net.sf.gridarta.gui.mapmenu.MapMenu.DeletedNode.treeNode
final DefaultMutableTreeNode treeNode
Definition: MapMenu.java:410
net.sf.gridarta.gui.mapmenu.MapMenu.getDirectory
String getDirectory(@NotNull final TreeNode treeNode)
Definition: MapMenu.java:319
net.sf.gridarta.gui.mapmenu.MapMenuEntry.toString
String toString()
Definition: MapMenuEntry.java:82
net.sf.gridarta.gui.mapmenu.MapMenu.getDeletedNode
DeletedNode getDeletedNode(final boolean delete)
Definition: MapMenu.java:342
net.sf.gridarta.gui.mapmenu.MapMenuEntryDir.isValidDirectory
static boolean isValidDirectory(@NotNull final String title)
Definition: MapMenuEntryDir.java:62
net.sf
net.sf.gridarta.gui.mapmenu.MapMenuLoader.loadNumEntries
int loadNumEntries()
Definition: MapMenuLoader.java:97
net.sf.gridarta.model.io.PathManager
Definition: PathManager.java:39
net.sf.gridarta.gui
net.sf.gridarta.gui.mapmenu.MapMenu.getOrCreateDirectory
DefaultMutableTreeNode getOrCreateDirectory(@NotNull final MutableTreeNode this2, @NotNull final String path)
Definition: MapMenu.java:245
net.sf.gridarta.gui.mapmenu.MapMenu
Definition: MapMenu.java:46
net.sf.gridarta.gui.mapmenu.MapMenuLoader.Result.getMapMenuEntry
MapMenuEntry getMapMenuEntry()
Definition: MapMenuLoader.java:263
net.sf.gridarta.gui.mapmenu.MapMenu.DeletedNode
Definition: MapMenu.java:398
net
net.sf.gridarta.gui.mapmenu.MapMenuEntry.getTitle
String getTitle()
Definition: MapMenuEntry.java:55
net.sf.gridarta.gui.mapmenu.MapMenuLoader.removeEntry
void removeEntry(final int index)
Definition: MapMenuLoader.java:209
net.sf.gridarta.gui.mapmenu.MapMenuLoader.loadEntry
Result loadEntry(final int index)
Definition: MapMenuLoader.java:123
net.sf.gridarta.gui.mapmenu.MapMenu.save
void save()
Definition: MapMenu.java:151
net.sf.gridarta.gui.mapmenu.MapMenu.insertNodeInto
TreePath insertNodeInto(@NotNull final MapMenuEntry mapEntry, @NotNull final DefaultMutableTreeNode parent, final int index)
Definition: MapMenu.java:280
net.sf.gridarta.gui.mapmenu.MapMenuLoader.Result.getDirectory
String getDirectory()
Definition: MapMenuLoader.java:254
net.sf.gridarta.gui.mapmenu.MapMenu.load
void load()
Definition: MapMenu.java:129
net.sf.gridarta.gui.mapmenu.MapMenu.mapMenuLoader
final MapMenuLoader mapMenuLoader
Definition: MapMenu.java:58
net.sf.gridarta.model.mapmodel.MapFile.getFile
File getFile()
Definition: MapFile.java:102
net.sf.gridarta.gui.mapmenu.MapMenu.newTree
JTree newTree()
Definition: MapMenu.java:380
net.sf.gridarta.gui.mapmenu.MapMenu.treeModel
final DefaultTreeModel treeModel
Definition: MapMenu.java:70
net.sf.gridarta.gui.mapmenu.MapMenuLoader.saveEntry
void saveEntry(final int index, @NotNull final String title, @NotNull final String filename, @NotNull final String directory, @NotNull final Type type)
Definition: MapMenuLoader.java:186
net.sf.gridarta.gui.mapmenu.MapMenuEntry.allowsChildren
abstract boolean allowsChildren()
net.sf.gridarta.gui.mapmenu.MapMenu.DeletedNode.directory
final String directory
Definition: MapMenu.java:404
net.sf.gridarta.gui.mapmenu
Definition: AbstractMapMenuPreferences.java:20
net.sf.gridarta.gui.mapmenu.MapMenu.DeletedNode.getDirectory
String getDirectory()
Definition: MapMenu.java:427
net.sf.gridarta.gui.mapmenu.MapMenuLoader
Definition: MapMenuLoader.java:35
net.sf.gridarta.utils.StringUtils
Definition: StringUtils.java:31
net.sf.gridarta.gui.mapmenu.MapMenu.treeModelListener
final TreeModelListener treeModelListener
Definition: MapMenu.java:88
net.sf.gridarta.model.io
Definition: AbstractArchetypeParser.java:20
net.sf.gridarta.gui.mapmenu.MapMenuEntryMap.getMapFile
MapFile getMapFile()
Definition: MapMenuEntryMap.java:57
net.sf.gridarta.gui.mapmenu.MapMenuLoader.Type
Definition: MapMenuLoader.java:41
net.sf.gridarta.gui.mapmenu.MapMenuEntry.visit
abstract void visit(@NotNull MapMenuEntryVisitor visitor)
net.sf.gridarta.gui.mapmenu.MapMenu.root
final DefaultMutableTreeNode root
Definition: MapMenu.java:64
net.sf.gridarta.gui.mapmenu.MapMenu.size
int size()
Definition: MapMenu.java:350
net.sf.gridarta.model
net.sf.gridarta.gui.mapmenu.MapMenu.getRoot
DefaultMutableTreeNode getRoot()
Definition: MapMenu.java:389
net.sf.gridarta.gui.mapmenu.MapMenu.DeletedNode.getTreeNode
DefaultMutableTreeNode getTreeNode()
Definition: MapMenu.java:436
net.sf.gridarta.gui.mapmenu.MapMenuLoader.Type.DIR
DIR
Definition: MapMenuLoader.java:46
net.sf.gridarta.gui.mapmenu.MapMenuEntryVisitor
Definition: MapMenuEntryVisitor.java:28
net.sf.gridarta.gui.mapmenu.MapMenu.treeModelModified
boolean treeModelModified
Definition: MapMenu.java:81
net.sf.gridarta.gui.mapmenu.MapMenuLoader.Type.MAP
MAP
Definition: MapMenuLoader.java:51
net.sf.gridarta.gui.mapmenu.MapMenu.MapMenu
MapMenu(@NotNull final String key, @NotNull final PathManager pathManager)
Definition: MapMenu.java:117
net.sf.gridarta.gui.mapmenu.MapMenu.LOG
static final Category LOG
Definition: MapMenu.java:52
net.sf.gridarta.gui.mapmenu.MapMenu.size
int size(@NotNull final TreeNode root)
Definition: MapMenu.java:359
net.sf.gridarta.gui.mapmenu.MapMenu.saveEntries
int saveEntries(@NotNull final DefaultMutableTreeNode treeNode, final int startIndex, @NotNull final String directory)
Definition: MapMenu.java:179
net.sf.gridarta.gui.mapmenu.MapMenu.removeNode
void removeNode(@NotNull final DefaultMutableTreeNode treeNode)
Definition: MapMenu.java:294
net.sf.gridarta.gui.mapmenu.MapMenuEntryMap
Definition: MapMenuEntryMap.java:29
net.sf.gridarta.gui.mapmenu.MapMenuEntryDir
Definition: MapMenuEntryDir.java:28
net.sf.gridarta.gui.mapmenu.MapMenu.addMapMenuEntry
void addMapMenuEntry(@NotNull final String directory, @NotNull final MapMenuEntry mapMenuEntry)
Definition: MapMenu.java:210
net.sf.gridarta.gui.mapmenu.MapMenu.saveAlways
void saveAlways()
Definition: MapMenu.java:163
net.sf.gridarta.utils
Definition: ActionBuilderUtils.java:20
net.sf.gridarta.gui.mapmenu.AutoscrollJTree
Definition: AutoscrollJTree.java:39