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

Last change on this file since 33311 was 33265, checked in by donvip, 8 years ago

fix #josm14386 - StackOverflowError

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