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-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.gomap;
21 
22 import java.awt.BorderLayout;
23 import java.awt.Component;
24 import java.awt.Dialog.ModalityType;
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.List;
34 import java.util.TreeSet;
35 import javax.swing.JComponent;
36 import javax.swing.JDialog;
37 import javax.swing.JList;
38 import javax.swing.JPanel;
39 import javax.swing.JScrollPane;
40 import javax.swing.JTextField;
41 import javax.swing.ListSelectionModel;
42 import javax.swing.ScrollPaneConstants;
43 import javax.swing.SwingUtilities;
44 import javax.swing.border.EmptyBorder;
45 import javax.swing.event.DocumentEvent;
46 import javax.swing.event.DocumentListener;
47 import javax.swing.text.JTextComponent;
60 import net.sf.japi.swing.action.ActionBuilder;
61 import net.sf.japi.swing.action.ActionBuilderFactory;
62 import net.sf.japi.swing.action.ActionMethod;
63 import org.jetbrains.annotations.NotNull;
64 
69 public class GoMapDialog<G extends GameObject<G, A, R>, A extends MapArchObject<A>, R extends Archetype<G, A, R>> {
70 
74  @NotNull
75  private static final ActionBuilder ACTION_BUILDER = ActionBuilderFactory.getInstance().getActionBuilder("net.sf.gridarta");
76 
80  @NotNull
81  private final JDialog dialog;
82 
86  @NotNull
87  private final JTextComponent input;
88 
92  @NotNull
93  private final MapsIndex mapsIndex;
94 
98  @NotNull
100 
104  @NotNull
105  private final GoMapListModel listModel = new GoMapListModel();
106 
110  @NotNull
111  private final JList<MapFile> list = new JList<>(listModel);
112 
116  private boolean dialogShown;
117 
121  @NotNull
122  private final Comparator<MapFile> mapNameComparator = new Comparator<MapFile>() {
123 
124  @Override
125  public int compare(@NotNull final MapFile o1, @NotNull final MapFile o2) {
126  final String name1 = mapsIndex.getName(o1);
127  final String name2 = mapsIndex.getName(o2);
128 
129  if (name1 == null) {
130  //noinspection VariableNotUsedInsideIf
131  return name2 == null ? 0 : -1;
132  }
133 
134  if (name2 == null) {
135  return +1;
136  }
137 
138  final int cmp = name1.compareToIgnoreCase(name2);
139  return cmp == 0 ? o1.getFile().compareTo(o2.getFile()) : cmp;
140  }
141 
142  };
143 
149  @NotNull
151 
152  @Override
153  public void valueAdded(@NotNull final MapFile value) {
154  // ignore
155  }
156 
157  @Override
158  public void valueRemoved(@NotNull final MapFile value) {
159  // ignore
160  }
161 
162  @Override
163  public void nameChanged() {
165  }
166 
167  @Override
168  public void pendingChanged() {
169  // ignore
170  }
171 
172  @Override
173  public void indexingFinished() {
175  }
176 
177  };
178 
185  @NotNull
186  private final WindowListener windowListener = new WindowListener() {
187 
188  @Override
189  public void windowOpened(final WindowEvent e) {
190  if (!dialogShown) {
191  dialogShown = true;
193  doSearch();
194  }
195  }
196 
197  @Override
198  public void windowClosing(final WindowEvent e) {
199  // ignore
200  }
201 
202  @Override
203  public void windowClosed(final WindowEvent e) {
204  if (dialogShown) {
205  dialogShown = false;
207  }
208  }
209 
210  @Override
211  public void windowIconified(final WindowEvent e) {
212  // ignore
213  }
214 
215  @Override
216  public void windowDeiconified(final WindowEvent e) {
217  // ignore
218  }
219 
220  @Override
221  public void windowActivated(final WindowEvent e) {
222  // ignore
223  }
224 
225  @Override
226  public void windowDeactivated(final WindowEvent e) {
227  // ignore
228  }
229 
230  };
231 
236  @NotNull
238 
239  @Override
240  public void change() {
241  if (!dialogShown) {
242  return;
243  }
244 
245  SwingUtilities.invokeLater(() -> {
246  //XXX:suppress incorrect warning
247  if (dialogShown) {
248  doSearch();
249  }
250  });
251  }
252 
253  });
254 
261  public GoMapDialog(@NotNull final Window parent, @NotNull final MapsIndex mapsIndex, @NotNull final MapViewsManager<G, A, R> mapViewsManager) {
262  this.mapsIndex = mapsIndex;
263  this.mapViewsManager = mapViewsManager;
264  final Component label = ActionBuilderUtils.newLabel(ACTION_BUILDER, "goMapLabel");
265 
266  input = new JTextField();
267  SwingUtils.addAction(input, ACTION_BUILDER.createAction(false, "goMapScrollUp", this));
268  SwingUtils.addAction(input, ACTION_BUILDER.createAction(false, "goMapScrollDown", this));
269  SwingUtils.addAction(input, ACTION_BUILDER.createAction(false, "goMapScrollPageUp", this));
270  SwingUtils.addAction(input, ACTION_BUILDER.createAction(false, "goMapScrollPageDown", this));
271  SwingUtils.addAction(input, ACTION_BUILDER.createAction(false, "goMapScrollTop", this));
272  SwingUtils.addAction(input, ACTION_BUILDER.createAction(false, "goMapScrollBottom", this));
273  SwingUtils.addAction(input, ACTION_BUILDER.createAction(false, "goMapSelectUp", this));
274  SwingUtils.addAction(input, ACTION_BUILDER.createAction(false, "goMapSelectDown", this));
275  SwingUtils.addAction(input, ACTION_BUILDER.createAction(false, "goMapCancel", this));
276  SwingUtils.addAction(input, ACTION_BUILDER.createAction(false, "goMapApply", this));
277  final DocumentListener documentListener = new DocumentListener() {
278 
279  @Override
280  public void changedUpdate(@NotNull final DocumentEvent e) {
281  doSearch();
282  }
283 
284  @Override
285  public void insertUpdate(@NotNull final DocumentEvent e) {
286  doSearch();
287  }
288 
289  @Override
290  public void removeUpdate(@NotNull final DocumentEvent e) {
291  doSearch();
292  }
293 
294  };
295  input.getDocument().addDocumentListener(documentListener);
297 
298  final JComponent inputPanel = new JPanel(new BorderLayout());
299  inputPanel.add(label, BorderLayout.NORTH);
300  inputPanel.add(input, BorderLayout.CENTER);
301  inputPanel.setBorder(new EmptyBorder(3, 3, 3, 3));
302 
303  list.setFocusable(false);
304  final Component scrollPane = new JScrollPane(list, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
305  list.setCellRenderer(new MapListCellRenderer(mapsIndex));
306  list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
307  final MouseListener mouseListener = new MouseListener() {
308 
309  @Override
310  public void mouseClicked(final MouseEvent e) {
311  // ignore
312  }
313 
314  @Override
315  public void mousePressed(final MouseEvent e) {
316  if (e.getClickCount() > 1) {
317  goMapApply();
318  }
319  }
320 
321  @Override
322  public void mouseReleased(final MouseEvent e) {
323  // ignore
324  }
325 
326  @Override
327  public void mouseEntered(final MouseEvent e) {
328  // ignore
329  }
330 
331  @Override
332  public void mouseExited(final MouseEvent e) {
333  // ignore
334  }
335 
336  };
337  list.addMouseListener(mouseListener);
338 
339  dialog = new JDialog(parent);
340  dialog.setResizable(false);
341  dialog.setSize(600, 400);
342  dialog.setLocationRelativeTo(parent);
343  dialog.setUndecorated(true);
344  dialog.setLayout(new BorderLayout());
345  dialog.add(inputPanel, BorderLayout.NORTH);
346  dialog.add(scrollPane, BorderLayout.CENTER);
347  dialog.setModalityType(ModalityType.DOCUMENT_MODAL);
348  dialog.addWindowListener(windowListener);
349  }
350 
354  public void showDialog() {
355  dialog.setVisible(true);
356  }
357 
361  private void doSearch() {
362  final String mapName = input.getText();
363  if (mapName.isEmpty()) {
364  listModel.clear();
365  return;
366  }
367 
368  final Collection<MapFile> maps = mapsIndex.findPartialName(mapName);
369  final Collection<MapFile> sortedMaps = new TreeSet<>(mapNameComparator);
370  sortedMaps.addAll(maps);
371  listModel.enable(false);
372  listModel.clear();
373  for (final MapFile map : sortedMaps) {
374  listModel.addElement(map);
375  }
376  listModel.enable(true);
377  list.setSelectedIndex(0);
378  list.ensureIndexIsVisible(0);
379  }
380 
384  @ActionMethod
385  public void goMapApply() {
386  if (goMap()) {
387  dialog.removeWindowListener(windowListener);
388  dialog.dispose();
389  }
390  }
391 
395  @ActionMethod
396  public void goMapCancel() {
397  dialog.removeWindowListener(windowListener);
398  dialog.dispose();
399  }
400 
404  @ActionMethod
405  public void goMapScrollUp() {
406  final int index = list.getMinSelectionIndex();
407  final int newIndex = (index > 0 ? index : listModel.size()) - 1;
408  list.setSelectedIndex(newIndex);
409  list.ensureIndexIsVisible(newIndex);
410  }
411 
415  @ActionMethod
416  public void goMapScrollDown() {
417  final int index = list.getMaxSelectionIndex() + 1;
418  final int newIndex = index < listModel.size() ? index : 0;
419  list.setSelectedIndex(newIndex);
420  list.ensureIndexIsVisible(newIndex);
421  }
422 
426  @ActionMethod
427  public void goMapScrollPageUp() {
428  final int index = list.getMinSelectionIndex();
429  final int firstIndex = list.getFirstVisibleIndex();
430  final int newIndex;
431  if (firstIndex == -1) {
432  newIndex = -1;
433  } else if (index == -1) {
434  newIndex = firstIndex;
435  } else if (index > firstIndex) {
436  newIndex = firstIndex;
437  } else {
438  newIndex = Math.max(firstIndex - (list.getLastVisibleIndex() - firstIndex), 0);
439  }
440  list.setSelectedIndex(newIndex);
441  list.ensureIndexIsVisible(newIndex);
442  }
443 
447  @ActionMethod
448  public void goMapScrollPageDown() {
449  final int index = list.getMaxSelectionIndex();
450  final int lastIndex = list.getLastVisibleIndex();
451  final int newIndex;
452  if (lastIndex == -1) {
453  newIndex = -1;
454  } else if (index == -1) {
455  newIndex = lastIndex;
456  } else if (index < lastIndex) {
457  newIndex = lastIndex;
458  } else {
459  newIndex = Math.min(lastIndex + (lastIndex - list.getFirstVisibleIndex()), listModel.size() - 1);
460  }
461  list.setSelectedIndex(newIndex);
462  list.ensureIndexIsVisible(newIndex);
463  }
464 
468  @ActionMethod
469  public void goMapScrollTop() {
470  final int newIndex = 0;
471  list.setSelectedIndex(newIndex);
472  list.ensureIndexIsVisible(newIndex);
473  }
474 
478  @ActionMethod
479  public void goMapScrollBottom() {
480  final int newIndex = listModel.size() - 1;
481  list.setSelectedIndex(newIndex);
482  list.ensureIndexIsVisible(newIndex);
483  }
484 
488  @ActionMethod
489  public void goMapSelectUp() {
490  final int index = list.getMinSelectionIndex();
491  if (index != 0) {
492  final int newIndex = (index > 0 ? index : listModel.size()) - 1;
493  list.addSelectionInterval(newIndex, newIndex);
494  list.ensureIndexIsVisible(newIndex);
495  }
496  }
497 
501  @ActionMethod
502  public void goMapSelectDown() {
503  final int index = list.getMaxSelectionIndex();
504  if (index + 1 < listModel.size()) {
505  final int newIndex = index + 1;
506  list.addSelectionInterval(newIndex, newIndex);
507  list.ensureIndexIsVisible(newIndex);
508  }
509  }
510 
515  private boolean goMap() {
516  final List<MapFile> selectedValues = list.getSelectedValuesList();
517  boolean result = false;
518  for (final MapFile selectedValue : selectedValues) {
519  try {
520  mapViewsManager.openMapFileWithView(selectedValue, null);
521  result = true;
522  } catch (final IOException ex) {
523  ACTION_BUILDER.showMessageDialog(dialog, "goMapIOException", selectedValue, ex.getMessage());
524  }
525  }
526  return result;
527  }
528 
529 }
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.dialogShown
boolean dialogShown
Whether dialog is currently shown.
Definition: GoMapDialog.java:116
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.goMapSelectUp
void goMapSelectUp()
Action method for select up.
Definition: GoMapDialog.java:489
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.list
final JList< MapFile > list
The JList showing the matching maps.
Definition: GoMapDialog.java:111
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.listModel
final GoMapListModel listModel
The list model containing the search results.
Definition: GoMapDialog.java:105
net.sf.gridarta
Base package of all Gridarta classes.
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.goMapScrollBottom
void goMapScrollBottom()
Action method for scroll bottom.
Definition: GoMapDialog.java:479
net.sf.gridarta.model.index.AbstractIndex.removeIndexListener
void removeIndexListener(@NotNull final IndexListener< V > listener)
Removes an IndexListener to be notified of changes.
Definition: AbstractIndex.java:274
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.goMapApply
void goMapApply()
Action method for apply.
Definition: GoMapDialog.java:385
net.sf
net.sf.gridarta.model.index.AbstractIndex.addIndexListener
void addIndexListener(@NotNull final IndexListener< V > listener)
Adds an IndexListener to be notified of changes.
Definition: AbstractIndex.java:269
net.sf.gridarta.model.mapmodel
Definition: AboveFloorInsertionMode.java:20
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.goMapSelectDown
void goMapSelectDown()
Action method for select down.
Definition: GoMapDialog.java:502
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.doSearch
void doSearch()
Updates the maps display from the map name input field.
Definition: GoMapDialog.java:361
net.sf.gridarta.model.archetype
Definition: AbstractArchetype.java:20
net.sf.gridarta.model.gameobject.GameObject
Reflects a game object (object on a map).
Definition: GameObject.java:36
net.sf.gridarta.utils.ActionBuilderUtils.newLabel
static JLabel newLabel(@NotNull final ActionBuilder actionBuilder, @NotNull final String key)
Creates a new JLabel from a resource key.
Definition: ActionBuilderUtils.java:117
net.sf.gridarta.gui.utils.SwingUtils.addAction
static void addAction(@NotNull final JComponent textComponent, @NotNull final Action action)
Adds an accelerator key for a component.
Definition: SwingUtils.java:71
net.sf.gridarta.gui
Graphical User Interface of Gridarta.
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.windowListener
final WindowListener windowListener
The WindowListener attached to dialog to track opening/closing the dialog.
Definition: GoMapDialog.java:186
net.sf.gridarta.model.gameobject
GameObjects are the objects based on Archetypes found on maps.
Definition: AbstractGameObject.java:20
net
net.sf.gridarta.model.index.AbstractIndex.getName
String getName(@NotNull final V value)
Returns the name associated with a value.
Definition: AbstractIndex.java:233
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.dialog
final JDialog dialog
The JDialog instance.
Definition: GoMapDialog.java:81
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.goMapScrollPageUp
void goMapScrollPageUp()
Action method for scroll page up.
Definition: GoMapDialog.java:427
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.ACTION_BUILDER
static final ActionBuilder ACTION_BUILDER
The ActionBuilder.
Definition: GoMapDialog.java:75
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.goMapScrollTop
void goMapScrollTop()
Action method for scroll top.
Definition: GoMapDialog.java:469
net.sf.gridarta.gui.utils.SwingUtils
Utility class for Swing related functions.
Definition: SwingUtils.java:37
net.sf.gridarta.model.maparchobject.MapArchObject
Interface for MapArchObjects.
Definition: MapArchObject.java:40
net.sf.gridarta.gui.map.mapview
Definition: AbstractMapView.java:20
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.goMapScrollUp
void goMapScrollUp()
Action method for scroll up.
Definition: GoMapDialog.java:405
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.delayedChangeManager
final DelayedChangeManager delayedChangeManager
A DelayedChangeManager for updating search results after {} changes.
Definition: GoMapDialog.java:237
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.goMapCancel
void goMapCancel()
Action method for cancel.
Definition: GoMapDialog.java:396
net.sf.gridarta.model.mapmodel.MapFile
The location of a map file with a map directory.
Definition: MapFile.java:31
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.goMap
boolean goMap()
Opens the selected maps.
Definition: GoMapDialog.java:515
net.sf.gridarta.gui.dialog.gomap.GoMapListModel.enable
void enable(final boolean enabled)
Enables or disables notification of listeners.
Definition: GoMapListModel.java:72
net.sf.gridarta.model.index
Definition: AbstractIndex.java:20
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.showDialog
void showDialog()
Opens the dialog.
Definition: GoMapDialog.java:354
net.sf.gridarta.model
net.sf.gridarta.model.archetype.Archetype
Reflects an Archetype.
Definition: Archetype.java:41
net.sf.gridarta.utils.DelayedChangeListener
Listener for forwarded events of DelayedChangeManager.
Definition: DelayedChangeListener.java:26
net.sf.gridarta.gui.utils.TextComponentUtils.setAutoSelectOnFocus
static void setAutoSelectOnFocus(@NotNull final JTextComponent textComponent)
Selects all text of a JTextComponent when the component gains the focus.
Definition: TextComponentUtils.java:47
net.sf.gridarta.model.index.AbstractIndex.findPartialName
Collection< V > findPartialName(@NotNull final String name)
Returns all matching values for a (possibly partial) key name.
Definition: AbstractIndex.java:104
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.GoMapDialog
GoMapDialog(@NotNull final Window parent, @NotNull final MapsIndex mapsIndex, @NotNull final MapViewsManager< G, A, R > mapViewsManager)
Creates a new instance.
Definition: GoMapDialog.java:261
net.sf.gridarta.gui.map
Base classes for rendering maps.
Definition: AbstractPerMapDialogManager.java:20
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.goMapScrollPageDown
void goMapScrollPageDown()
Action method for scroll page down.
Definition: GoMapDialog.java:448
net.sf.gridarta.utils.DelayedChangeManager.change
void change()
Delivers a change event to the associated DelayedChangeListener.
Definition: DelayedChangeManager.java:208
net.sf.gridarta.model.index.IndexListener
Interface for listeners interested in Index related events.
Definition: IndexListener.java:30
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.indexListener
final IndexListener< MapFile > indexListener
The IndexListener attached to mapsIndex to update search results after index changes.
Definition: GoMapDialog.java:150
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.input
final JTextComponent input
The map name input field.
Definition: GoMapDialog.java:87
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.mapsIndex
final MapsIndex mapsIndex
The MapsIndex for looking up maps.
Definition: GoMapDialog.java:93
net.sf.gridarta.utils.ActionBuilderUtils
Utility class for ActionBuilder related functions.
Definition: ActionBuilderUtils.java:31
net.sf.gridarta.utils.DelayedChangeManager.finish
void finish()
Finishes a series of change events.
Definition: DelayedChangeManager.java:218
net.sf.gridarta.model.index.MapsIndex
Indexes maps by map name.
Definition: MapsIndex.java:28
net.sf.gridarta.model.maparchobject
Definition: AbstractMapArchObject.java:20
net.sf.gridarta.gui.dialog.gomap.GoMapDialog
A dialog to ask the user for a map to open.
Definition: GoMapDialog.java:69
net.sf.gridarta.gui.utils
Definition: AnimationComponent.java:20
net.sf.gridarta.gui.dialog.gomap.MapListCellRenderer
A DefaultListCellRenderer that renders values of a {}.
Definition: MapListCellRenderer.java:34
net.sf.gridarta.gui.map.mapview.MapViewsManager.openMapFileWithView
MapView< G, A, R > openMapFileWithView(@NotNull final MapFile mapFile, @Nullable final Point viewPosition)
Loads a map file and creates a map view.
Definition: MapViewsManager.java:333
net.sf.gridarta.utils.DelayedChangeManager
Helper for reducing the number of change events: calls to change() will be forwarded to DelayedChange...
Definition: DelayedChangeManager.java:32
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.mapViewsManager
final MapViewsManager< G, A, R > mapViewsManager
The MapViewsManager for opening maps.
Definition: GoMapDialog.java:99
net.sf.gridarta.gui.utils.TextComponentUtils
Utility class for JTextComponent related functions.
Definition: TextComponentUtils.java:34
net.sf.gridarta.gui.map.mapview.MapViewsManager
Stores all existing MapViews.
Definition: MapViewsManager.java:47
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.mapNameComparator
final Comparator< MapFile > mapNameComparator
A Comparator that orders map files by map name.
Definition: GoMapDialog.java:122
net.sf.gridarta.utils
Definition: ActionBuilderUtils.java:20
net.sf.gridarta.gui.dialog.gomap.GoMapListModel
A DefaultListModel that can be disabled during updates.
Definition: GoMapListModel.java:29
net.sf.gridarta.gui.dialog.gomap.GoMapDialog.goMapScrollDown
void goMapScrollDown()
Action method for scroll down.
Definition: GoMapDialog.java:416