Gridarta Editor
FindArchetypesDialog.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.findarchetypes;
21 
22 import java.awt.Component;
23 import java.awt.GridBagConstraints;
24 import java.awt.GridBagLayout;
25 import java.awt.Rectangle;
26 import java.awt.event.MouseAdapter;
27 import java.awt.event.MouseEvent;
28 import java.awt.event.MouseListener;
29 import javax.swing.JButton;
30 import javax.swing.JDialog;
31 import javax.swing.JOptionPane;
32 import javax.swing.JPanel;
33 import javax.swing.JScrollPane;
34 import javax.swing.JTable;
35 import javax.swing.JTextField;
36 import javax.swing.JViewport;
37 import javax.swing.ListSelectionModel;
38 import javax.swing.ScrollPaneConstants;
39 import javax.swing.WindowConstants;
40 import javax.swing.event.DocumentEvent;
41 import javax.swing.event.DocumentListener;
42 import javax.swing.event.ListSelectionEvent;
43 import javax.swing.event.ListSelectionListener;
44 import javax.swing.text.JTextComponent;
53 import net.sf.japi.swing.action.ActionBuilder;
54 import net.sf.japi.swing.action.ActionBuilderFactory;
55 import net.sf.japi.swing.action.ActionMethod;
56 import org.jetbrains.annotations.NotNull;
57 import org.jetbrains.annotations.Nullable;
58 
63 public class FindArchetypesDialog<G extends GameObject<G, A, R>, A extends MapArchObject<A>, R extends Archetype<G, A, R>> {
64 
68  private static final int MINIMUM_AUTO_SEARCH_LENGTH = 3;
69 
73  @NotNull
74  private static final ActionBuilder ACTION_BUILDER = ActionBuilderFactory.getInstance().getActionBuilder("net.sf.gridarta");
75 
79  @NotNull
81 
85  @NotNull
87 
91  @NotNull
92  private final JTextComponent nameField = new JTextField();
93 
97  @NotNull
99 
103  @NotNull
104  private final JTable resultTable;
105 
110  @NotNull
111  private final JScrollPane scrollPane;
112 
116  @NotNull
117  private final JDialog dialog;
118 
122  @NotNull
123  private String previousSearch = "";
124 
134  public FindArchetypesDialog(@NotNull final Component parent, @NotNull final ArchetypeChooserControl<G, A, R> archetypeChooserControl, @NotNull final ObjectChooser<G, A, R> objectChooser, @NotNull final ArchetypeTypeSet archetypeTypeSet) {
135  this.archetypeChooserControl = archetypeChooserControl;
136  this.objectChooser = objectChooser;
137 
138  final JPanel panel = new JPanel(new GridBagLayout());
139 
140  SwingUtils.addAction(nameField, ACTION_BUILDER.createAction(false, "findArchetypesScrollUp", this));
141  SwingUtils.addAction(nameField, ACTION_BUILDER.createAction(false, "findArchetypesScrollDown", this));
142  SwingUtils.addAction(nameField, ACTION_BUILDER.createAction(false, "findArchetypesFindArchetype", this));
143 
144  final DocumentListener documentListener = new DocumentListener() {
145 
146  @Override
147  public void changedUpdate(@NotNull final DocumentEvent e) {
148  doSearch(false);
149  }
150 
151  @Override
152  public void insertUpdate(@NotNull final DocumentEvent e) {
153  doSearch(false);
154  }
155 
156  @Override
157  public void removeUpdate(@NotNull final DocumentEvent e) {
158  doSearch(false);
159  }
160 
161  };
162  nameField.getDocument().addDocumentListener(documentListener);
163 
164  resultTableModel = new TableModel<>(archetypeTypeSet);
165  resultTable = new JTable(resultTableModel);
166  resultTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
167  resultTable.setRowSelectionAllowed(true);
168  resultTable.setColumnSelectionAllowed(false);
169  final ListSelectionListener listSelectionListener = new ListSelectionListener() {
170 
171  @Override
172  public void valueChanged(final ListSelectionEvent e) {
174  }
175 
176  };
177  resultTable.getSelectionModel().addListSelectionListener(listSelectionListener);
178  //noinspection RefusedBequest
179  final MouseListener mouseListener = new MouseAdapter() {
180 
181  @Override
182  public void mousePressed(final MouseEvent e) {
184  if (e.getClickCount() > 1) {
186  }
187  }
188 
189  };
190  resultTable.addMouseListener(mouseListener);
191  scrollPane = new JScrollPane(resultTable);
192  scrollPane.getViewport().setScrollMode(JViewport.SIMPLE_SCROLL_MODE);
193  scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
194  scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
195 
196  final GridBagConstraints gbc = new GridBagConstraints();
197  gbc.gridx = 0;
198  gbc.gridy = 0;
199  panel.add(ActionBuilderUtils.newLabel(ACTION_BUILDER, "findArchetypesName"), gbc);
200  gbc.gridx = 1;
201  gbc.gridy = 0;
202  gbc.fill = GridBagConstraints.HORIZONTAL;
203  gbc.weightx = 1.0;
204  panel.add(nameField, gbc);
205  gbc.gridx = 0;
206  gbc.gridy = 1;
207  gbc.gridwidth = 2;
208  gbc.fill = GridBagConstraints.BOTH;
209  gbc.weighty = 1.0;
210  panel.add(scrollPane, gbc);
211 
212  final JButton searchButton = new JButton(ACTION_BUILDER.createAction(false, "findArchetypesSearch", this));
213  final JButton closeButton = new JButton(ACTION_BUILDER.createAction(false, "findArchetypesClose", this));
214  final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.PLAIN_MESSAGE, JOptionPane.DEFAULT_OPTION, null, new JButton[] { searchButton, closeButton, }, nameField);
215  dialog = optionPane.createDialog(parent, ActionBuilderUtils.getString(ACTION_BUILDER, "findArchetypesTitle"));
216  dialog.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
217  dialog.setModal(false);
218  dialog.setResizable(true);
219  dialog.setSize(500, 250);
220  dialog.setLocationRelativeTo(parent);
221  }
222 
226  public void show() {
227  scrollPane.getVerticalScrollBar().setValue(0);
228 
229  if (dialog.isShowing()) {
230  dialog.toFront();
231  } else {
232  nameField.setText("");
233  resultTable.clearSelection();
234  try {
235  resultTableModel.clear();
236  } finally {
237  resultTableModel.finishUpdate();
238  }
239  dialog.setVisible(true);
240  }
241 
242  nameField.selectAll();
243  nameField.requestFocusInWindow();
244  }
245 
249  @ActionMethod
250  public void findArchetypesSearch() {
251  previousSearch = "";
252  doSearch(true);
253  nameField.selectAll();
254  }
255 
262  private void doSearch(final boolean force) {
263  @Nullable final R selectedArchetype;
264  try {
265  resultTableModel.clear();
266  final String name = nameField.getText();
267  if (name.length() <= 0 || name.equals(previousSearch)) {
268  return;
269  }
270  if (!force && name.length() < MINIMUM_AUTO_SEARCH_LENGTH) {
271  return;
272  }
273  previousSearch = name;
274 
275  final CharSequence lowerCaseName = name.toLowerCase();
276  R exactArchetypeNameMatch = null;
277  R exactDisplayNameMatch = null;
278  for (final R archetype : archetypeChooserControl) {
279  if (!archetype.isTail()) {
280  final String archetypeName = archetype.getArchetypeName();
281  final String objName = archetype.getObjName();
282  if (archetypeName.toLowerCase().contains(lowerCaseName) || objName.toLowerCase().contains(lowerCaseName)) {
283  if (exactArchetypeNameMatch != null) {
284  // ignore
285  } else if (archetypeName.equals(name)) {
286  exactArchetypeNameMatch = archetype;
287  } else if (exactDisplayNameMatch != null) {
288  // ignore
289  } else if (objName.equals(name)) {
290  exactDisplayNameMatch = archetype;
291  }
292  resultTableModel.add(archetype);
293  }
294  }
295  }
296 
297  if (exactArchetypeNameMatch != null) {
298  selectedArchetype = exactArchetypeNameMatch;
299  } else if (exactDisplayNameMatch != null) {
300  selectedArchetype = exactDisplayNameMatch;
301  } else {
302  selectedArchetype = null;
303  }
304 
305  resultTableModel.sortTable();
306  } finally {
307  resultTableModel.finishUpdate();
308  }
309 
310  final int index = resultTableModel.findTableIndex(selectedArchetype);
311  if (index != -1) {
312  selectRow(index);
313  }
314  }
315 
319  public void findArchetypesClose() {
320  dialog.setVisible(false);
321  }
322 
327  private void highlightSelectedEntry() {
328  final int index = resultTable.getSelectedRow();
329  if (index == -1) {
330  return;
331  }
332 
333  final R archetype = resultTableModel.get(index);
334  objectChooser.moveArchetypeChooserToFront();
335  archetypeChooserControl.selectArchetype(archetype);
336  }
337 
341  @ActionMethod
342  public void findArchetypesScrollUp() {
343  final int index = resultTable.getSelectedRow();
344  if (index > 0) {
345  selectRow(index - 1);
346  }
347  }
348 
352  @ActionMethod
353  public void findArchetypesScrollDown() {
354  final int index = resultTable.getSelectedRow();
355  if (index != -1 && index + 1 < resultTableModel.getRowCount()) {
356  selectRow(index + 1);
357  }
358  }
359 
364  @ActionMethod
366  previousSearch = "";
367  doSearch(true);
368  nameField.selectAll();
369  }
370 
375  private void selectRow(final int index) {
376  resultTable.setRowSelectionInterval(index, index);
377  resultTable.scrollRectToVisible(new Rectangle(resultTable.getCellRect(index, 0, true)));
378  }
379 
380 }
final JScrollPane scrollPane
The scroll pane which contains the search results table resultTable.
void sortTable()
Sort the table contents by name.
Graphical User Interface of Gridarta.
void highlightSelectedEntry()
Highlights the selected row from resultTable in the insertion object chooser.
final ObjectChooser< G, A, R > objectChooser
The insertion object chooser to use when selecting search results.
Reading and writing of Atrinik maps.
Manages ArchetypeType instances, list, and bitmask definitions.
R get(final int index)
Return one archetype.
void doSearch(final boolean force)
Searches for the current name.
void clear()
Clear the model&#39;s contents.
void findArchetypesScrollDown()
Action method to scroll down one line in the result table.
void moveArchetypeChooserToFront()
Move the Archetype Chooser in front of the Pickmap Chooser.
Utility class for Swing related functions.
Definition: SwingUtils.java:37
void add(@NotNull final R archetype)
Add an archetype to the model.
static String getString(@NotNull final ActionBuilder actionBuilder, @NotNull final String key, @NotNull final String defaultValue)
Returns the value of a key.
static final int MINIMUM_AUTO_SEARCH_LENGTH
Do not perform an auto-search until the input name reaches this length.
void findArchetypesFindArchetype()
Action method to search for the archetype, ignoring MINIMUM_AUTO_SEARCH_LENGTH.
Base package of all Gridarta classes.
Reflects a game object (object on a map).
Definition: GameObject.java:36
void selectRow(final int index)
Selects one row in the result table.
final ArchetypeChooserControl< G, A, R > archetypeChooserControl
The archetype set to search.
GameObjects are the objects based on Archetypes found on maps.
String previousSearch
The previously processed search string.
void selectArchetype(@NotNull final R archetype)
Select an archetype.
final TableModel< G, A, R > resultTableModel
The table model for the search results table resultTable.
void finishUpdate()
Finish updating the model&#39;s contents.
Utility class for ActionBuilder related functions.
FindArchetypesDialog(@NotNull final Component parent, @NotNull final ArchetypeChooserControl< G, A, R > archetypeChooserControl, @NotNull final ObjectChooser< G, A, R > objectChooser, @NotNull final ArchetypeTypeSet archetypeTypeSet)
Creates a new instance.
int findTableIndex(@Nullable final R archetype)
Return the row index of an archetype.
static JLabel newLabel(@NotNull final ActionBuilder actionBuilder, @NotNull final String key)
Creates a new JLabel from a resource key.
Common base interface for ObjectChoosers.
void findArchetypesScrollUp()
Action method to scroll up one line in the result table.
Defines types of GameObjects with corresponding attributes.
static void addAction(@NotNull final JComponent textComponent, @NotNull final Action action)
Adds an accelerator key for a component.
Definition: SwingUtils.java:71