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-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.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 org.jetbrains.annotations.NotNull;
43 import org.jetbrains.annotations.Nullable;
44 
49 public class DefaultErrorView implements ErrorView {
50 
54  @NotNull
55  private static final ActionBuilder ACTION_BUILDER = ActionBuilderFactory.getInstance().getActionBuilder("net.sf.gridarta");
56 
60  @NotNull
61  private final DefaultTreeModel treeModel = new DefaultTreeModel(null);
62 
66  @NotNull
67  private final DefaultMutableTreeNode treeRoot = new ErrorEntry(treeModel, "/", true);
68 
72  @NotNull
73  private final Map<ErrorViewCategory, ErrorEntry> categories = new EnumMap<>(ErrorViewCategory.class);
74 
78  @Nullable
79  private final Component parent;
80 
84  private boolean errors;
85 
89  @Nullable
90  private Dialog dialog;
91 
95  @NotNull
96  private final Object dialogSync = new Object();
97 
101  @Nullable
102  private JButton okButton;
103 
108  @NotNull
109  private final Semaphore semaphore = new Semaphore(0);
110 
116  public DefaultErrorView(@Nullable final Component parent) {
117  treeModel.setRoot(treeRoot);
118  this.parent = parent;
119  }
120 
121  @Override
122  public void addError(@NotNull final ErrorViewCategory categoryName, @NotNull final String message) {
123  addEntry(categoryName, message);
124  errors = true;
125  }
126 
127  @Override
128  public void addError(@NotNull final ErrorViewCategory categoryName, final int lineNo, @NotNull final String message) {
129  addEntry(categoryName, lineNo + ": " + message);
130  errors = true;
131  }
132 
133  @Override
134  public void addWarning(@NotNull final ErrorViewCategory categoryName, @NotNull final String message) {
135  addEntry(categoryName, "Warning: " + message);
136  }
137 
138  @Override
139  public void addWarning(@NotNull final ErrorViewCategory categoryName, final int lineNo, @NotNull final String message) {
140  addEntry(categoryName, "Warning: line " + lineNo + ": " + message);
141  }
142 
148  private void addEntry(final ErrorViewCategory categoryName, final String message) {
149  final Runnable runnable = new Runnable() {
150 
151  @Override
152  public void run() {
153  final ErrorEntry category = getCategory(categoryName);
154  final ErrorEntry errorEntry = new ErrorEntry(treeModel, message, false);
155  category.add(errorEntry);
156  showDialog(category, errorEntry);
157  }
158 
159  };
160  if (SwingUtilities.isEventDispatchThread()) {
161  runnable.run();
162  } else {
163  try {
164  SwingUtilities.invokeAndWait(runnable);
165  } catch (final InterruptedException ignored) {
166  Thread.currentThread().interrupt();
167  } catch (final InvocationTargetException ex) {
168  throw new RuntimeException(ex);
169  }
170  }
171  }
172 
178  @NotNull
179  private ErrorEntry getCategory(@NotNull final ErrorViewCategory categoryName) {
180  final ErrorEntry existingErrorEntry = categories.get(categoryName);
181  if (existingErrorEntry != null) {
182  return existingErrorEntry;
183  }
184 
185  final ErrorEntry category = new ErrorEntry(treeModel, categoryName.toString(), true);
186  categories.put(categoryName, category);
187  treeRoot.add(category);
188  return category;
189  }
190 
191  @Override
192  public boolean hasErrors() {
193  return errors;
194  }
195 
202  private void showDialog(@NotNull final ErrorEntry category, @NotNull final ErrorEntry errorEntry) {
203  synchronized (dialogSync) {
204  if (dialog == null) {
205  showDialogInt(category, errorEntry);
206  }
207  }
208  }
209 
216  private void showDialogInt(@NotNull final ErrorEntry category, @NotNull final ErrorEntry errorEntry) {
217  final JTree tree = new JTree(treeModel);
218  final JScrollPane scrollPane = new JScrollPane(tree);
219  tree.setExpandsSelectedPaths(true);
220  final TreePath path = new TreePath(new Object[] { treeRoot, category, errorEntry, });
221  tree.setSelectionPath(path);
222  tree.scrollPathToVisible(path);
223  okButton = new JButton(ACTION_BUILDER.createAction(false, "errorViewOk", this));
224  final JOptionPane pane = new JOptionPane(scrollPane, JOptionPane.PLAIN_MESSAGE, JOptionPane.DEFAULT_OPTION, null, new Object[] { okButton, }, okButton) {
225 
227  private static final long serialVersionUID = 1L;
228 
229  @Override
230  public void setValue(@Nullable final Object newValue) {
231  super.setValue(newValue);
232  if (newValue != UNINITIALIZED_VALUE) {
233  errorViewOk();
234  }
235  }
236 
237  };
238  pane.setPreferredSize(new Dimension(800, 600));
239  assert okButton != null;
240  okButton.setEnabled(false);
241  dialog = pane.createDialog(parent, ActionBuilderUtils.getString(ACTION_BUILDER, "errorViewTitle"));
242  pane.selectInitialValue();
243  assert dialog != null;
244  dialog.pack();
245  assert dialog != null;
246  dialog.setModal(false);
247  assert dialog != null;
248  dialog.setVisible(true);
249  }
250 
251  @Override
252  public void waitDialog() throws InterruptedException {
253  if (hasDialog()) {
254  final Runnable runnable = new Runnable() {
255 
256  @Override
257  public void run() {
258  assert okButton != null;
259  okButton.setEnabled(true);
260  }
261 
262  };
263  if (SwingUtilities.isEventDispatchThread()) {
264  runnable.run();
265  } else {
266  try {
267  SwingUtilities.invokeAndWait(runnable);
268  } catch (final InvocationTargetException ex) {
269  throw new RuntimeException(ex);
270  }
271  }
272 
273  semaphore.acquire();
274  }
275 
276  if (Thread.interrupted()) {
277  throw new InterruptedException();
278  }
279  }
280 
284  public void errorViewOk() {
285  synchronized (dialogSync) {
286  if (dialog != null) {
287  try {
288  dialog.dispose();
289  dialog = null;
290  } finally {
291  semaphore.release();
292  }
293  }
294  }
295  }
296 
301  private boolean hasDialog() {
302  synchronized (dialogSync) {
303  return dialog != null;
304  }
305  }
306 
307 }
final DefaultTreeModel treeModel
The DefaultTreeModel used for the error dialog.
final Map< ErrorViewCategory, ErrorEntry > categories
Maps category name to child node.
void add(@NotNull final MutableTreeNode newChild)
Definition: ErrorEntry.java:56
final DefaultMutableTreeNode treeRoot
The tree of defined objects.
void showDialogInt(@NotNull final ErrorEntry category, @NotNull final ErrorEntry errorEntry)
Shows a dialog showing the object tree.
void waitDialog()
Waits until the dialog has been dismissed.
Defines possible error categories for ErrorView instances.
ErrorEntry getCategory(@NotNull final ErrorViewCategory categoryName)
Returns the node for a category name.
static String getString(@NotNull final ActionBuilder actionBuilder, @NotNull final String key, @NotNull final String defaultValue)
Returns the value of a key.
Interface for classes displaying error messages.
Definition: ErrorView.java:28
Base package of all Gridarta classes.
void addEntry(final ErrorViewCategory categoryName, final String message)
Adds a text message.
boolean errors
Whether at least one error message has been added.
final Semaphore semaphore
The Semaphore used to wait for the dismissal of the error dialog.
void addWarning(@NotNull final ErrorViewCategory categoryName, final int lineNo, @NotNull final String message)
Adds a warning message.
An entry in a net.sf.gridarta.gui.dialog.errorview.DefaultErrorView.
Definition: ErrorEntry.java:31
boolean hasDialog()
Returns whether the dialog has been created.
void addWarning(@NotNull final ErrorViewCategory categoryName, @NotNull final String message)
Adds a warning message.
void addError(@NotNull final ErrorViewCategory categoryName, @NotNull final String message)
Adds an error message.
void errorViewOk()
Action method for "ok" button of error dialog.
final Object dialogSync
The synchronization object used to access dialog.
Utility class for ActionBuilder related functions.
void showDialog(@NotNull final ErrorEntry category, @NotNull final ErrorEntry errorEntry)
Shows a dialog showing the object tree.
void addError(@NotNull final ErrorViewCategory categoryName, final int lineNo, @NotNull final String message)
Adds an error message.
JButton okButton
The "ok" button of the error dialog.
boolean hasErrors()
Whether at least one error message has been added.
final Component parent
The parent component for showing the error dialog or.
A dialog displaying a tree of error messages.
static final ActionBuilder ACTION_BUILDER
Action Builder.
DefaultErrorView(@Nullable final Component parent)
Creates a new instance.