source: osm/applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/FindRelationAction.java

Last change on this file was 36217, checked in by GerdP, 23 months ago

fix #23521: fix some memory leaks

  • dispose dialogs
  • either avoid to create clones of ways or relations or use setNodes(null) / setMembers(null)
  • replaces most ChangeCommand instances by better specialized alternatives
  • add some comments
  • fix some checkstyle / sonar issues
File size: 9.3 KB
RevLine 
[32395]1// License: GPL. For details, see LICENSE file.
[25677]2package relcontext.actions;
3
[32395]4import static org.openstreetmap.josm.tools.I18n.tr;
5
[25677]6import java.awt.BorderLayout;
7import java.awt.Dialog.ModalityType;
8import java.awt.Dimension;
[32395]9import java.awt.event.ActionEvent;
10import java.awt.event.KeyAdapter;
11import java.awt.event.KeyEvent;
12import java.awt.event.MouseAdapter;
13import java.awt.event.MouseEvent;
[25677]14import java.util.ArrayList;
[32395]15import java.util.Collection;
16import java.util.List;
17
18import javax.swing.AbstractListModel;
19import javax.swing.DefaultListSelectionModel;
20import javax.swing.JDialog;
21import javax.swing.JList;
22import javax.swing.JOptionPane;
23import javax.swing.JPanel;
24import javax.swing.JScrollPane;
25import javax.swing.JTextField;
26import javax.swing.ListSelectionModel;
27import javax.swing.SwingUtilities;
28
[25677]29import org.openstreetmap.josm.actions.JosmAction;
[33530]30import org.openstreetmap.josm.data.osm.DefaultNameFormatter;
[25677]31import org.openstreetmap.josm.data.osm.Relation;
[34551]32import org.openstreetmap.josm.gui.MainApplication;
[34130]33import org.openstreetmap.josm.gui.PrimitiveRenderer;
[33530]34import org.openstreetmap.josm.tools.Logging;
[25717]35import org.openstreetmap.josm.tools.Shortcut;
[32395]36
[25677]37import relcontext.ChosenRelation;
38
39/**
40 * Opens a list of all relations with keyword search field. Choose selected relation.
41 *
42 * @author Zverik
43 */
44public class FindRelationAction extends JosmAction {
45 protected ChosenRelation chRel;
46
[32395]47 public FindRelationAction(ChosenRelation chRel) {
[28805]48 super(tr("Find"), "relcontext/find", tr("Find a relation"),
[25717]49 Shortcut.registerShortcut("reltoolbox:find", tr("Relation Toolbox: {0}", tr("Find a relation")),
[32395]50 KeyEvent.VK_F, Shortcut.ALT_CTRL), false);
[25677]51 this.chRel = chRel;
52 }
53
[32395]54 @Override
55 public void actionPerformed(ActionEvent e) {
[25677]56 JPanel panel = new JPanel(new BorderLayout());
57 final JTextField searchField = new JTextField();
58 panel.add(searchField, BorderLayout.NORTH);
59 final FindRelationListModel relationsData = new FindRelationListModel();
[30532]60 final JList<Relation> relationsList = new JList<>(relationsData);
[25677]61 relationsList.setSelectionModel(relationsData.getSelectionModel());
62 relationsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
[34130]63 relationsList.setCellRenderer(new PrimitiveRenderer());
[32398]64 panel.add(new JScrollPane(relationsList,
65 JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER), BorderLayout.CENTER);
[25677]66 panel.setPreferredSize(new Dimension(400, 400));
67
68 final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION) {
69 @Override
70 public void selectInitialValue() {
71 searchField.requestFocusInWindow();
72 }
73 };
[34551]74 final JDialog dlg = optionPane.createDialog(MainApplication.getMainFrame(), tr("Find a relation"));
[25677]75 dlg.setModalityType(ModalityType.DOCUMENT_MODAL);
76
77 relationsList.addMouseListener(new MouseAdapter() {
78 @Override
[32395]79 public void mouseClicked(MouseEvent e) {
80 if (e.getClickCount() >= 2 && !relationsList.isSelectionEmpty()) {
[25677]81 dlg.setVisible(false);
82 optionPane.setValue(JOptionPane.OK_OPTION);
83 }
84 }
85 });
86
[36102]87 searchField.addActionListener(e1 -> {
88 if (!relationsList.isSelectionEmpty()) {
89 dlg.setVisible(false);
90 optionPane.setValue(JOptionPane.OK_OPTION);
[25677]91 }
92 });
93
94 searchField.addKeyListener(new KeyAdapter() {
95 @Override
[32395]96 public void keyTyped(KeyEvent e) {
[36102]97 SwingUtilities.invokeLater(() -> updateRelationData(relationsData, searchField.getText()));
[25677]98 }
99
100 @Override
[32395]101 public void keyPressed(KeyEvent e) {
[32398]102 if (shouldForward(e)) {
[25677]103 relationsList.dispatchEvent(e);
[32395]104 }
[25677]105 }
106
107 @Override
[32395]108 public void keyReleased(KeyEvent e) {
[32398]109 if (shouldForward(e)) {
[25677]110 relationsList.dispatchEvent(e);
[32395]111 }
[25677]112 }
113
[32395]114 private boolean shouldForward(KeyEvent e) {
[25677]115 return e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_DOWN
116 || e.getKeyCode() == KeyEvent.VK_PAGE_DOWN || e.getKeyCode() == KeyEvent.VK_PAGE_UP
117 || e.getKeyCode() == KeyEvent.VK_HOME || e.getKeyCode() == KeyEvent.VK_END;
118 }
119 });
120
121 updateRelationData(relationsData, null);
122 dlg.setVisible(true);
123
124 Object answer = optionPane.getValue();
[36217]125 dlg.dispose();
126
[32395]127 if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE
[32398]128 || (answer instanceof Integer && (Integer) answer != JOptionPane.OK_OPTION))
[25677]129 return;
130
[32395]131 Relation r = relationsList.getSelectedValue();
[32398]132 if (r != null) {
[25677]133 chRel.set(r);
[32395]134 }
[25677]135 }
136
137 @Override
138 protected void updateEnabledState() {
[32398]139 setEnabled(getLayerManager().getEditDataSet() != null);
[25677]140 }
141
[32395]142 protected void updateRelationData(FindRelationListModel data, String filter) {
[25677]143 String[] keywords = filter == null ? new String[0] : filter.split("\\s+");
[32395]144 if (keywords.length > 0) {
[30737]145 List<String> filteredKeywords = new ArrayList<>(keywords.length);
[32398]146 for (String s : keywords) {
147 if (s.length() > 0) {
[25677]148 filteredKeywords.add(s.trim().toLowerCase());
[32395]149 }
[32398]150 }
[25677]151 keywords = filteredKeywords.toArray(new String[0]);
152 }
153
[33530]154 if (Logging.isDebugEnabled()) {
155 Logging.debug("keywords.length = " + keywords.length);
[32398]156 for (int i = 0; i < keywords.length; i++) {
[33530]157 Logging.debug("keyword["+i+"] = " + keywords[i]);
[32398]158 }
[32395]159 }
[25677]160
[30737]161 List<Relation> relations = new ArrayList<>();
[32398]162 if (getLayerManager().getEditLayer() != null) {
163 for (Relation r : getLayerManager().getEditLayer().data.getRelations()) {
[32395]164 if (!r.isDeleted() && r.isVisible() && !r.isIncomplete()) {
[25677]165 boolean add = true;
[32395]166 for (int i = 0; i < keywords.length && add; i++) {
[25677]167 boolean ok = false;
[32398]168 if (String.valueOf(r.getPrimitiveId().getUniqueId()).contains(keywords[i])) {
[25677]169 ok = true;
[32395]170 } else {
171 for (String key : r.keySet()) {
172 if (key.contains(keywords[i]) || r.get(key).toLowerCase().contains(keywords[i])
[35196]173 || safetr(r.get(key)).toLowerCase().contains(keywords[i])) {
[25677]174 ok = true;
175 break;
176 }
177 }
178 }
[32398]179 if (!ok) {
[32395]180 add = false;
181 }
[25677]182 }
[32398]183 if (add) {
[25677]184 relations.add(r);
[32395]185 }
[25677]186 }
187 }
188 }
189
[36102]190 relations.sort(DefaultNameFormatter.getInstance().getRelationComparator());
[25677]191 data.setRelations(relations);
192 }
193
[35196]194 private static String safetr(String s) {
195 try {
196 return tr(s);
197 } catch (IllegalArgumentException e) {
198 Logging.trace(e);
199 return s;
200 }
201 }
202
[25677]203 /**
204 * I admit, some of it was copypasted from {@link org.openstreetmap.josm.gui.dialogs.RelationListDialog.RelationListModel}.
205 */
[33265]206 protected static class FindRelationListModel extends AbstractListModel<Relation> {
[30737]207 private final ArrayList<Relation> relations = new ArrayList<>();
[36102]208 private final DefaultListSelectionModel selectionModel;
[25677]209
[32395]210 public FindRelationListModel(DefaultListSelectionModel selectionModel) {
[25677]211 super();
212 this.selectionModel = selectionModel;
213 }
214
215 public FindRelationListModel() {
216 this(new DefaultListSelectionModel());
217 }
218
219 public DefaultListSelectionModel getSelectionModel() {
220 return selectionModel;
221 }
222
[30532]223 @Override
[25677]224 public int getSize() {
225 return relations.size();
226 }
227
[30532]228 @Override
[32395]229 public Relation getElementAt(int index) {
[30532]230 return relations.get(index);
[25677]231 }
232
233 public void setRelations(Collection<Relation> relations) {
234 int selectedIndex = selectionModel.getMinSelectionIndex();
[32398]235 Relation sel = selectedIndex < 0 ? null : getElementAt(selectedIndex);
[32395]236
[25677]237 this.relations.clear();
238 selectionModel.clearSelection();
[32398]239 if (relations != null) {
[25677]240 this.relations.addAll(relations);
[32395]241 }
[25677]242 fireIntervalAdded(this, 0, getSize());
243
[32395]244 if (sel != null) {
[25677]245 selectedIndex = this.relations.indexOf(sel);
[32398]246 if (selectedIndex >= 0) {
[25677]247 selectionModel.addSelectionInterval(selectedIndex, selectedIndex);
[32395]248 }
[25677]249 }
[32398]250 if (selectionModel.isSelectionEmpty() && !this.relations.isEmpty()) {
[25677]251 selectionModel.addSelectionInterval(0, 0);
[32395]252 }
[25677]253 }
254 }
255}
Note: See TracBrowser for help on using the repository browser.