source: josm/trunk/src/org/openstreetmap/josm/io/remotecontrol/AddTagsDialog.java@ 6104

Last change on this file since 6104 was 6104, checked in by Don-vip, 11 years ago

see #8902 - Small performance enhancements / coding style (patch by shinigami):

  • while -> foreach
  • for -> for each

plus:

  • cleanup of FileDrop class to make it more integrated into JOSM core + remove warnings
  • Property svn:eol-style set to native
File size: 13.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io.remotecontrol;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Color;
7import java.awt.Component;
8import java.awt.Font;
9import java.awt.GridBagLayout;
10import java.awt.event.ActionEvent;
11import java.awt.event.KeyEvent;
12import java.awt.event.MouseEvent;
13import java.io.UnsupportedEncodingException;
14import java.net.URLDecoder;
15import java.util.Collection;
16import java.util.HashMap;
17import java.util.HashSet;
18import java.util.Map;
19import java.util.Set;
20import javax.swing.AbstractAction;
21import javax.swing.JCheckBox;
22
23import javax.swing.JPanel;
24import javax.swing.JTable;
25import javax.swing.KeyStroke;
26import javax.swing.table.DefaultTableModel;
27import javax.swing.table.TableCellEditor;
28import javax.swing.table.TableCellRenderer;
29import javax.swing.table.TableModel;
30
31import org.openstreetmap.josm.Main;
32import org.openstreetmap.josm.command.ChangePropertyCommand;
33import org.openstreetmap.josm.data.SelectionChangedListener;
34import org.openstreetmap.josm.data.osm.DataSet;
35import org.openstreetmap.josm.data.osm.OsmPrimitive;
36import org.openstreetmap.josm.gui.ExtendedDialog;
37import org.openstreetmap.josm.gui.util.GuiHelper;
38import org.openstreetmap.josm.gui.util.TableHelper;
39import org.openstreetmap.josm.tools.GBC;
40
41/**
42 *
43 * @author master
44 *
45 * Dialog to add tags as part of the remotecontrol
46 * Existing Keys get grey color and unchecked selectboxes so they will not overwrite the old Key-Value-Pairs by default.
47 * You can choose the tags you want to add by selectboxes. You can edit the tags before you apply them.
48 *
49 */
50public class AddTagsDialog extends ExtendedDialog implements SelectionChangedListener {
51
52
53 /** initially given tags **/
54 String[][] tags;
55
56 private final JTable propertyTable;
57 private Collection<? extends OsmPrimitive> sel;
58 int[] count;
59
60 String sender;
61 static Set<String> trustedSenders = new HashSet<String>();
62
63 /**
64 * Class for displaying "delete from ... objects" in the table
65 */
66 static class DeleteTagMarker {
67 int num;
68 public DeleteTagMarker(int num) {
69 this.num = num;
70 }
71 public String toString() {
72 return tr("<delete from {0} objects>", num);
73 }
74 }
75
76 /**
77 * Class for displaying list of existing tag values in the table
78 */
79 static class ExistingValues {
80 String tag;
81 HashMap<String, Integer> valueCount;
82 public ExistingValues(String tag) {
83 this.tag=tag; valueCount=new HashMap<String, Integer>();
84 }
85
86 int addValue(String val) {
87 Integer c = valueCount.get(val);
88 int r = c==null? 1 : (c.intValue()+1);
89 valueCount.put(val, r);
90 return r;
91 }
92
93 @Override
94 public String toString() {
95 StringBuilder sb=new StringBuilder();
96 for (String k: valueCount.keySet()) {
97 if (sb.length()>0) sb.append(", ");
98 sb.append(k);
99 }
100 return sb.toString();
101 }
102
103 private String getToolTip() {
104 StringBuilder sb=new StringBuilder();
105 sb.append("<html>");
106 sb.append(tr("Old values of"));
107 sb.append(" <b>");
108 sb.append(tag);
109 sb.append("</b><br/>");
110 for (String k: valueCount.keySet()) {
111 sb.append("<b>");
112 sb.append(valueCount.get(k));
113 sb.append(" x </b>");
114 sb.append(k);
115 sb.append("<br/>");
116 }
117 sb.append("</html>");
118 return sb.toString();
119
120 }
121 }
122
123 public AddTagsDialog(String[][] tags, String senderName) {
124 super(Main.parent, tr("Add tags to selected objects"), new String[] { tr("Add selected tags"), tr("Add all tags"), tr("Cancel")},
125 false,
126 true);
127 setToolTipTexts(new String[]{tr("Add checked tags to selected objects"), tr("Shift+Enter: Add all tags to selected objects"), ""});
128
129 this.sender = senderName;
130
131 DataSet.addSelectionListener(this);
132
133
134 final DefaultTableModel tm = new DefaultTableModel(new String[] {tr("Assume"), tr("Key"), tr("Value"), tr("Existing values")}, tags.length) {
135 final Class<?>[] types = {Boolean.class, String.class, Object.class, ExistingValues.class};
136 @Override
137 public Class getColumnClass(int c) {
138 return types[c];
139 }
140 };
141
142 sel = Main.main.getCurrentDataSet().getSelected();
143 count = new int[tags.length];
144
145 for (int i = 0; i<tags.length; i++) {
146 count[i] = 0;
147 String key = tags[i][0];
148 String value = tags[i][1], oldValue;
149 Boolean b = Boolean.TRUE;
150 ExistingValues old = new ExistingValues(key);
151 for (OsmPrimitive osm : sel) {
152 oldValue = osm.get(key);
153 if (oldValue!=null) {
154 old.addValue(oldValue);
155 if (!oldValue.equals(value)) {
156 b = Boolean.FALSE;
157 count[i]++;
158 }
159 }
160 }
161 tm.setValueAt(b, i, 0);
162 tm.setValueAt(tags[i][0], i, 1);
163 tm.setValueAt(tags[i][1].isEmpty() ? new DeleteTagMarker(count[i]) : tags[i][1], i, 2);
164 tm.setValueAt(old , i, 3);
165 }
166
167 propertyTable = new JTable(tm) {
168
169 private static final long serialVersionUID = 1L;
170 ///private final DefaultCellEditor textEditor = new DefaultCellEditor( new JTextField() );
171
172 @Override
173 public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
174 Component c = super.prepareRenderer(renderer, row, column);
175 if (count[row]>0) {
176 c.setFont(c.getFont().deriveFont(Font.ITALIC));
177 c.setForeground(new Color(100, 100, 100));
178 } else {
179 c.setFont(c.getFont().deriveFont(Font.PLAIN));
180 c.setForeground(new Color(0, 0, 0));
181 }
182 return c;
183 }
184
185 @Override
186 public TableCellEditor getCellEditor(int row, int column) {
187 Object value = getValueAt(row,column);
188 if (value instanceof DeleteTagMarker) return null;
189 if (value instanceof ExistingValues) return null;
190 return getDefaultEditor(value.getClass());
191 }
192
193 @Override
194 public String getToolTipText(MouseEvent event) {
195 int r = rowAtPoint(event.getPoint());
196 int c = columnAtPoint(event.getPoint());
197 Object o = getValueAt(r, c);
198 if (c==1 || c==2) return o.toString();
199 if (c==3) return ((ExistingValues)o).getToolTip();
200 return tr("Enable the checkbox to accept the value");
201 }
202
203 };
204
205 propertyTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
206 // a checkbox has a size of 15 px
207 propertyTable.getColumnModel().getColumn(0).setMaxWidth(15);
208 TableHelper.adjustColumnWidth(propertyTable, 1, 150);
209 TableHelper.adjustColumnWidth(propertyTable, 2, 400);
210 TableHelper.adjustColumnWidth(propertyTable, 3, 300);
211 // get edit results if the table looses the focus, for example if a user clicks "add tags"
212 propertyTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
213 propertyTable.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, KeyEvent.SHIFT_MASK), "shiftenter");
214 propertyTable.getActionMap().put("shiftenter", new AbstractAction() {
215 @Override public void actionPerformed(ActionEvent e) {
216 buttonAction(1, e); // add all tags on Shift-Enter
217 }
218 });
219
220 // set the content of this AddTagsDialog consisting of the tableHeader and the table itself.
221 JPanel tablePanel = new JPanel();
222 tablePanel.setLayout(new GridBagLayout());
223 tablePanel.add(propertyTable.getTableHeader(), GBC.eol().fill(GBC.HORIZONTAL));
224 tablePanel.add(propertyTable, GBC.eol().fill(GBC.BOTH));
225 if (!sender.isEmpty() && !trustedSenders.contains(sender)) {
226 final JCheckBox c = new JCheckBox();
227 c.setAction(new AbstractAction(tr("Accept all tags from {0} for this session", sender) ) {
228 @Override public void actionPerformed(ActionEvent e) {
229 if (c.isSelected())
230 trustedSenders.add(sender);
231 else
232 trustedSenders.remove(sender);
233 }
234 } );
235 tablePanel.add(c , GBC.eol().insets(20,10,0,0));
236 }
237 setContent(tablePanel);
238 setDefaultButton(2);
239 }
240
241 /**
242 * This method looks for existing tags in the current selection and sets the corresponding boolean in the boolean array existing[]
243 */
244 private void findExistingTags() {
245 TableModel tm = propertyTable.getModel();
246 for (int i=0; i<tm.getRowCount(); i++) {
247 String key = (String)tm.getValueAt(i, 1);
248 String value = (String)tm.getValueAt(i, 1);
249 count[i] = 0;
250 for (OsmPrimitive osm : sel) {
251 if (osm.keySet().contains(key) && !osm.get(key).equals(value)) {
252 count[i]++;
253 break;
254 }
255 }
256 }
257 propertyTable.repaint();
258 }
259
260 /**
261 * If you click the "Add tags" button build a ChangePropertyCommand for every key that has a checked checkbox to apply the key value pair to all selected osm objects.
262 * You get a entry for every key in the command queue.
263 */
264 @Override
265 protected void buttonAction(int buttonIndex, ActionEvent evt) {
266 // if layer all layers were closed, ignore all actions
267 if (Main.main.getCurrentDataSet() != null && buttonIndex != 2) {
268 TableModel tm = propertyTable.getModel();
269 for (int i=0; i<tm.getRowCount(); i++) {
270 if (buttonIndex==1 || (Boolean)tm.getValueAt(i, 0)) {
271 String key =(String)tm.getValueAt(i, 1);
272 Object value = tm.getValueAt(i, 2);
273 Main.main.undoRedo.add(new ChangePropertyCommand(sel,
274 key, value instanceof String ? (String) value : ""));
275 }
276 }
277 }
278 if (buttonIndex == 2) {
279 trustedSenders.remove(sender);
280 }
281 setVisible(false);
282 }
283
284 @Override
285 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
286 sel = newSelection;
287 findExistingTags();
288 }
289
290 /*
291 * parse addtags parameters Example URL (part):
292 * addtags=wikipedia:de%3DResidenzschloss Dresden|name:en%3DDresden Castle
293 */
294 public static void addTags(final Map<String, String> args, final String sender) {
295 if (args.containsKey("addtags")) {
296 GuiHelper.executeByMainWorkerInEDT(new Runnable() {
297
298 @Override
299 public void run() {
300 String[] tags = null;
301 try {
302 tags = URLDecoder.decode(args.get("addtags"), "UTF-8").split("\\|");
303 } catch (UnsupportedEncodingException e) {
304 throw new RuntimeException();
305 }
306 Set<String> tagSet = new HashSet<String>();
307 for (String tag : tags) {
308 if (!tag.trim().isEmpty() && tag.contains("=")) {
309 tagSet.add(tag.trim());
310 }
311 }
312 if (!tagSet.isEmpty()) {
313 String[][] keyValue = new String[tagSet.size()][2];
314 int i = 0;
315 for (String tag : tagSet) {
316 // support a = b===c as "a"="b===c"
317 String [] pair = tag.split("\\s*=\\s*",2);
318 keyValue[i][0] = pair[0];
319 keyValue[i][1] = pair.length<2 ? "": pair[1];
320 i++;
321 }
322 addTags(keyValue, sender);
323 }
324 }
325
326
327 });
328 }
329 }
330
331 /**
332 * Ask user and add the tags he confirm
333 * @param keyValue is a table or {{tag1,val1},{tag2,val2},...}
334 * @param sender is a string for skipping confirmations. Use epmty string for always confirmed adding.
335 */
336 public static void addTags(String[][] keyValue, String sender) {
337 if (trustedSenders.contains(sender)) {
338 if (Main.main.getCurrentDataSet() != null) {
339 Collection<OsmPrimitive> s = Main.main.getCurrentDataSet().getSelected();
340 for (String[] row : keyValue) {
341 Main.main.undoRedo.add(new ChangePropertyCommand(s, row[0], row[1]));
342 }
343 }
344 } else {
345 new AddTagsDialog(keyValue, sender).showDialog();
346 }
347 }
348}
Note: See TracBrowser for help on using the repository browser.