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

Last change on this file since 5845 was 5845, checked in by akks, 11 years ago

fix #8599: Remote control command add_way now creates closed ways correctly
Show old values and tooltips in add_tags dialog
All nodes added by add_node and add_way are merged with existing ones

  • Property svn:eol-style set to native
File size: 9.8 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.util.Collection;
14import java.util.HashMap;
15import javax.swing.AbstractAction;
16
17import javax.swing.JPanel;
18import javax.swing.JTable;
19import javax.swing.KeyStroke;
20import javax.swing.event.CellEditorListener;
21import javax.swing.event.ChangeEvent;
22import javax.swing.table.DefaultTableModel;
23import javax.swing.table.TableCellEditor;
24import javax.swing.table.TableCellRenderer;
25import javax.swing.table.TableModel;
26
27import org.openstreetmap.josm.Main;
28import org.openstreetmap.josm.command.ChangePropertyCommand;
29import org.openstreetmap.josm.data.SelectionChangedListener;
30import org.openstreetmap.josm.data.osm.DataSet;
31import org.openstreetmap.josm.data.osm.OsmPrimitive;
32import org.openstreetmap.josm.gui.ExtendedDialog;
33import org.openstreetmap.josm.gui.util.TableHelper;
34import org.openstreetmap.josm.tools.GBC;
35
36/**
37 *
38 * @author master
39 *
40 * Dialog to add tags as part of the remotecontrol
41 * Existing Keys get grey color and unchecked selectboxes so they will not overwrite the old Key-Value-Pairs by default.
42 * You can choose the tags you want to add by selectboxes. You can edit the tags before you apply them.
43 *
44 */
45public class AddTagsDialog extends ExtendedDialog implements SelectionChangedListener {
46
47
48 private final JTable propertyTable;
49 private Collection<? extends OsmPrimitive> sel;
50 int[] count;
51
52 /**
53 * Class for displaying "delete from ... objects" in the table
54 */
55 static class DeleteTagMarker {
56 int num;
57 public DeleteTagMarker(int num) {
58 this.num = num;
59 }
60 public String toString() {
61 return tr("<delete from {0} objects>", num);
62 }
63 }
64
65 /**
66 * Class for displaying list of existing tag values in the table
67 */
68 static class ExistingValues {
69 String tag;
70 HashMap<String, Integer> valueCount;
71 public ExistingValues(String tag) {
72 this.tag=tag; valueCount=new HashMap<String, Integer>();
73 }
74
75 int addValue(String val) {
76 Integer c = valueCount.get(val);
77 int r = c==null? 1 : (c.intValue()+1);
78 valueCount.put(val, r);
79 return r;
80 }
81
82 @Override
83 public String toString() {
84 StringBuilder sb=new StringBuilder();
85 for (String k: valueCount.keySet()) {
86 if (sb.length()>0) sb.append(", ");
87 sb.append(k);
88 }
89 return sb.toString();
90 }
91
92 private String getToolTip() {
93 StringBuilder sb=new StringBuilder();
94 sb.append("<html>");
95 sb.append(tr("Old values of"));
96 sb.append(" <b>");
97 sb.append(tag);
98 sb.append("</b><br/>");
99 for (String k: valueCount.keySet()) {
100 sb.append("<b>");
101 sb.append(valueCount.get(k));
102 sb.append(" x </b>");
103 sb.append(k);
104 sb.append("<br/>");
105 }
106 sb.append("</html>");
107 return sb.toString();
108
109 }
110 }
111
112 public AddTagsDialog(String[][] tags) {
113 super(Main.parent, tr("Add tags to selected objects"), new String[] { tr("Add selected tags"), tr("Add all tags"), tr("Cancel")},
114 false,
115 true);
116 setToolTipTexts(new String[]{tr("Add checked tags to selected objects"), tr("Shift+Enter: Add all tags to selected objects"), ""});
117
118 DataSet.addSelectionListener(this);
119
120
121 final DefaultTableModel tm = new DefaultTableModel(new String[] {tr("Assume"), tr("Key"), tr("Value"), tr("Existing values")}, tags.length) {
122 final Class<?> types[] = {Boolean.class, String.class, Object.class, ExistingValues.class};
123 @Override
124 public Class getColumnClass(int c) {
125 return types[c];
126 }
127
128 };
129
130 sel = Main.main.getCurrentDataSet().getSelected();
131 count = new int[tags.length];
132
133 for (int i = 0; i<tags.length; i++) {
134 count[i] = 0;
135 String key = tags[i][0];
136 String value = tags[i][1], oldValue;
137 Boolean b = Boolean.TRUE;
138 ExistingValues old = new ExistingValues(key);
139 for (OsmPrimitive osm : sel) {
140 oldValue = osm.get(key);
141 if (oldValue!=null) {
142 old.addValue(oldValue);
143 if (!oldValue.equals(value)) {
144 b = Boolean.FALSE;
145 count[i]++;
146 }
147 }
148 }
149 tm.setValueAt(b, i, 0);
150 tm.setValueAt(tags[i][0], i, 1);
151 tm.setValueAt(tags[i][1].isEmpty() ? new DeleteTagMarker(count[i]) : tags[i][1], i, 2);
152 tm.setValueAt(old , i, 3);
153 }
154
155 propertyTable = new JTable(tm) {
156
157 private static final long serialVersionUID = 1L;
158 ///private final DefaultCellEditor textEditor = new DefaultCellEditor( new JTextField() );
159
160 @Override
161 public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
162 Component c = super.prepareRenderer(renderer, row, column);
163 if (count[row]>0) {
164 c.setFont(c.getFont().deriveFont(Font.ITALIC));
165 c.setForeground(new Color(100, 100, 100));
166 } else {
167 c.setFont(c.getFont().deriveFont(Font.PLAIN));
168 c.setForeground(new Color(0, 0, 0));
169 }
170 return c;
171 }
172
173 @Override
174 public TableCellEditor getCellEditor(int row, int column) {
175 Object value = getValueAt(row,column);
176 if (value instanceof DeleteTagMarker) return null;
177 if (value instanceof ExistingValues) return null;
178 return getDefaultEditor(value.getClass());
179 }
180
181 @Override
182 public String getToolTipText(MouseEvent event) {
183 int r = rowAtPoint(event.getPoint());
184 int c = columnAtPoint(event.getPoint());
185 Object o = getValueAt(r, c);
186 if (c==1 || c==2) return o.toString();
187 if (c==3) return ((ExistingValues)o).getToolTip();
188 return tr("Enable the checkbox to accept the value");
189 }
190
191 };
192
193 propertyTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
194 // a checkbox has a size of 15 px
195 propertyTable.getColumnModel().getColumn(0).setMaxWidth(15);
196 TableHelper.adjustColumnWidth(propertyTable, 1, 150);
197 TableHelper.adjustColumnWidth(propertyTable, 2, 400);
198 TableHelper.adjustColumnWidth(propertyTable, 3, 300);
199 // get edit results if the table looses the focus, for example if a user clicks "add tags"
200 propertyTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
201 propertyTable.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, KeyEvent.SHIFT_MASK), "shiftenter");
202 propertyTable.getActionMap().put("shiftenter", new AbstractAction() {
203 @Override public void actionPerformed(ActionEvent e) {
204 buttonAction(1, e); // add all tags on Shift-Enter
205 }
206 });
207
208 // set the content of this AddTagsDialog consisting of the tableHeader and the table itself.
209 JPanel tablePanel = new JPanel();
210 tablePanel.setLayout(new GridBagLayout());
211 tablePanel.add(propertyTable.getTableHeader(), GBC.eol().fill(GBC.HORIZONTAL));
212 tablePanel.add(propertyTable, GBC.eol().fill(GBC.BOTH));
213 setContent(tablePanel);
214 setDefaultButton(2);
215 }
216
217 /**
218 * This method looks for existing tags in the current selection and sets the corresponding boolean in the boolean array existing[]
219 */
220 private void findExistingTags() {
221 TableModel tm = propertyTable.getModel();
222 for (int i=0; i<tm.getRowCount(); i++) {
223 String key = (String)tm.getValueAt(i, 1);
224 String value = (String)tm.getValueAt(i, 1);
225 count[i] = 0;
226 for (OsmPrimitive osm : sel) {
227 if (osm.keySet().contains(key) && !osm.get(key).equals(value)) {
228 count[i]++;
229 break;
230 }
231 }
232 }
233 propertyTable.repaint();
234 }
235
236 /**
237 * 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.
238 * You get a entry for every key in the command queue.
239 */
240 @Override
241 protected void buttonAction(int buttonIndex, ActionEvent evt) {
242 // if layer all layers were closed, ignore all actions
243 if (Main.main.getCurrentDataSet() != null && buttonIndex != 2) {
244 TableModel tm = propertyTable.getModel();
245 for (int i=0; i<tm.getRowCount(); i++) {
246 if (buttonIndex==1 || (Boolean)tm.getValueAt(i, 0)) {
247 String key =(String)tm.getValueAt(i, 1);
248 Object value = tm.getValueAt(i, 2);
249 Main.main.undoRedo.add(new ChangePropertyCommand(sel,
250 key, value instanceof String ? (String) value : ""));
251 }
252 }
253 }
254 setVisible(false);
255 }
256
257 @Override
258 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
259 sel = newSelection;
260 findExistingTags();
261 }
262
263}
Note: See TracBrowser for help on using the repository browser.