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

Last change on this file since 36217 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
Line 
1// License: GPL. For details, see LICENSE file.
2package relcontext.actions;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.BorderLayout;
7import java.awt.Dialog.ModalityType;
8import java.awt.Dimension;
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;
14import java.util.ArrayList;
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
29import org.openstreetmap.josm.actions.JosmAction;
30import org.openstreetmap.josm.data.osm.DefaultNameFormatter;
31import org.openstreetmap.josm.data.osm.Relation;
32import org.openstreetmap.josm.gui.MainApplication;
33import org.openstreetmap.josm.gui.PrimitiveRenderer;
34import org.openstreetmap.josm.tools.Logging;
35import org.openstreetmap.josm.tools.Shortcut;
36
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
47 public FindRelationAction(ChosenRelation chRel) {
48 super(tr("Find"), "relcontext/find", tr("Find a relation"),
49 Shortcut.registerShortcut("reltoolbox:find", tr("Relation Toolbox: {0}", tr("Find a relation")),
50 KeyEvent.VK_F, Shortcut.ALT_CTRL), false);
51 this.chRel = chRel;
52 }
53
54 @Override
55 public void actionPerformed(ActionEvent e) {
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();
60 final JList<Relation> relationsList = new JList<>(relationsData);
61 relationsList.setSelectionModel(relationsData.getSelectionModel());
62 relationsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
63 relationsList.setCellRenderer(new PrimitiveRenderer());
64 panel.add(new JScrollPane(relationsList,
65 JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER), BorderLayout.CENTER);
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 };
74 final JDialog dlg = optionPane.createDialog(MainApplication.getMainFrame(), tr("Find a relation"));
75 dlg.setModalityType(ModalityType.DOCUMENT_MODAL);
76
77 relationsList.addMouseListener(new MouseAdapter() {
78 @Override
79 public void mouseClicked(MouseEvent e) {
80 if (e.getClickCount() >= 2 && !relationsList.isSelectionEmpty()) {
81 dlg.setVisible(false);
82 optionPane.setValue(JOptionPane.OK_OPTION);
83 }
84 }
85 });
86
87 searchField.addActionListener(e1 -> {
88 if (!relationsList.isSelectionEmpty()) {
89 dlg.setVisible(false);
90 optionPane.setValue(JOptionPane.OK_OPTION);
91 }
92 });
93
94 searchField.addKeyListener(new KeyAdapter() {
95 @Override
96 public void keyTyped(KeyEvent e) {
97 SwingUtilities.invokeLater(() -> updateRelationData(relationsData, searchField.getText()));
98 }
99
100 @Override
101 public void keyPressed(KeyEvent e) {
102 if (shouldForward(e)) {
103 relationsList.dispatchEvent(e);
104 }
105 }
106
107 @Override
108 public void keyReleased(KeyEvent e) {
109 if (shouldForward(e)) {
110 relationsList.dispatchEvent(e);
111 }
112 }
113
114 private boolean shouldForward(KeyEvent e) {
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();
125 dlg.dispose();
126
127 if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE
128 || (answer instanceof Integer && (Integer) answer != JOptionPane.OK_OPTION))
129 return;
130
131 Relation r = relationsList.getSelectedValue();
132 if (r != null) {
133 chRel.set(r);
134 }
135 }
136
137 @Override
138 protected void updateEnabledState() {
139 setEnabled(getLayerManager().getEditDataSet() != null);
140 }
141
142 protected void updateRelationData(FindRelationListModel data, String filter) {
143 String[] keywords = filter == null ? new String[0] : filter.split("\\s+");
144 if (keywords.length > 0) {
145 List<String> filteredKeywords = new ArrayList<>(keywords.length);
146 for (String s : keywords) {
147 if (s.length() > 0) {
148 filteredKeywords.add(s.trim().toLowerCase());
149 }
150 }
151 keywords = filteredKeywords.toArray(new String[0]);
152 }
153
154 if (Logging.isDebugEnabled()) {
155 Logging.debug("keywords.length = " + keywords.length);
156 for (int i = 0; i < keywords.length; i++) {
157 Logging.debug("keyword["+i+"] = " + keywords[i]);
158 }
159 }
160
161 List<Relation> relations = new ArrayList<>();
162 if (getLayerManager().getEditLayer() != null) {
163 for (Relation r : getLayerManager().getEditLayer().data.getRelations()) {
164 if (!r.isDeleted() && r.isVisible() && !r.isIncomplete()) {
165 boolean add = true;
166 for (int i = 0; i < keywords.length && add; i++) {
167 boolean ok = false;
168 if (String.valueOf(r.getPrimitiveId().getUniqueId()).contains(keywords[i])) {
169 ok = true;
170 } else {
171 for (String key : r.keySet()) {
172 if (key.contains(keywords[i]) || r.get(key).toLowerCase().contains(keywords[i])
173 || safetr(r.get(key)).toLowerCase().contains(keywords[i])) {
174 ok = true;
175 break;
176 }
177 }
178 }
179 if (!ok) {
180 add = false;
181 }
182 }
183 if (add) {
184 relations.add(r);
185 }
186 }
187 }
188 }
189
190 relations.sort(DefaultNameFormatter.getInstance().getRelationComparator());
191 data.setRelations(relations);
192 }
193
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
203 /**
204 * I admit, some of it was copypasted from {@link org.openstreetmap.josm.gui.dialogs.RelationListDialog.RelationListModel}.
205 */
206 protected static class FindRelationListModel extends AbstractListModel<Relation> {
207 private final ArrayList<Relation> relations = new ArrayList<>();
208 private final DefaultListSelectionModel selectionModel;
209
210 public FindRelationListModel(DefaultListSelectionModel selectionModel) {
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
223 @Override
224 public int getSize() {
225 return relations.size();
226 }
227
228 @Override
229 public Relation getElementAt(int index) {
230 return relations.get(index);
231 }
232
233 public void setRelations(Collection<Relation> relations) {
234 int selectedIndex = selectionModel.getMinSelectionIndex();
235 Relation sel = selectedIndex < 0 ? null : getElementAt(selectedIndex);
236
237 this.relations.clear();
238 selectionModel.clearSelection();
239 if (relations != null) {
240 this.relations.addAll(relations);
241 }
242 fireIntervalAdded(this, 0, getSize());
243
244 if (sel != null) {
245 selectedIndex = this.relations.indexOf(sel);
246 if (selectedIndex >= 0) {
247 selectionModel.addSelectionInterval(selectedIndex, selectedIndex);
248 }
249 }
250 if (selectionModel.isSelectionEmpty() && !this.relations.isEmpty()) {
251 selectionModel.addSelectionInterval(0, 0);
252 }
253 }
254 }
255}
Note: See TracBrowser for help on using the repository browser.