Gridarta Editor
DefaultErrorView.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.dialog.errorview;
21 
22 import java.awt.Component;
23 import java.awt.Dialog;
24 import java.awt.Dimension;
25 import java.lang.reflect.InvocationTargetException;
26 import java.util.EnumMap;
27 import java.util.Map;
28 import java.util.concurrent.Semaphore;
29 import javax.swing.JButton;
30 import javax.swing.JOptionPane;
31 import javax.swing.JScrollPane;
32 import javax.swing.JTree;
33 import javax.swing.SwingUtilities;
34 import javax.swing.tree.DefaultMutableTreeNode;
35 import javax.swing.tree.DefaultTreeModel;
36 import javax.swing.tree.TreePath;
40 import net.sf.japi.swing.action.ActionBuilder;
41 import net.sf.japi.swing.action.ActionBuilderFactory;
42 import net.sf.japi.swing.action.ActionMethod;
43 import org.jetbrains.annotations.NotNull;
44 import org.jetbrains.annotations.Nullable;
45 
50 public class DefaultErrorView implements ErrorView {
51 
55  @NotNull
56  private static final ActionBuilder ACTION_BUILDER = ActionBuilderFactory.getInstance().getActionBuilder("net.sf.gridarta");
57 
61  @NotNull
62  private final DefaultTreeModel treeModel = new DefaultTreeModel(null);
63 
67  @NotNull
68  private final DefaultMutableTreeNode treeRoot = new ErrorEntry(treeModel, "/", true);
69 
73  @NotNull
74  private final Map<ErrorViewCategory, ErrorEntry> categories = new EnumMap<>(ErrorViewCategory.class);
75 
79  @Nullable
80  private final Component parent;
81 
85  private boolean errors;
86 
90  @Nullable
91  private Dialog dialog;
92 
96  @NotNull
97  private final Object dialogSync = new Object();
98 
102  @Nullable
103  private JButton okButton;
104 
109  @NotNull
110  private final Semaphore semaphore = new Semaphore(0);
111 
117  public DefaultErrorView(@Nullable final Component parent) {
118  treeModel.setRoot(treeRoot);
119  this.parent = parent;
120  }
121 
122  @Override
123  public void addError(@NotNull final ErrorViewCategory categoryName, @NotNull final String message) {
124  addEntry(categoryName, message);
125  errors = true;
126  }
127 
128  @Override
129  public void addError(@NotNull final ErrorViewCategory categoryName, final int lineNo, @NotNull final String message) {
130  addEntry(categoryName, lineNo + ": " + message);
131  errors = true;
132  }
133 
134  @Override
135  public void addWarning(@NotNull final ErrorViewCategory categoryName, @NotNull final String message) {
136  addEntry(categoryName, "Warning: " + message);
137  }
138 
139  @Override
140  public void addWarning(@NotNull final ErrorViewCategory categoryName, final int lineNo, @NotNull final String message) {
141  addEntry(categoryName, "Warning: line " + lineNo + ": " + message);
142  }
143 
149  private void addEntry(final ErrorViewCategory categoryName, final String message) {
150  final Runnable runnable = () -> {
151  final ErrorEntry category = getCategory(categoryName);
152  final ErrorEntry errorEntry = new ErrorEntry(treeModel, message, false);
153  category.add(errorEntry);
154  showDialog(category, errorEntry);
155  };
156  if (SwingUtilities.isEventDispatchThread()) {
157  runnable.run();
158  } else {
159  try {
160  SwingUtilities.invokeAndWait(runnable);
161  } catch (final InterruptedException ignored) {
162  Thread.currentThread().interrupt();
163  } catch (final InvocationTargetException ex) {
164  throw new RuntimeException(ex);
165  }
166  }
167  }
168 
174  @NotNull
175  private ErrorEntry getCategory(@NotNull final ErrorViewCategory categoryName) {
176  final ErrorEntry existingErrorEntry = categories.get(categoryName);
177  if (existingErrorEntry != null) {
178  return existingErrorEntry;
179  }
180 
181  final ErrorEntry category = new ErrorEntry(treeModel, categoryName.toString(), true);
182  categories.put(categoryName, category);
183  treeRoot.add(category);
184  return category;
185  }
186 
187  @Override
188  public boolean hasErrors() {
189  return errors;
190  }
191 
198  private void showDialog(@NotNull final ErrorEntry category, @NotNull final ErrorEntry errorEntry) {
199  synchronized (dialogSync) {
200  if (dialog == null) {
201  showDialogInt(category, errorEntry);
202  }
203  }
204  }
205 
212  private void showDialogInt(@NotNull final ErrorEntry category, @NotNull final ErrorEntry errorEntry) {
213  final JTree tree = new JTree(treeModel);
214  final JScrollPane scrollPane = new JScrollPane(tree);
215  tree.setExpandsSelectedPaths(true);
216  final TreePath path = new TreePath(new Object[] { treeRoot, category, errorEntry, });
217  tree.setSelectionPath(path);
218  tree.scrollPathToVisible(path);
219  okButton = new JButton(ACTION_BUILDER.createAction(false, "errorViewOk", this));
220  final JOptionPane pane = new JOptionPane(scrollPane, JOptionPane.PLAIN_MESSAGE, JOptionPane.DEFAULT_OPTION, null, new Object[] { okButton, }, okButton) {
221 
223  private static final long serialVersionUID = 1L;
224 
225  @Override
226  public void setValue(@Nullable final Object newValue) {
227  super.setValue(newValue);
228  if (newValue != UNINITIALIZED_VALUE) {
229  errorViewOk();
230  }
231  }
232 
233  };
234  pane.setPreferredSize(new Dimension(800, 600));
235  assert okButton != null;
236  okButton.setEnabled(false);
237  dialog = pane.createDialog(parent, ActionBuilderUtils.getString(ACTION_BUILDER, "errorViewTitle"));
238  pane.selectInitialValue();
239  assert dialog != null;
240  dialog.pack();
241  assert dialog != null;
242  dialog.setModal(false);
243  assert dialog != null;
244  dialog.setVisible(true);
245  }
246 
247  @Override
248  public void waitDialog() throws InterruptedException {
249  if (hasDialog()) {
250  final Runnable runnable = () -> {
251  assert okButton != null;
252  okButton.setEnabled(true);
253  };
254  if (SwingUtilities.isEventDispatchThread()) {
255  runnable.run();
256  } else {
257  try {
258  SwingUtilities.invokeAndWait(runnable);
259  } catch (final InvocationTargetException ex) {
260  throw new RuntimeException(ex);
261  }
262  }
263 
264  semaphore.acquire();
265  }
266 
267  if (Thread.interrupted()) {
268  throw new InterruptedException("current thread was interrupted");
269  }
270  }
271 
275  @ActionMethod
276  public void errorViewOk() {
277  synchronized (dialogSync) {
278  if (dialog != null) {
279  try {
280  dialog.dispose();
281  dialog = null;
282  } finally {
283  semaphore.release();
284  }
285  }
286  }
287  }
288 
293  private boolean hasDialog() {
294  synchronized (dialogSync) {
295  return dialog != null;
296  }
297  }
298 
299 }
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.hasErrors
boolean hasErrors()
Whether at least one error message has been added.
Definition: DefaultErrorView.java:188
net.sf.gridarta
Base package of all Gridarta classes.
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.DefaultErrorView
DefaultErrorView(@Nullable final Component parent)
Creates a new instance.
Definition: DefaultErrorView.java:117
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.getCategory
ErrorEntry getCategory(@NotNull final ErrorViewCategory categoryName)
Returns the node for a category name.
Definition: DefaultErrorView.java:175
net.sf
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.categories
final Map< ErrorViewCategory, ErrorEntry > categories
Maps category name to child node.
Definition: DefaultErrorView.java:74
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView
A dialog displaying a tree of error messages.
Definition: DefaultErrorView.java:50
net.sf.gridarta.gui.dialog.errorview.ErrorEntry.add
void add(@NotNull final MutableTreeNode newChild)
Definition: ErrorEntry.java:56
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.treeRoot
final DefaultMutableTreeNode treeRoot
The tree of defined objects.
Definition: DefaultErrorView.java:68
net.sf.gridarta.model.errorview.ErrorView
Interface for classes displaying error messages.
Definition: ErrorView.java:28
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.showDialogInt
void showDialogInt(@NotNull final ErrorEntry category, @NotNull final ErrorEntry errorEntry)
Shows a dialog showing the object tree.
Definition: DefaultErrorView.java:212
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.addEntry
void addEntry(final ErrorViewCategory categoryName, final String message)
Adds a text message.
Definition: DefaultErrorView.java:149
net
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.waitDialog
void waitDialog()
Waits until the dialog has been dismissed.
Definition: DefaultErrorView.java:248
net.sf.gridarta.model.errorview
Definition: ErrorView.java:20
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.semaphore
final Semaphore semaphore
The Semaphore used to wait for the dismissal of the error {}.
Definition: DefaultErrorView.java:110
net.sf.gridarta.model.errorview.ErrorViewCategory
Defines possible error categories for ErrorView instances.
Definition: ErrorViewCategory.java:28
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.addWarning
void addWarning(@NotNull final ErrorViewCategory categoryName, final int lineNo, @NotNull final String message)
Adds a warning message.
Definition: DefaultErrorView.java:140
net.sf.gridarta.utils.ActionBuilderUtils.getString
static String getString(@NotNull final ActionBuilder actionBuilder, @NotNull final String key, @NotNull final String defaultValue)
Returns the value of a key.
Definition: ActionBuilderUtils.java:71
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.errors
boolean errors
Whether at least one error message has been added.
Definition: DefaultErrorView.java:85
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.hasDialog
boolean hasDialog()
Returns whether the dialog has been created.
Definition: DefaultErrorView.java:293
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.addWarning
void addWarning(@NotNull final ErrorViewCategory categoryName, @NotNull final String message)
Adds a warning message.
Definition: DefaultErrorView.java:135
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.addError
void addError(@NotNull final ErrorViewCategory categoryName, @NotNull final String message)
Adds an error message.
Definition: DefaultErrorView.java:123
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.errorViewOk
void errorViewOk()
Action method for "ok" button of error dialog.
Definition: DefaultErrorView.java:276
net.sf.gridarta.model
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.parent
final Component parent
The parent component for showing the error dialog or.
Definition: DefaultErrorView.java:80
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.showDialog
void showDialog(@NotNull final ErrorEntry category, @NotNull final ErrorEntry errorEntry)
Shows a dialog showing the object tree.
Definition: DefaultErrorView.java:198
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.addError
void addError(@NotNull final ErrorViewCategory categoryName, final int lineNo, @NotNull final String message)
Adds an error message.
Definition: DefaultErrorView.java:129
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.dialog
Dialog dialog
The dialog instance.
Definition: DefaultErrorView.java:91
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.okButton
JButton okButton
The "ok" button of the error dialog.
Definition: DefaultErrorView.java:103
net.sf.gridarta.utils.ActionBuilderUtils
Utility class for ActionBuilder related functions.
Definition: ActionBuilderUtils.java:31
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.dialogSync
final Object dialogSync
The synchronization object used to access dialog.
Definition: DefaultErrorView.java:97
net.sf.gridarta.gui.dialog.errorview.ErrorEntry
An entry in a DefaultErrorView.
Definition: ErrorEntry.java:31
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.treeModel
final DefaultTreeModel treeModel
The DefaultTreeModel used for the error dialog.
Definition: DefaultErrorView.java:62
net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.ACTION_BUILDER
static final ActionBuilder ACTION_BUILDER
Action Builder.
Definition: DefaultErrorView.java:56
net.sf.gridarta.utils
Definition: ActionBuilderUtils.java:20