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-2023 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.MapMenuEntry.getTitle
String getTitle()
Definition: MapMenuEntry.java:55
net.sf.gridarta.gui.mapmenu.MapMenu.treeModelModified
boolean treeModelModified
Definition: MapMenu.java:81
net.sf.gridarta.gui.mapmenu.MapMenu.deletedNodes
final Deque< DeletedNode > deletedNodes
Definition: MapMenu.java:76
net.sf.gridarta.gui.mapmenu.MapMenu.root
final DefaultMutableTreeNode root
Definition: MapMenu.java:64
net.sf.gridarta.gui.mapmenu.MapMenuEntry
Definition: MapMenuEntry.java:29
net.sf.gridarta.gui.mapmenu.MapMenu.size
int size()
Definition: MapMenu.java:350
net.sf.gridarta.gui.mapmenu.MapMenu.treeModel
final DefaultTreeModel treeModel
Definition: MapMenu.java:70
net.sf.gridarta.utils.StringUtils
Definition: StringUtils.java:31
net.sf.gridarta
net.sf.gridarta.gui.mapmenu.MapMenuLoader.removeEntry
void removeEntry(final int index)
Definition: MapMenuLoader.java:209
net.sf.gridarta.gui.mapmenu.MapMenuLoader.Type
Definition: MapMenuLoader.java:41
net.sf.gridarta.gui.mapmenu.MapMenu.load
void load()
Definition: MapMenu.java:129
net.sf.gridarta.gui.mapmenu.MapMenuEntryMap
Definition: MapMenuEntryMap.java:29
net.sf
net.sf.gridarta.gui.mapmenu.MapMenuLoader.loadEntry
Result loadEntry(final int index)
Definition: MapMenuLoader.java:123
net.sf.gridarta.gui.mapmenu.MapMenuEntry.visit
abstract void visit(@NotNull MapMenuEntryVisitor visitor)
net.sf.gridarta.gui.mapmenu.MapMenu.DeletedNode
Definition: MapMenu.java:398
net.sf.gridarta.gui.mapmenu.MapMenuLoader.Type.DIR
DIR
Definition: MapMenuLoader.java:46
net.sf.gridarta.gui.mapmenu.MapMenu.getDeletedNode
DeletedNode getDeletedNode(final boolean delete)
Definition: MapMenu.java:342
net.sf.gridarta.gui.mapmenu.MapMenuLoader.Result.getDirectory
String getDirectory()
Definition: MapMenuLoader.java:254
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.MapMenuLoader.saveNumEntries
void saveNumEntries(final int num)
Definition: MapMenuLoader.java:109
net.sf.gridarta.gui
net.sf.gridarta.gui.mapmenu.MapMenu.DeletedNode.treeNode
final DefaultMutableTreeNode treeNode
Definition: MapMenu.java:410
net.sf.gridarta.gui.mapmenu.AutoscrollJTree
Definition: AutoscrollJTree.java:39
net.sf.gridarta.gui.mapmenu.MapMenuLoader.Type.MAP
MAP
Definition: MapMenuLoader.java:51
net
net.sf.gridarta.gui.mapmenu.MapMenu.mapMenuLoader
final MapMenuLoader mapMenuLoader
Definition: MapMenu.java:58
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.MapMenuEntry.allowsChildren
abstract boolean allowsChildren()
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.size
int size(@NotNull final TreeNode root)
Definition: MapMenu.java:359
net.sf.gridarta.gui.mapmenu.MapMenu.LOG
static final Category LOG
Definition: MapMenu.java:52
net.sf.gridarta.gui.mapmenu.MapMenuEntry.toString
String toString()
Definition: MapMenuEntry.java:82
directory
This document describes some hints and requirements for general development on the CrossfireEditor If you plan to make changes to the editor code or setup please read the following and keep it in derived from a basic editor application called Gridder by Pasi Ker�nen so please communicate with best through the cf devel mailing before considering any fundamental changes About code DO NOT USE TABS No matter what Java development platform you are please configure insert indent Tabs are displayed totally different in every editor and there are millions of different editors out there The insertion of tabs in the source code is messing up the syntax formatting in a way that is UNREPAIRABLE Apart from please keep code indentation accurate This is not just good it helps to keep code readable and in that way dramatically decreases the chance for overlooked bugs Everyone is welcomed to correct indentation errors wherever they are spotted Before you start to do this please double check that your editor is really configured to insert spaces Line feeds may be checked in either in windows or in unix linux style All reasonable text and java editors can deal with both linefeed formats Converting line feeds is but in this case please make sure that only linefeed characters are changed and nothing else is affected Due to the platform independent nature of the editor has the potential to run on almost any given operating system the build process differs greatly between systems as well as java environments In the several people have attempted to add build scripts along with structural changes to optimize the setup on one particular system environment which has led to conflict Please do *not *attempt to change the structure or any directories for the mere purpose of improving a build process or performance in a java environment Build scripts may be placed in the root directory
Definition: Developer_README.txt:45
net.sf.gridarta.model.io.PathManager
Definition: PathManager.java:39
net.sf.gridarta.gui.mapmenu
Definition: AbstractMapMenuPreferences.java:20
net.sf.gridarta.gui.mapmenu.MapMenuLoader.Result.getMapMenuEntry
MapMenuEntry getMapMenuEntry()
Definition: MapMenuLoader.java:263
net.sf.gridarta.gui.mapmenu.MapMenuEntryVisitor
Definition: MapMenuEntryVisitor.java:28
net.sf.gridarta.gui.mapmenu.MapMenu
Definition: MapMenu.java:46
net.sf.gridarta.model.io
Definition: AbstractArchetypeParser.java:20
net.sf.gridarta.gui.mapmenu.MapMenu.DeletedNode.DeletedNode
DeletedNode(@NotNull final String directory, @NotNull final DefaultMutableTreeNode treeNode)
Definition: MapMenu.java:417
net.sf.gridarta.utils.StringUtils.PATTERN_SLASH
static final Pattern PATTERN_SLASH
Definition: StringUtils.java:79
net.sf.gridarta.gui.mapmenu.MapMenuLoader.loadNumEntries
int loadNumEntries()
Definition: MapMenuLoader.java:97
net.sf.gridarta.model
net.sf.gridarta.gui.mapmenu.MapMenu.saveAlways
void saveAlways()
Definition: MapMenu.java:163
net.sf.gridarta.gui.mapmenu.MapMenu.getDirectory
String getDirectory(@NotNull final TreeNode treeNode)
Definition: MapMenu.java:319
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.MapMenuLoader.Result
Definition: MapMenuLoader.java:225
net.sf.gridarta.gui.mapmenu.MapMenu.removeNode
void removeNode(@NotNull final DefaultMutableTreeNode treeNode)
Definition: MapMenu.java:294
net.sf.gridarta.gui.mapmenu.MapMenuLoader
Definition: MapMenuLoader.java:35
net.sf.gridarta.gui.mapmenu.MapMenu.treeModelListener
final TreeModelListener treeModelListener
Definition: MapMenu.java:88
net.sf.gridarta.model.mapmodel.MapFile.getFile
File getFile()
Definition: MapFile.java:102
net.sf.gridarta.gui.mapmenu.MapMenu.DeletedNode.directory
final String directory
Definition: MapMenu.java:404
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.MapMenu.insertNodeInto
TreePath insertNodeInto(@NotNull final MapMenuEntry mapEntry, @NotNull final DefaultMutableTreeNode parent, final int index)
Definition: MapMenu.java:280
net.sf.gridarta.gui.mapmenu.MapMenuEntryDir.isValidDirectory
static boolean isValidDirectory(@NotNull final String title)
Definition: MapMenuEntryDir.java:62
net.sf.gridarta.utils
Definition: ActionBuilderUtils.java:20
net.sf.gridarta.gui.mapmenu.MapMenu.DeletedNode.getDirectory
String getDirectory()
Definition: MapMenu.java:427
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.newTree
JTree newTree()
Definition: MapMenu.java:380
net.sf.gridarta.gui.mapmenu.MapMenuEntryDir
Definition: MapMenuEntryDir.java:28
net.sf.gridarta.gui.mapmenu.MapMenu.save
void save()
Definition: MapMenu.java:151
net.sf.gridarta.gui.mapmenu.MapMenuEntryMap.getMapFile
MapFile getMapFile()
Definition: MapMenuEntryMap.java:57