source: osm/applications/editors/josm/plugins/utilsplugin2/src/org/openstreetmap/josm/plugins/utilsplugin2/multitagger/MultiTagDialog.java@ 35476

Last change on this file since 35476 was 35476, checked in by gerdp, 4 years ago

fix #josm19313: use getActiveDataSet() instead of getEditDataSet() where appropriate
minor other improvements (errorprone, sonarlint, deprecations)

File size: 15.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.plugins.utilsplugin2.multitagger;
3
4import static org.openstreetmap.josm.tools.I18n.marktr;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.awt.Color;
8import java.awt.Component;
9import java.awt.Dimension;
10import java.awt.GridBagLayout;
11import java.awt.event.ActionEvent;
12import java.awt.event.ItemEvent;
13import java.awt.event.ItemListener;
14import java.awt.event.KeyEvent;
15import java.awt.event.MouseAdapter;
16import java.awt.event.MouseEvent;
17import java.util.ArrayList;
18import java.util.Arrays;
19import java.util.Collection;
20import java.util.Collections;
21import java.util.LinkedList;
22import java.util.List;
23
24import javax.swing.AbstractAction;
25import javax.swing.BoxLayout;
26import javax.swing.JButton;
27import javax.swing.JComponent;
28import javax.swing.JLabel;
29import javax.swing.JPanel;
30import javax.swing.JPopupMenu;
31import javax.swing.JScrollPane;
32import javax.swing.JTable;
33import javax.swing.JToggleButton;
34import javax.swing.KeyStroke;
35import javax.swing.ListSelectionModel;
36import javax.swing.UIManager;
37import javax.swing.event.ListSelectionEvent;
38import javax.swing.event.ListSelectionListener;
39import javax.swing.table.DefaultTableCellRenderer;
40
41import org.openstreetmap.josm.actions.AutoScaleAction;
42import org.openstreetmap.josm.actions.search.SearchAction;
43import org.openstreetmap.josm.data.osm.DataSelectionListener;
44import org.openstreetmap.josm.data.osm.OsmPrimitive;
45import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
46import org.openstreetmap.josm.data.osm.search.SearchMode;
47import org.openstreetmap.josm.data.preferences.NamedColorProperty;
48import org.openstreetmap.josm.gui.ExtendedDialog;
49import org.openstreetmap.josm.gui.MainApplication;
50import org.openstreetmap.josm.gui.layer.OsmDataLayer;
51import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingTextField;
52import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
53import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager;
54import org.openstreetmap.josm.gui.util.HighlightHelper;
55import org.openstreetmap.josm.gui.util.TableHelper;
56import org.openstreetmap.josm.gui.util.WindowGeometry;
57import org.openstreetmap.josm.gui.widgets.HistoryComboBox;
58import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
59import org.openstreetmap.josm.spi.preferences.Config;
60import org.openstreetmap.josm.tools.GBC;
61import org.openstreetmap.josm.tools.ImageProvider;
62import org.openstreetmap.josm.tools.Logging;
63
64/**
65 * Dialog for editing multiple object tags
66 */
67public class MultiTagDialog extends ExtendedDialog implements DataSelectionListener {
68
69 private final MultiTaggerTableModel tableModel = new MultiTaggerTableModel();
70 private final JTable tbl;
71
72 private final HighlightHelper highlightHelper = new HighlightHelper();
73 private final HistoryComboBox cbTagSet = new HistoryComboBox();
74 private List<OsmPrimitive> currentSelection;
75
76 private static final String HISTORY_KEY = "utilsplugin2.multitaghistory";
77 String[] defaultHistory = {"addr:street, addr:housenumber, building, ${area}",
78 "highway, name, ${id}, ${length}",
79 "name name:en name:ru name:de"};
80
81 public MultiTagDialog() {
82 super(MainApplication.getMainFrame(), tr("Edit tags"), new String[]{tr("Ok"), tr("Cancel")}, false);
83 JPanel pnl = new JPanel(new GridBagLayout());
84 tbl = createTable();
85
86 cbTagSet.addItemListener(tagSetChanger);
87 cbTagSet.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
88 .put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true), "applyTagSet");
89 cbTagSet.getActionMap().put("applyTagSet", tagSetChanger);
90
91 tbl.addMouseListener(new PopupMenuLauncher(createPopupMenu()));
92
93 pnl.add(cbTagSet, GBC.std().fill(GBC.HORIZONTAL));
94 pnl.add(new JButton(new DeleteFromHistoryAction()), GBC.std());
95 pnl.add(new JButton(new FindMatchingAction()), GBC.std());
96 final JToggleButton jt = new JToggleButton("", ImageProvider.get("restart"), true);
97 jt.setToolTipText(tr("Sync with JOSM selection"));
98 jt.addActionListener(e -> tableModel.setWatchSelection(jt.isSelected()));
99 pnl.add(jt, GBC.eol());
100
101 pnl.add(createTypeFilterPanel(), GBC.eol().fill(GBC.HORIZONTAL));
102 pnl.add(tbl.getTableHeader(), GBC.eop().fill(GBC.HORIZONTAL));
103
104 pnl.add(new JScrollPane(tbl), GBC.eol().fill(GBC.BOTH));
105 setContent(pnl);
106 setDefaultButton(-1);
107 loadHistory();
108
109 WindowGeometry defaultGeometry = WindowGeometry.centerInWindow(MainApplication.getMainFrame(), new Dimension(500, 500));
110 setRememberWindowGeometry(getClass().getName() + ".geometry", defaultGeometry);
111 }
112
113 private JTable createTable() {
114 JTable t = new JTable(tableModel);
115 tableModel.setTable(t);
116 t.setFillsViewportHeight(true);
117 t.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
118 t.addMouseListener(tableMouseAdapter);
119 t.setRowSelectionAllowed(true);
120 t.setColumnSelectionAllowed(true);
121 t.setDefaultRenderer(OsmPrimitiveType.class, new PrimitiveTypeIconRenderer());
122 t.setDefaultRenderer(String.class, new ColoredRenderer());
123 t.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
124 t.getSelectionModel().addListSelectionListener(selectionListener);
125 return t;
126 }
127
128 private JPanel createTypeFilterPanel() {
129 JPanel p = new JPanel();
130 p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
131 for (final OsmPrimitiveType type: OsmPrimitiveType.values()) {
132 final JToggleButton jt = new JToggleButton("", ImageProvider.get(type), true);
133 jt.addActionListener(e -> {
134 if (jt.isSelected())
135 tableModel.shownTypes.add(type);
136 else
137 tableModel.shownTypes.remove(type);
138 tableModel.updateData(MainApplication.getLayerManager().getEditDataSet().getSelected());
139 });
140 ImageProvider.get(type);
141 p.add(jt);
142 }
143 return p;
144 }
145
146 private void loadHistory() {
147 List<String> cmtHistory = new LinkedList<>(
148 Config.getPref().getList(HISTORY_KEY, Arrays.asList(defaultHistory)));
149 Collections.reverse(cmtHistory);
150 cbTagSet.setPossibleItems(cmtHistory);
151 String s = cmtHistory.get(cmtHistory.size()-1);
152 cbTagSet.setText(s);
153 specifyTagSet(s);
154 }
155
156 @Override
157 protected void buttonAction(int buttonIndex, ActionEvent evt) {
158 highlightHelper.clear();
159 tbl.getSelectionModel().removeListSelectionListener(selectionListener);
160 super.buttonAction(buttonIndex, evt);
161 }
162
163 @Override
164 public void selectionChanged(SelectionChangeEvent event) {
165 tableModel.selectionChanged(event);
166 }
167
168 void doSelectionChanged(Collection<? extends OsmPrimitive> newSelection) {
169 tableModel.doSelectionChanged(newSelection);
170 }
171
172 /*private OsmPrimitive getSelectedPrimitive() {
173 int idx = tbl.getSelectedRow();
174 if (idx>= 0) {
175 return tableModel.getPrimitiveAt(tbl.convertRowIndexToModel(idx));
176 } else {
177 return null;
178 }
179 }*/
180
181 private final MouseAdapter tableMouseAdapter = new MouseAdapter() {
182 @Override
183 public void mouseClicked(MouseEvent e) {
184 if (e.getClickCount() > 1 && MainApplication.isDisplayingMapView()) {
185 AutoScaleAction.zoomTo(currentSelection);
186 }
187 }
188
189 };
190
191 private final ListSelectionListener selectionListener = new ListSelectionListener() {
192 @Override
193 public void valueChanged(ListSelectionEvent e) {
194 currentSelection = getSelectedPrimitives();
195 if (currentSelection != null && MainApplication.isDisplayingMapView()) {
196 if (highlightHelper.highlightOnly(currentSelection)) {
197 MainApplication.getMap().mapView.repaint();
198 }
199 }
200 }
201 };
202
203 public List<OsmPrimitive> getSelectedPrimitives() {
204 ArrayList<OsmPrimitive> sel = new ArrayList<>(100);
205 for (int idx: tbl.getSelectedRows()) {
206 sel.add(tableModel.getPrimitiveAt(tbl.convertRowIndexToModel(idx)));
207 }
208 return sel;
209 }
210
211 private final TagSetChanger tagSetChanger = new TagSetChanger();
212
213 private void initAutocompletion() {
214 OsmDataLayer l = MainApplication.getLayerManager().getEditLayer();
215 AutoCompletionManager autocomplete = AutoCompletionManager.of(l.data);
216 for (int i = 0; i < tableModel.mainTags.length; i++) {
217 if (tableModel.isSpecialTag[i]) continue;
218 AutoCompletingTextField tf = new AutoCompletingTextField(0, false);
219 AutoCompletionList acList = new AutoCompletionList();
220 autocomplete.populateWithTagValues(acList, tableModel.mainTags[i]);
221 tf.setAutoCompletionList(acList);
222 tbl.getColumnModel().getColumn(i+1).setCellEditor(tf);
223 }
224 }
225
226 private JPopupMenu createPopupMenu() {
227 JPopupMenu menu = new JPopupMenu();
228 menu.add(new AbstractAction(tr("Zoom to objects"), ImageProvider.get("dialogs/autoscale", "selection")) {
229 @Override
230 public void actionPerformed(ActionEvent e) {
231 if (MainApplication.isDisplayingMapView()) {
232 AutoScaleAction.zoomTo(currentSelection);
233 }
234 }
235 });
236 menu.add(new AbstractAction(tr("Select"), ImageProvider.get("dialogs", "select")) {
237 @Override
238 public void actionPerformed(ActionEvent e) {
239 MainApplication.getLayerManager().getEditDataSet().setSelected(getSelectedPrimitives());
240 }
241 });
242 menu.add(new AbstractAction(tr("Remove tag"), ImageProvider.get("dialogs", "delete")) {
243 @Override
244 public void actionPerformed(ActionEvent e) {
245 tableModel.setAutoCommit(false);
246 for (int c: tbl.getSelectedColumns()) {
247 for (int r: tbl.getSelectedRows()) {
248 tableModel.setValueAt("", tbl.convertRowIndexToModel(r), tbl.convertColumnIndexToModel(c));
249 }
250 }
251 tableModel.commit(tr("Delete tags from multiple objects"));
252 tableModel.setAutoCommit(true);
253 }
254 });
255 menu.add(new AbstractAction(tr("Duplicate tags from the first"), ImageProvider.get("copy")) {
256 @Override
257 public void actionPerformed(ActionEvent e) {
258 tableModel.setAutoCommit(false);
259 for (int c: tbl.getSelectedColumns()) {
260 if (c == 0 || tableModel.isSpecialTag[c-1]) continue;
261 boolean first = true;
262 String value = "";
263 for (int r: tbl.getSelectedRows()) {
264 if (first) {
265 value = (String) tableModel.getValueAt(tbl.convertRowIndexToModel(r), tbl.convertColumnIndexToModel(c));
266 }
267 first = false;
268 tableModel.setValueAt(value, tbl.convertRowIndexToModel(r), tbl.convertColumnIndexToModel(c));
269 }
270 }
271 tableModel.commit(tr("Set tags for multiple objects"));
272 tableModel.setAutoCommit(true);
273 }
274 });
275 return menu;
276 }
277
278 private static class PrimitiveTypeIconRenderer extends DefaultTableCellRenderer {
279 @Override
280 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
281 Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
282 if (c instanceof JLabel && value instanceof OsmPrimitiveType) {
283 ((JLabel) c).setIcon(ImageProvider.get((OsmPrimitiveType) value));
284 ((JLabel) c).setText("");
285 }
286 return c;
287 }
288 }
289
290 private class DeleteFromHistoryAction extends AbstractAction {
291 DeleteFromHistoryAction() {
292 super("", ImageProvider.get("dialogs", "delete"));
293 putValue(SHORT_DESCRIPTION, tr("Delete from history"));
294 }
295
296 @Override
297 public void actionPerformed(ActionEvent e) {
298 String txt = cbTagSet.getText();
299 System.out.println(txt);
300 List<String> history = cbTagSet.getHistory();
301 history.remove(txt);
302 if (history.isEmpty()) {
303 history = Arrays.asList(defaultHistory);
304 }
305 Config.getPref().putList(HISTORY_KEY, history);
306 loadHistory();
307 }
308 }
309
310 private class FindMatchingAction extends AbstractAction {
311 FindMatchingAction() {
312 super("", ImageProvider.get("dialogs", "search"));
313 putValue(SHORT_DESCRIPTION, tr("Find primitives with these tags"));
314 }
315
316 @Override
317 public void actionPerformed(ActionEvent e) {
318 SearchAction.search(tableModel.getSearchExpression(), SearchMode.replace);
319 }
320 }
321
322 private class TagSetChanger extends AbstractAction implements ItemListener {
323 String oldTags;
324
325 @Override
326 public void itemStateChanged(ItemEvent e) {
327 // skip text-changing enevts, we need only combobox-selecting ones
328 if (cbTagSet.getSelectedIndex() < 0) return;
329 actionPerformed(null);
330 }
331
332 @Override
333 public void actionPerformed(ActionEvent e) {
334 String s = cbTagSet.getText();
335 if (s == null || s.isEmpty() || s.equals(oldTags)) return;
336 oldTags = s;
337 cbTagSet.addCurrentItemToHistory();
338 Config.getPref().putList(HISTORY_KEY, cbTagSet.getHistory());
339 specifyTagSet(s);
340 }
341 }
342
343 private void specifyTagSet(String s) {
344 Logging.info("Multitagger tags="+s);
345 tableModel.setupColumnsFromText(s);
346
347 tbl.createDefaultColumnsFromModel();
348 tbl.setAutoCreateRowSorter(true);
349
350 tbl.getColumnModel().getColumn(0).setMaxWidth(20);
351 for (int i = 1; i < tableModel.getColumnCount(); i++) {
352 TableHelper.adjustColumnWidth(tbl, i, 100);
353 }
354 initAutocompletion();
355 tableModel.fireTableDataChanged();
356 }
357
358 class ColoredRenderer extends DefaultTableCellRenderer {
359 private final Color highlightColor = new NamedColorProperty(
360 marktr("Multitag Background: highlight"), new Color(255, 255, 200)).get();
361 @Override
362 public Component getTableCellRendererComponent(JTable table, Object value, boolean
363 isSelected, boolean hasFocus, int row, int column) {
364 int row1 = tbl.convertRowIndexToModel(row);
365 JLabel label = (JLabel) super.getTableCellRendererComponent(
366 table, value, isSelected, hasFocus, row, column);
367 if (tbl.isRowSelected(row1) && !tbl.isColumnSelected(column)) {
368 label.setBackground(highlightColor);
369 } else {
370 if (isSelected) {
371 label.setBackground(UIManager.getColor("Table.selectionBackground"));
372 } else {
373 label.setBackground(UIManager.getColor("Table.background"));
374 }
375 }
376 return label;
377 }
378 }
379}
Note: See TracBrowser for help on using the repository browser.