Gridarta Editor
GoMapDialog.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.gomap;
21 
22 import java.awt.BorderLayout;
23 import java.awt.Component;
24 import java.awt.Dialog;
25 import java.awt.Window;
26 import java.awt.event.MouseEvent;
27 import java.awt.event.MouseListener;
28 import java.awt.event.WindowEvent;
29 import java.awt.event.WindowListener;
30 import java.io.IOException;
31 import java.util.Collection;
32 import java.util.Comparator;
33 import java.util.HashSet;
34 import java.util.List;
35 import java.util.TreeSet;
36 import javax.swing.DefaultListModel;
37 import javax.swing.JComponent;
38 import javax.swing.JDialog;
39 import javax.swing.JList;
40 import javax.swing.JPanel;
41 import javax.swing.JScrollPane;
42 import javax.swing.JTextField;
43 import javax.swing.ListSelectionModel;
44 import javax.swing.ScrollPaneConstants;
45 import javax.swing.SwingUtilities;
46 import javax.swing.border.EmptyBorder;
47 import javax.swing.event.DocumentEvent;
48 import javax.swing.event.DocumentListener;
49 import javax.swing.text.JTextComponent;
62 import net.sf.japi.swing.action.ActionBuilder;
63 import net.sf.japi.swing.action.ActionBuilderFactory;
64 import net.sf.japi.swing.action.ActionMethod;
65 import org.jetbrains.annotations.NotNull;
66 
71 public class GoMapDialog<G extends GameObject<G, A, R>, A extends MapArchObject<A>, R extends Archetype<G, A, R>> {
72 
76  @NotNull
77  private static final ActionBuilder ACTION_BUILDER = ActionBuilderFactory.getInstance().getActionBuilder("net.sf.gridarta");
78 
82  @NotNull
83  private final JDialog dialog;
84 
88  @NotNull
89  private final JTextComponent input;
90 
94  @NotNull
95  private final MapsIndex mapsIndex;
96 
100  @NotNull
102 
106  @NotNull
107  private final DefaultListModel<MapFile> listModel = new DefaultListModel<>();
108 
112  @NotNull
113  private final JList<MapFile> list = new JList<>(listModel);
114 
118  private boolean dialogShown;
119 
123  @NotNull
124  private final Comparator<MapFile> mapNameComparator = new Comparator<MapFile>() {
125 
126  @Override
127  public int compare(@NotNull final MapFile o1, @NotNull final MapFile o2) {
128  final String name1 = mapsIndex.getName(o1);
129  final String name2 = mapsIndex.getName(o2);
130 
131  if (name1 == null) {
132  //noinspection VariableNotUsedInsideIf
133  return name2 == null ? 0 : -1;
134  }
135 
136  if (name2 == null) {
137  return +1;
138  }
139 
140  final int cmp = name1.compareToIgnoreCase(name2);
141  if (cmp != 0) {
142  return cmp;
143  }
144 
145  return o1.getFile().compareTo(o2.getFile());
146  }
147 
148  };
149 
155  @NotNull
157 
158  @Override
159  public void valueAdded(@NotNull final MapFile value) {
160  // ignore
161  }
162 
163  @Override
164  public void valueRemoved(@NotNull final MapFile value) {
165  // ignore
166  }
167 
168  @Override
169  public void nameChanged() {
171  }
172 
173  @Override
174  public void pendingChanged() {
175  // ignore
176  }
177 
178  @Override
179  public void indexingFinished() {
181  }
182 
183  };
184 
191  @NotNull
192  private final WindowListener windowListener = new WindowListener() {
193 
194  @Override
195  public void windowOpened(final WindowEvent e) {
196  if (!dialogShown) {
197  dialogShown = true;
198  mapsIndex.addIndexListener(indexListener);
199  doSearch();
200  }
201  }
202 
203  @Override
204  public void windowClosing(final WindowEvent e) {
205  // ignore
206  }
207 
208  @Override
209  public void windowClosed(final WindowEvent e) {
210  if (dialogShown) {
211  dialogShown = false;
212  mapsIndex.removeIndexListener(indexListener);
213  }
214  }
215 
216  @Override
217  public void windowIconified(final WindowEvent e) {
218  // ignore
219  }
220 
221  @Override
222  public void windowDeiconified(final WindowEvent e) {
223  // ignore
224  }
225 
226  @Override
227  public void windowActivated(final WindowEvent e) {
228  // ignore
229  }
230 
231  @Override
232  public void windowDeactivated(final WindowEvent e) {
233  // ignore
234  }
235 
236  };
237 
242  @NotNull
244 
245  @Override
246  public void change() {
247  if (!dialogShown) {
248  return;
249  }
250 
251  SwingUtilities.invokeLater(new Runnable() {
252 
253  @Override
254  public void run() {
255  //XXX:suppress incorrect warning
256  //noinspection ConstantConditions
257  if (dialogShown) {
258  doSearch();
259  }
260  }
261 
262  });
263  }
264 
265  });
266 
273  public GoMapDialog(@NotNull final Window parent, @NotNull final MapsIndex mapsIndex, @NotNull final MapViewsManager<G, A, R> mapViewsManager) {
274  this.mapsIndex = mapsIndex;
275  this.mapViewsManager = mapViewsManager;
276  final Component label = ActionBuilderUtils.newLabel(ACTION_BUILDER, "goMapLabel");
277 
278  input = new JTextField();
279  SwingUtils.addAction(input, ACTION_BUILDER.createAction(false, "goMapScrollUp", this));
280  SwingUtils.addAction(input, ACTION_BUILDER.createAction(false, "goMapScrollDown", this));
281  SwingUtils.addAction(input, ACTION_BUILDER.createAction(false, "goMapScrollPageUp", this));
282  SwingUtils.addAction(input, ACTION_BUILDER.createAction(false, "goMapScrollPageDown", this));
283  SwingUtils.addAction(input, ACTION_BUILDER.createAction(false, "goMapScrollTop", this));
284  SwingUtils.addAction(input, ACTION_BUILDER.createAction(false, "goMapScrollBottom", this));
285  SwingUtils.addAction(input, ACTION_BUILDER.createAction(false, "goMapSelectUp", this));
286  SwingUtils.addAction(input, ACTION_BUILDER.createAction(false, "goMapSelectDown", this));
287  SwingUtils.addAction(input, ACTION_BUILDER.createAction(false, "goMapCancel", this));
288  SwingUtils.addAction(input, ACTION_BUILDER.createAction(false, "goMapApply", this));
289  final DocumentListener documentListener = new DocumentListener() {
290 
291  @Override
292  public void changedUpdate(@NotNull final DocumentEvent e) {
293  doSearch();
294  }
295 
296  @Override
297  public void insertUpdate(@NotNull final DocumentEvent e) {
298  doSearch();
299  }
300 
301  @Override
302  public void removeUpdate(@NotNull final DocumentEvent e) {
303  doSearch();
304  }
305 
306  };
307  input.getDocument().addDocumentListener(documentListener);
309 
310  final JComponent inputPanel = new JPanel(new BorderLayout());
311  inputPanel.add(label, BorderLayout.NORTH);
312  inputPanel.add(input, BorderLayout.CENTER);
313  inputPanel.setBorder(new EmptyBorder(3, 3, 3, 3));
314 
315  list.setFocusable(false);
316  final Component scrollPane = new JScrollPane(list, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
317  list.setCellRenderer(new MapListCellRenderer(mapsIndex));
318  list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
319  final MouseListener mouseListener = new MouseListener() {
320 
321  @Override
322  public void mouseClicked(final MouseEvent e) {
323  // ignore
324  }
325 
326  @Override
327  public void mousePressed(final MouseEvent e) {
328  if (e.getClickCount() > 1) {
329  goMapApply();
330  }
331  }
332 
333  @Override
334  public void mouseReleased(final MouseEvent e) {
335  // ignore
336  }
337 
338  @Override
339  public void mouseEntered(final MouseEvent e) {
340  // ignore
341  }
342 
343  @Override
344  public void mouseExited(final MouseEvent e) {
345  // ignore
346  }
347 
348  };
349  list.addMouseListener(mouseListener);
350 
351  dialog = new JDialog(parent);
352  dialog.setResizable(false);
353  dialog.setSize(600, 400);
354  dialog.setLocationRelativeTo(parent);
355  dialog.setUndecorated(true);
356  dialog.setLayout(new BorderLayout());
357  dialog.add(inputPanel, BorderLayout.NORTH);
358  dialog.add(scrollPane, BorderLayout.CENTER);
359  dialog.setModalityType(Dialog.ModalityType.DOCUMENT_MODAL);
360  dialog.addWindowListener(windowListener);
361  }
362 
366  public void showDialog() {
367  dialog.setVisible(true);
368  }
369 
373  private void doSearch() {
374  final String mapName = input.getText();
375  if (mapName.isEmpty()) {
376  listModel.clear();
377  return;
378  }
379 
380  final Collection<MapFile> maps = mapsIndex.findPartialName(mapName);
381  final Collection<MapFile> sortedMaps = new TreeSet<>(mapNameComparator);
382  sortedMaps.addAll(maps);
383  final Collection<MapFile> selectedValues = new HashSet<>(list.getSelectedValuesList());
384  listModel.clear();
385  int visibleIndex = -1;
386  for (final MapFile map : sortedMaps) {
387  listModel.addElement(map);
388  if (selectedValues.contains(map)) {
389  final int index = listModel.size() - 1;
390  list.addSelectionInterval(index, index);
391  visibleIndex = index;
392  }
393  }
394  if (list.getSelectedIndex() == -1) {
395  list.setSelectedIndex(0);
396  visibleIndex = 0;
397  }
398  if (visibleIndex != -1) {
399  list.ensureIndexIsVisible(visibleIndex);
400  }
401  }
402 
406  @ActionMethod
407  public void goMapApply() {
408  if (goMap()) {
409  dialog.removeWindowListener(windowListener);
410  dialog.dispose();
411  }
412  }
413 
417  @ActionMethod
418  public void goMapCancel() {
419  dialog.removeWindowListener(windowListener);
420  dialog.dispose();
421  }
422 
426  @ActionMethod
427  public void goMapScrollUp() {
428  final int index = list.getMinSelectionIndex();
429  final int newIndex = index > 0 ? index - 1 : listModel.size() - 1;
430  list.setSelectedIndex(newIndex);
431  list.ensureIndexIsVisible(newIndex);
432  }
433 
437  @ActionMethod
438  public void goMapScrollDown() {
439  final int index = list.getMaxSelectionIndex() + 1;
440  final int newIndex = index < listModel.size() ? index : 0;
441  list.setSelectedIndex(newIndex);
442  list.ensureIndexIsVisible(newIndex);
443  }
444 
448  @ActionMethod
449  public void goMapScrollPageUp() {
450  final int index = list.getMinSelectionIndex();
451  final int firstIndex = list.getFirstVisibleIndex();
452  final int newIndex;
453  if (firstIndex == -1) {
454  newIndex = -1;
455  } else if (index == -1) {
456  newIndex = firstIndex;
457  } else if (index > firstIndex) {
458  newIndex = firstIndex;
459  } else {
460  newIndex = Math.max(firstIndex - (list.getLastVisibleIndex() - firstIndex), 0);
461  }
462  list.setSelectedIndex(newIndex);
463  list.ensureIndexIsVisible(newIndex);
464  }
465 
469  @ActionMethod
470  public void goMapScrollPageDown() {
471  final int index = list.getMaxSelectionIndex();
472  final int lastIndex = list.getLastVisibleIndex();
473  final int newIndex;
474  if (lastIndex == -1) {
475  newIndex = -1;
476  } else if (index == -1) {
477  newIndex = lastIndex;
478  } else if (index < lastIndex) {
479  newIndex = lastIndex;
480  } else {
481  newIndex = Math.min(lastIndex + (lastIndex - list.getFirstVisibleIndex()), listModel.size() - 1);
482  }
483  list.setSelectedIndex(newIndex);
484  list.ensureIndexIsVisible(newIndex);
485  }
486 
490  @ActionMethod
491  public void goMapScrollTop() {
492  final int newIndex = 0;
493  list.setSelectedIndex(newIndex);
494  list.ensureIndexIsVisible(newIndex);
495  }
496 
500  @ActionMethod
501  public void goMapScrollBottom() {
502  final int newIndex = listModel.size() - 1;
503  list.setSelectedIndex(newIndex);
504  list.ensureIndexIsVisible(newIndex);
505  }
506 
510  @ActionMethod
511  public void goMapSelectUp() {
512  final int index = list.getMinSelectionIndex();
513  if (index != 0) {
514  final int newIndex = index > 0 ? index - 1 : listModel.size() - 1;
515  list.addSelectionInterval(newIndex, newIndex);
516  list.ensureIndexIsVisible(newIndex);
517  }
518  }
519 
523  @ActionMethod
524  public void goMapSelectDown() {
525  final int index = list.getMaxSelectionIndex();
526  if (index + 1 < listModel.size()) {
527  final int newIndex = index + 1;
528  list.addSelectionInterval(newIndex, newIndex);
529  list.ensureIndexIsVisible(newIndex);
530  }
531  }
532 
537  private boolean goMap() {
538  final List<MapFile> selectedValues = list.getSelectedValuesList();
539  boolean result = false;
540  for (final MapFile selectedValue : selectedValues) {
541  try {
542  mapViewsManager.openMapFileWithView(selectedValue, null, null);
543  result = true;
544  } catch (final IOException ex) {
545  ACTION_BUILDER.showMessageDialog(dialog, "goMapIOException", selectedValue, ex.getMessage());
546  }
547  }
548  return result;
549  }
550 
551 }
Indexes maps by map name.
Definition: MapsIndex.java:29
Helper for reducing the number of change events: calls to change() will be forwarded to DelayedChange...
final MapsIndex mapsIndex
The MapsIndex for looking up maps.
static final ActionBuilder ACTION_BUILDER
The ActionBuilder.
void removeIndexListener(@NotNull final IndexListener< V > listener)
Removes an IndexListener to be notified of changes.
void goMapScrollPageUp()
Action method for scroll page up.
void finish()
Finishes a series of change events.
Graphical User Interface of Gridarta.
final MapViewsManager< G, A, R > mapViewsManager
The MapViewsManager for opening maps.
Interface for listeners interested in Index related events.
void goMapSelectDown()
Action method for select down.
void goMapScrollPageDown()
Action method for scroll page down.
Listener for forwarded events of DelayedChangeManager.
void goMapScrollUp()
Action method for scroll up.
final JDialog dialog
The JDialog instance.
void doSearch()
Updates the maps display from the map name input field.
final JList< MapFile > list
The JList showing the matching maps.
void goMapScrollTop()
Action method for scroll top.
Utility class for Swing related functions.
Definition: SwingUtils.java:37
void addIndexListener(@NotNull final IndexListener< V > listener)
Adds an IndexListener to be notified of changes.
Base package of all Gridarta classes.
void goMapSelectUp()
Action method for select up.
Reflects a game object (object on a map).
Definition: GameObject.java:36
Utility class for JTextComponent related functions.
MapView< G, A, R > openMapFileWithView(@NotNull final MapFile mapFile, @Nullable final Point viewPosition, @Nullable final Point centerSquare)
Load a map file and create a map view.
A DefaultListCellRenderer that renders values of a MapsIndex.
final DelayedChangeManager delayedChangeManager
A DelayedChangeManager for updating search results after mapsIndex changes.
GameObjects are the objects based on Archetypes found on maps.
static void setAutoSelectOnFocus(@NotNull final JTextComponent textComponent)
Selects all text of a JTextComponent when the component gains the focus.
Collection< V > findPartialName(@NotNull final String name)
Returns all matching values for a (possibly partial) key name.
void change()
Delivers a change event to the associated DelayedChangeListener.
void goMapScrollDown()
Action method for scroll down.
void goMapScrollBottom()
Action method for scroll bottom.
Base classes for rendering maps.
GoMapDialog(@NotNull final Window parent, @NotNull final MapsIndex mapsIndex, @NotNull final MapViewsManager< G, A, R > mapViewsManager)
Creates a new instance.
final Comparator< MapFile > mapNameComparator
A Comparator that orders map files by map name.
void goMapApply()
Action method for apply.
final IndexListener< MapFile > indexListener
The IndexListener attached to mapsIndex to update search results after index changes.
String getName(@NotNull final V value)
Returns the name associated with a value.
Utility class for ActionBuilder related functions.
A dialog to ask the user for a map to open.
void goMapCancel()
Action method for cancel.
static JLabel newLabel(@NotNull final ActionBuilder actionBuilder, @NotNull final String key)
Creates a new JLabel from a resource key.
final DefaultListModel< MapFile > listModel
The list model containing the search results.
The location of a map file with a map directory.
Definition: MapFile.java:31
boolean goMap()
Opens the selected maps.
boolean dialogShown
Whether dialog is currently shown.
final WindowListener windowListener
The WindowListener attached to dialog to track opening/closing the dialog.
final JTextComponent input
The map name input field.
static void addAction(@NotNull final JComponent textComponent, @NotNull final Action action)
Adds an accelerator key for a component.
Definition: SwingUtils.java:71