Changeset 5636 in josm
- Timestamp:
- 2012-12-27T17:40:48+01:00 (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/gui/dialogs/properties/TagEditHelper.java
r5633 r5636 71 71 */ 72 72 class TagEditHelper { 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 73 private final DefaultTableModel propertyData; 74 private final Map<String, Map<String, Integer>> valueCount; 75 76 private String changedKey; 77 78 private String lastAddKey = null; 79 private String lastAddValue = null; 80 81 public static final int DEFAULT_LRU_TAGS_NUMBER = 5; 82 public static final int MAX_LRU_TAGS_NUMBER = 9; 83 84 private String objKey; 85 86 Comparator<AutoCompletionListItem> defaultACItemComparator = new Comparator<AutoCompletionListItem>() { 87 public int compare(AutoCompletionListItem o1, AutoCompletionListItem o2) { 88 return String.CASE_INSENSITIVE_ORDER.compare(o1.getValue(), o2.getValue()); 89 } 90 }; 91 91 92 92 … … 120 120 if (sel.isEmpty()) return; 121 121 122 JPanel p = new JPanel(new GridBagLayout()); 123 p.add(new JLabel("<html>"+trn("This will change up to {0} object.", 124 "This will change up to {0} objects.", sel.size(),sel.size()) 125 +"<br><br>"+tr("Please select a key")), GBC.eol().fill(GBC.HORIZONTAL)); 126 final AutoCompletingComboBox keys = new AutoCompletingComboBox(); 127 AutoCompletionManager autocomplete = Main.main.getEditLayer().data.getAutoCompletionManager(); 128 List<AutoCompletionListItem> keyList = autocomplete.getKeys(); 129 130 AutoCompletionListItem itemToSelect = null; 131 // remove the object's tag keys from the list 132 Iterator<AutoCompletionListItem> iter = keyList.iterator(); 133 while (iter.hasNext()) { 134 AutoCompletionListItem item = iter.next(); 135 if (item.getValue().equals(lastAddKey)) { 136 itemToSelect = item; 137 } 138 for (int i = 0; i < propertyData.getRowCount(); ++i) { 139 if (item.getValue().equals(propertyData.getValueAt(i, 0))) { 140 if (itemToSelect == item) { 141 itemToSelect = null; 142 } 143 iter.remove(); 144 break; 145 } 146 } 147 } 148 149 Collections.sort(keyList, defaultACItemComparator); 150 keys.setPossibleACItems(keyList); 151 keys.setEditable(true); 152 153 p.add(keys, GBC.eop().fill()); 154 155 p.add(new JLabel(tr("Please select a value")), GBC.eol()); 156 final AutoCompletingComboBox values = new AutoCompletingComboBox(); 157 values.setEditable(true); 158 p.add(values, GBC.eop().fill()); 159 if (itemToSelect != null) { 160 keys.setSelectedItem(itemToSelect); 161 if (lastAddValue != null) { 162 values.setSelectedItem(lastAddValue); 163 } 164 } 165 166 FocusAdapter focus = addFocusAdapter(keys, values, autocomplete, defaultACItemComparator); 167 // fire focus event in advance or otherwise the popup list will be too small at first 168 focus.focusGained(null); 169 170 int recentTagsToShow = Main.pref.getInteger("properties.recently-added-tags", DEFAULT_LRU_TAGS_NUMBER); 171 if (recentTagsToShow > MAX_LRU_TAGS_NUMBER) { 172 recentTagsToShow = MAX_LRU_TAGS_NUMBER; 173 } 174 List<JosmAction> recentTagsActions = new ArrayList<JosmAction>(); 175 suggestRecentlyAddedTags(p, keys, values, recentTagsActions, recentTagsToShow, focus); 176 177 JOptionPane pane = new JOptionPane(p, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION){ 122 final AddTagsPanel p = new AddTagsPanel(sel); 123 124 final JOptionPane optionPane = new JOptionPane(p, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION){ 178 125 @Override public void selectInitialValue() { 179 126 // save unix system selection (middle mouse paste) … … 181 128 if(sysSel != null) { 182 129 Transferable old = sysSel.getContents(null); 183 keys.requestFocusInWindow();184 keys.getEditor().selectAll();130 p.keys.requestFocusInWindow(); 131 p.keys.getEditor().selectAll(); 185 132 sysSel.setContents(old, null); 186 133 } else { 187 keys.requestFocusInWindow();188 keys.getEditor().selectAll();134 p.keys.requestFocusInWindow(); 135 p.keys.getEditor().selectAll(); 189 136 } 190 137 } 191 138 }; 192 JDialog dialog = pane.createDialog(Main.parent, tr("Add value?"));139 final JDialog dialog = optionPane.createDialog(Main.parent, tr("Add value?")); 193 140 dialog.setModalityType(Dialog.ModalityType.DOCUMENT_MODAL); 141 // We specify what to do if panel wants to close the entire dialog 142 p.setCloseActionListener(new ActionListener() { 143 public void actionPerformed(ActionEvent e) { 144 dialog.setVisible(false); 145 optionPane.setValue(JOptionPane.OK_OPTION); 146 } 147 }); 194 148 dialog.setVisible(true); 195 149 196 for (JosmAction action : recentTagsActions) { 197 action.destroy(); 198 } 199 200 if (!Integer.valueOf(JOptionPane.OK_OPTION).equals(pane.getValue())) 150 p.destroyActions(); 151 152 if (!Integer.valueOf(JOptionPane.OK_OPTION).equals(optionPane.getValue())) 201 153 return; 202 String key = keys.getEditor().getItem().toString().trim(); 203 String value = values.getEditor().getItem().toString().trim(); 204 if (key.isEmpty() || value.isEmpty()) 154 p.performTagAdding(); 155 } 156 157 /** 158 * Create a focus handling adapter and apply in to the editor component of value 159 * autocompletion box. 160 * @param keys Box for keys entering and autocompletion 161 * @param values Box for values entering and autocompletion 162 * @param autocomplete Manager handling the autocompletion 163 * @param comparator Class to decide what values are offered on autocompletion 164 * @return The created adapter 165 */ 166 private FocusAdapter addFocusAdapter(final AutoCompletingComboBox keys, final AutoCompletingComboBox values, 167 final AutoCompletionManager autocomplete, final Comparator<AutoCompletionListItem> comparator) { 168 // get the combo box' editor component 169 JTextComponent editor = (JTextComponent)values.getEditor() 170 .getEditorComponent(); 171 // Refresh the values model when focus is gained 172 FocusAdapter focus = new FocusAdapter() { 173 @Override public void focusGained(FocusEvent e) { 174 String key = keys.getEditor().getItem().toString(); 175 176 List<AutoCompletionListItem> valueList = autocomplete.getValues(getAutocompletionKeys(key)); 177 Collections.sort(valueList, comparator); 178 179 values.setPossibleACItems(valueList); 180 objKey=key; 181 } 182 }; 183 editor.addFocusListener(focus); 184 return focus; 185 } 186 187 /** 188 * Edit the value in the properties table row 189 * @param row The row of the table from which the value is edited. 190 */ 191 public void editProperty(final int row) { 192 changedKey = null; 193 Collection<OsmPrimitive> sel = Main.main.getCurrentDataSet().getSelected(); 194 if (sel.isEmpty()) return; 195 196 String key = propertyData.getValueAt(row, 0).toString(); 197 objKey=key; 198 199 @SuppressWarnings("unchecked") 200 final EditTagsPanel p = new EditTagsPanel(key, row, sel, 201 (Map<String, Integer>) propertyData.getValueAt(row, 1)); 202 203 final JOptionPane optionPane = new JOptionPane(p, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION) { 204 @Override public void selectInitialValue() { 205 // save unix system selection (middle mouse paste) 206 Clipboard sysSel = Toolkit.getDefaultToolkit().getSystemSelection(); 207 if(sysSel != null) { 208 Transferable old = sysSel.getContents(null); 209 p.values.requestFocusInWindow(); 210 p.values.getEditor().selectAll(); 211 sysSel.setContents(old, null); 212 } else { 213 p.values.requestFocusInWindow(); 214 p.values.getEditor().selectAll(); 215 } 216 } 217 }; 218 219 final JDialog dialog = optionPane.createDialog(Main.parent, trn("Change value?", "Change values?", p.getValueCount())); 220 dialog.setModalityType(Dialog.ModalityType.DOCUMENT_MODAL); 221 Dimension dlgSize = dialog.getSize(); 222 if(dlgSize.width > Main.parent.getSize().width) { 223 dlgSize.width = Math.max(250, Main.parent.getSize().width); 224 dialog.setSize(dlgSize); 225 } 226 dialog.setLocationRelativeTo(Main.parent); 227 228 // Auto-close dialog when user selects a value from list 229 p.values.getEditor().addActionListener(new ActionListener() { 230 public void actionPerformed(ActionEvent e) { 231 dialog.setVisible(false); 232 optionPane.setValue(JOptionPane.OK_OPTION); 233 } 234 }); 235 236 dialog.setVisible(true); 237 238 if (!Integer.valueOf(JOptionPane.OK_OPTION).equals(optionPane.getValue())) { 205 239 return; 206 lastAddKey = key; 207 lastAddValue = value; 208 recentTags.put(new Tag(key, value), null); 209 Main.main.undoRedo.add(new ChangePropertyCommand(sel, key, value)); 210 changedKey = key; 211 } 212 213 private void suggestRecentlyAddedTags(JPanel p, final AutoCompletingComboBox keys, final AutoCompletingComboBox values, List<JosmAction> tagsActions, int tagsToShow, final FocusAdapter focus) { 214 if (tagsToShow > 0 && !recentTags.isEmpty()) { 215 p.add(new JLabel(tr("Recently added tags")), GBC.eol()); 240 } 241 242 p.performTagEdit(); 243 244 } 245 246 /** 247 * If during last editProperty call user changed the key name, this key will be returned 248 * Elsewhere, returns null. 249 */ 250 public String getChangedKey() { 251 return changedKey; 252 } 253 254 public void resetChangedKey() { 255 changedKey = null; 256 } 257 258 /** 259 * For a given key k, return a list of keys which are used as keys for 260 * auto-completing values to increase the search space. 261 * @param key the key k 262 * @return a list of keys 263 */ 264 private static List<String> getAutocompletionKeys(String key) { 265 if ("name".equals(key) || "addr:street".equals(key)) 266 return Arrays.asList("addr:street", "name"); 267 else 268 return Arrays.asList(key); 269 } 270 271 272 class EditTagsPanel extends JPanel { 273 final AutoCompletingComboBox keys; 274 final AutoCompletingComboBox values; 275 String oldValue; 276 final String key; 277 final Collection<OsmPrimitive> sel; 278 final Map<String, Integer> m; 279 280 public EditTagsPanel(final String key, final int row, Collection<OsmPrimitive> sel, Map<String, Integer> countMap) { 281 super(new BorderLayout()); 282 this.key = key; 283 this.sel = sel; 284 m = countMap; 285 286 287 String msg = "<html>"+trn("This will change {0} object.", 288 "This will change up to {0} objects.", sel.size(), sel.size()) 289 +"<br><br>("+tr("An empty value deletes the tag.", key)+")</html>"; 290 291 add(new JLabel(msg), BorderLayout.NORTH); 292 293 JPanel p = new JPanel(new GridBagLayout()); 294 add(p, BorderLayout.CENTER); 295 296 AutoCompletionManager autocomplete = Main.main.getEditLayer().data.getAutoCompletionManager(); 297 List<AutoCompletionListItem> keyList = autocomplete.getKeys(); 298 Collections.sort(keyList, defaultACItemComparator); 299 300 keys = new AutoCompletingComboBox(key); 301 keys.setPossibleACItems(keyList); 302 keys.setEditable(true); 303 keys.setSelectedItem(key); 304 305 p.add(new JLabel(tr("Key")), GBC.std()); 306 p.add(Box.createHorizontalStrut(10), GBC.std()); 307 p.add(keys, GBC.eol().fill(GBC.HORIZONTAL)); 308 309 310 Comparator<AutoCompletionListItem> usedValuesAwareComparator = new Comparator<AutoCompletionListItem>() { 311 312 @Override 313 public int compare(AutoCompletionListItem o1, AutoCompletionListItem o2) { 314 boolean c1 = m.containsKey(o1.getValue()); 315 boolean c2 = m.containsKey(o2.getValue()); 316 if (c1 == c2) 317 return String.CASE_INSENSITIVE_ORDER.compare(o1.getValue(), o2.getValue()); 318 else if (c1) 319 return -1; 320 else 321 return +1; 322 } 323 }; 324 325 List<AutoCompletionListItem> valueList = autocomplete.getValues(getAutocompletionKeys(key)); 326 Collections.sort(valueList, usedValuesAwareComparator); 327 328 final String selection= m.size()!=1?tr("<different>"):m.entrySet().iterator().next().getKey(); 329 330 values = new AutoCompletingComboBox(selection); 331 values.setRenderer(new DefaultListCellRenderer() { 332 @Override public Component getListCellRendererComponent(JList list, 333 Object value, int index, boolean isSelected, boolean cellHasFocus){ 334 Component c = super.getListCellRendererComponent(list, value, 335 index, isSelected, cellHasFocus); 336 if (c instanceof JLabel) { 337 String str = ((AutoCompletionListItem) value).getValue(); 338 if (valueCount.containsKey(objKey)) { 339 Map<String, Integer> m = valueCount.get(objKey); 340 if (m.containsKey(str)) { 341 str = tr("{0} ({1})", str, m.get(str)); 342 c.setFont(c.getFont().deriveFont(Font.ITALIC + Font.BOLD)); 343 } 344 } 345 ((JLabel) c).setText(str); 346 } 347 return c; 348 } 349 }); 350 351 values.setEditable(true); 352 values.setPossibleACItems(valueList); 353 values.setSelectedItem(selection); 354 values.getEditor().setItem(selection); 355 p.add(new JLabel(tr("Value")), GBC.std()); 356 p.add(Box.createHorizontalStrut(10), GBC.std()); 357 p.add(values, GBC.eol().fill(GBC.HORIZONTAL)); 358 addFocusAdapter(keys, values, autocomplete, usedValuesAwareComparator); 359 360 } 361 362 private int getValueCount() { 363 return m.size(); 364 } 365 366 /** 367 * Edit tags of multiple selected objects according to selected ComboBox values 368 * If value == "", tag will be deleted 369 * Confirmations may be needed. 370 */ 371 private void performTagEdit() { 372 String value = values.getEditor().getItem().toString().trim(); 373 // is not Java 1.5 374 //value = java.text.Normalizer.normalize(value, java.text.Normalizer.Form.NFC); 375 if (value.equals("")) { 376 value = null; // delete the key 377 } 378 String newkey = keys.getEditor().getItem().toString().trim(); 379 //newkey = java.text.Normalizer.normalize(newkey, java.text.Normalizer.Form.NFC); 380 if (newkey.equals("")) { 381 newkey = key; 382 value = null; // delete the key instead 383 } 384 if (key.equals(newkey) && tr("<different>").equals(value)) 385 return; 386 if (key.equals(newkey) || value == null) { 387 Main.main.undoRedo.add(new ChangePropertyCommand(sel, newkey, value)); 388 } else { 389 for (OsmPrimitive osm: sel) { 390 if(osm.get(newkey) != null) { 391 ExtendedDialog ed = new ExtendedDialog( 392 Main.parent, 393 tr("Overwrite key"), 394 new String[]{tr("Replace"), tr("Cancel")}); 395 ed.setButtonIcons(new String[]{"purge", "cancel"}); 396 ed.setContent(tr("You changed the key from ''{0}'' to ''{1}''.\n" 397 + "The new key is already used, overwrite values?", key, newkey)); 398 ed.setCancelButton(2); 399 ed.toggleEnable("overwriteEditKey"); 400 ed.showDialog(); 401 402 if (ed.getValue() != 1) 403 return; 404 break; 405 } 406 } 407 Collection<Command> commands=new Vector<Command>(); 408 commands.add(new ChangePropertyCommand(sel, key, null)); 409 if (value.equals(tr("<different>"))) { 410 HashMap<String, Vector<OsmPrimitive>> map=new HashMap<String, Vector<OsmPrimitive>>(); 411 for (OsmPrimitive osm: sel) { 412 String val=osm.get(key); 413 if(val != null) 414 { 415 if (map.containsKey(val)) { 416 map.get(val).add(osm); 417 } else { 418 Vector<OsmPrimitive> v = new Vector<OsmPrimitive>(); 419 v.add(osm); 420 map.put(val, v); 421 } 422 } 423 } 424 for (Map.Entry<String, Vector<OsmPrimitive>> e: map.entrySet()) { 425 commands.add(new ChangePropertyCommand(e.getValue(), newkey, e.getKey())); 426 } 427 } else { 428 commands.add(new ChangePropertyCommand(sel, newkey, value)); 429 } 430 Main.main.undoRedo.add(new SequenceCommand( 431 trn("Change properties of up to {0} object", 432 "Change properties of up to {0} objects", sel.size(), sel.size()), 433 commands)); 434 } 435 436 changedKey = newkey; 437 } 438 439 440 } 441 442 class AddTagsPanel extends JPanel { 443 final AutoCompletingComboBox keys = new AutoCompletingComboBox(); 444 final AutoCompletingComboBox values = new AutoCompletingComboBox(); 445 List<JosmAction> recentTagsActions = new ArrayList<JosmAction>(); 446 Collection<OsmPrimitive> sel; 447 private ActionListener autoCloseActionListener; 448 449 public AddTagsPanel(Collection<OsmPrimitive> sel) { 450 super(new GridBagLayout()); 451 this.sel = sel; 452 add(new JLabel("<html>"+trn("This will change up to {0} object.", 453 "This will change up to {0} objects.", sel.size(),sel.size()) 454 +"<br><br>"+tr("Please select a key")), GBC.eol().fill(GBC.HORIZONTAL)); 455 456 AutoCompletionManager autocomplete = Main.main.getEditLayer().data.getAutoCompletionManager(); 457 List<AutoCompletionListItem> keyList = autocomplete.getKeys(); 458 459 AutoCompletionListItem itemToSelect = null; 460 // remove the object's tag keys from the list 461 Iterator<AutoCompletionListItem> iter = keyList.iterator(); 462 while (iter.hasNext()) { 463 AutoCompletionListItem item = iter.next(); 464 if (item.getValue().equals(lastAddKey)) { 465 itemToSelect = item; 466 } 467 for (int i = 0; i < propertyData.getRowCount(); ++i) { 468 if (item.getValue().equals(propertyData.getValueAt(i, 0))) { 469 if (itemToSelect == item) { 470 itemToSelect = null; 471 } 472 iter.remove(); 473 break; 474 } 475 } 476 } 477 478 Collections.sort(keyList, defaultACItemComparator); 479 keys.setPossibleACItems(keyList); 480 keys.setEditable(true); 481 482 add(keys, GBC.eop().fill()); 483 484 add(new JLabel(tr("Please select a value")), GBC.eol()); 485 values.setEditable(true); 486 add(values, GBC.eop().fill()); 487 if (itemToSelect != null) { 488 keys.setSelectedItem(itemToSelect); 489 if (lastAddValue != null) { 490 values.setSelectedItem(lastAddValue); 491 } 492 } 493 494 FocusAdapter focus = addFocusAdapter(keys, values, autocomplete, defaultACItemComparator); 495 // fire focus event in advance or otherwise the popup list will be too small at first 496 focus.focusGained(null); 497 498 int recentTagsToShow = Main.pref.getInteger("properties.recently-added-tags", DEFAULT_LRU_TAGS_NUMBER); 499 if (recentTagsToShow > MAX_LRU_TAGS_NUMBER) { 500 recentTagsToShow = MAX_LRU_TAGS_NUMBER; 501 } 502 suggestRecentlyAddedTags(recentTagsToShow, focus); 503 } 504 505 private void suggestRecentlyAddedTags(int tagsToShow, final FocusAdapter focus) { 506 if (!(tagsToShow > 0 && !recentTags.isEmpty())) 507 return; 508 509 add(new JLabel(tr("Recently added tags")), GBC.eol()); 216 510 217 511 int count = 1; … … 234 528 } 235 529 }; 236 tagsActions.add(action); 237 // Disable action if its key is already set on the object (the key being absent from the keys list for this reason 238 // performing this action leads to autocomplete to the next key (see #7671 comments) 239 for (int j = 0; j < propertyData.getRowCount(); ++j) { 240 if (t.getKey().equals(propertyData.getValueAt(j, 0))) { 241 action.setEnabled(false); 242 break; 243 } 244 } 530 recentTagsActions.add(action); 531 disableTagIfNeeded(t, action); 245 532 // Find and display icon 246 533 ImageIcon icon = MapPaintStyles.getNodeIcon(t, false); // Filters deprecated icon … … 250 537 GridBagConstraints gbc = new GridBagConstraints(); 251 538 gbc.ipadx = 5; 252 p.add(new JLabel(action.isEnabled() ? icon : GuiHelper.getDisabledIcon(icon)), gbc);539 add(new JLabel(action.isEnabled() ? icon : GuiHelper.getDisabledIcon(icon)), gbc); 253 540 // Create tag label 254 541 final String color = action.isEnabled() ? "" : "; color:gray"; … … 258 545 if (action.isEnabled()) { 259 546 // Register action 260 p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), actionShortcutKey);261 p.getActionMap().put(actionShortcutKey, action);547 getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), actionShortcutKey); 548 getActionMap().put(actionShortcutKey, action); 262 549 // Make the tag label clickable and set tooltip to the action description (this displays also the keyboard shortcut) 263 550 tagLabel.setToolTipText((String) action.getValue(Action.SHORT_DESCRIPTION)); … … 267 554 public void mouseClicked(MouseEvent e) { 268 555 action.actionPerformed(null); 556 // add tags and close window on double-click 557 if (e.getClickCount()>1) { 558 performTagAdding(); 559 if (autoCloseActionListener!=null) 560 autoCloseActionListener.actionPerformed(null); 561 } 562 // add tags on Shift-Click 563 if (e.isShiftDown()) { 564 performTagAdding(); 565 } 269 566 } 270 567 }); … … 278 575 JPanel tagPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); 279 576 tagPanel.add(tagLabel); 280 p.add(tagPanel, GBC.eol().fill(GBC.HORIZONTAL)); 281 } 282 } 283 } 284 285 /** 286 * Create a focus handling adapter and apply in to the editor component of value 287 * autocompletion box. 288 * @param keys Box for keys entering and autocompletion 289 * @param values Box for values entering and autocompletion 290 * @param autocomplete Manager handling the autocompletion 291 * @param comparator Class to decide what values are offered on autocompletion 292 * @return The created adapter 293 */ 294 private FocusAdapter addFocusAdapter(final AutoCompletingComboBox keys, final AutoCompletingComboBox values, 295 final AutoCompletionManager autocomplete, final Comparator<AutoCompletionListItem> comparator) { 296 // get the combo box' editor component 297 JTextComponent editor = (JTextComponent)values.getEditor() 298 .getEditorComponent(); 299 // Refresh the values model when focus is gained 300 FocusAdapter focus = new FocusAdapter() { 301 @Override public void focusGained(FocusEvent e) { 302 String key = keys.getEditor().getItem().toString(); 303 304 List<AutoCompletionListItem> valueList = autocomplete.getValues(getAutocompletionKeys(key)); 305 Collections.sort(valueList, comparator); 306 307 values.setPossibleACItems(valueList); 308 objKey=key; 309 } 310 }; 311 editor.addFocusListener(focus); 312 return focus; 313 } 314 577 add(tagPanel, GBC.eol().fill(GBC.HORIZONTAL)); 578 } 579 } 580 581 public void destroyActions() { 582 for (JosmAction action : recentTagsActions) { 583 action.destroy(); 584 } 585 } 586 587 315 588 /** 316 * Edit the value in the properties table row 317 * @param row The row of the table from which the value is edited. 318 */ 319 public void editProperty(final int row) { 320 changedKey = null; 321 Collection<OsmPrimitive> sel = Main.main.getCurrentDataSet().getSelected(); 322 if (sel.isEmpty()) return; 323 324 String key = propertyData.getValueAt(row, 0).toString(); 325 objKey=key; 326 327 String msg = "<html>"+trn("This will change {0} object.", 328 "This will change up to {0} objects.", sel.size(), sel.size()) 329 +"<br><br>("+tr("An empty value deletes the tag.", key)+")</html>"; 330 331 JPanel panel = new JPanel(new BorderLayout()); 332 panel.add(new JLabel(msg), BorderLayout.NORTH); 333 334 JPanel p = new JPanel(new GridBagLayout()); 335 panel.add(p, BorderLayout.CENTER); 336 337 AutoCompletionManager autocomplete = Main.main.getEditLayer().data.getAutoCompletionManager(); 338 List<AutoCompletionListItem> keyList = autocomplete.getKeys(); 339 Collections.sort(keyList, defaultACItemComparator); 340 341 final AutoCompletingComboBox keys = new AutoCompletingComboBox(key); 342 keys.setPossibleACItems(keyList); 343 keys.setEditable(true); 344 keys.setSelectedItem(key); 345 346 p.add(new JLabel(tr("Key")), GBC.std()); 347 p.add(Box.createHorizontalStrut(10), GBC.std()); 348 p.add(keys, GBC.eol().fill(GBC.HORIZONTAL)); 349 350 @SuppressWarnings("unchecked") 351 final Map<String, Integer> m = (Map<String, Integer>) propertyData.getValueAt(row, 1); 352 353 Comparator<AutoCompletionListItem> usedValuesAwareComparator = new Comparator<AutoCompletionListItem>() { 354 355 @Override 356 public int compare(AutoCompletionListItem o1, AutoCompletionListItem o2) { 357 boolean c1 = m.containsKey(o1.getValue()); 358 boolean c2 = m.containsKey(o2.getValue()); 359 if (c1 == c2) 360 return String.CASE_INSENSITIVE_ORDER.compare(o1.getValue(), o2.getValue()); 361 else if (c1) 362 return -1; 363 else 364 return +1; 365 } 366 }; 367 368 List<AutoCompletionListItem> valueList = autocomplete.getValues(getAutocompletionKeys(key)); 369 Collections.sort(valueList, usedValuesAwareComparator); 370 371 final String selection= m.size()!=1?tr("<different>"):m.entrySet().iterator().next().getKey(); 372 373 final AutoCompletingComboBox values = new AutoCompletingComboBox(selection); 374 values.setRenderer(new DefaultListCellRenderer() { 375 @Override public Component getListCellRendererComponent(JList list, 376 Object value, int index, boolean isSelected, boolean cellHasFocus){ 377 Component c = super.getListCellRendererComponent(list, value, 378 index, isSelected, cellHasFocus); 379 if (c instanceof JLabel) { 380 String str = ((AutoCompletionListItem) value).getValue(); 381 if (valueCount.containsKey(objKey)) { 382 Map<String, Integer> m = valueCount.get(objKey); 383 if (m.containsKey(str)) { 384 str = tr("{0} ({1})", str, m.get(str)); 385 c.setFont(c.getFont().deriveFont(Font.ITALIC + Font.BOLD)); 386 } 387 } 388 ((JLabel) c).setText(str); 389 } 390 return c; 391 } 392 }); 393 394 values.setEditable(true); 395 values.setPossibleACItems(valueList); 396 values.setSelectedItem(selection); 397 values.getEditor().setItem(selection); 398 p.add(new JLabel(tr("Value")), GBC.std()); 399 p.add(Box.createHorizontalStrut(10), GBC.std()); 400 p.add(values, GBC.eol().fill(GBC.HORIZONTAL)); 401 addFocusAdapter(keys, values, autocomplete, usedValuesAwareComparator); 402 403 final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION) { 404 @Override public void selectInitialValue() { 405 // save unix system selection (middle mouse paste) 406 Clipboard sysSel = Toolkit.getDefaultToolkit().getSystemSelection(); 407 if(sysSel != null) { 408 Transferable old = sysSel.getContents(null); 409 values.requestFocusInWindow(); 410 values.getEditor().selectAll(); 411 sysSel.setContents(old, null); 412 } else { 413 values.requestFocusInWindow(); 414 values.getEditor().selectAll(); 415 } 416 } 417 }; 418 final JDialog dlg = optionPane.createDialog(Main.parent, trn("Change value?", "Change values?", m.size())); 419 dlg.setModalityType(Dialog.ModalityType.DOCUMENT_MODAL); 420 Dimension dlgSize = dlg.getSize(); 421 if(dlgSize.width > Main.parent.getSize().width) { 422 dlgSize.width = Math.max(250, Main.parent.getSize().width); 423 dlg.setSize(dlgSize); 424 } 425 dlg.setLocationRelativeTo(Main.parent); 426 values.getEditor().addActionListener(new ActionListener() { 427 public void actionPerformed(ActionEvent e) { 428 dlg.setVisible(false); 429 optionPane.setValue(JOptionPane.OK_OPTION); 430 } 431 }); 432 433 String oldValue = values.getEditor().getItem().toString(); 434 dlg.setVisible(true); 435 436 Object answer = optionPane.getValue(); 437 if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE || 438 (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION)) { 439 values.getEditor().setItem(oldValue); 440 return; 441 } 442 443 String value = values.getEditor().getItem().toString().trim(); 444 // is not Java 1.5 445 //value = java.text.Normalizer.normalize(value, java.text.Normalizer.Form.NFC); 446 if (value.equals("")) { 447 value = null; // delete the key 448 } 449 String newkey = keys.getEditor().getItem().toString().trim(); 450 //newkey = java.text.Normalizer.normalize(newkey, java.text.Normalizer.Form.NFC); 451 if (newkey.equals("")) { 452 newkey = key; 453 value = null; // delete the key instead 454 } 455 if (key.equals(newkey) && tr("<different>").equals(value)) 456 return; 457 if (key.equals(newkey) || value == null) { 458 Main.main.undoRedo.add(new ChangePropertyCommand(sel, newkey, value)); 459 } else { 460 for (OsmPrimitive osm: sel) { 461 if(osm.get(newkey) != null) { 462 ExtendedDialog ed = new ExtendedDialog( 463 Main.parent, 464 tr("Overwrite key"), 465 new String[]{tr("Replace"), tr("Cancel")}); 466 ed.setButtonIcons(new String[]{"purge", "cancel"}); 467 ed.setContent(tr("You changed the key from ''{0}'' to ''{1}''.\n" 468 + "The new key is already used, overwrite values?", key, newkey)); 469 ed.setCancelButton(2); 470 ed.toggleEnable("overwriteEditKey"); 471 ed.showDialog(); 472 473 if (ed.getValue() != 1) 474 return; 589 * Read tags from comboboxes and add it to all selected objects 590 */ 591 public void performTagAdding() { 592 String key = keys.getEditor().getItem().toString().trim(); 593 String value = values.getEditor().getItem().toString().trim(); 594 if (key.isEmpty() || value.isEmpty()) return; 595 lastAddKey = key; 596 lastAddValue = value; 597 recentTags.put(new Tag(key, value), null); 598 Main.main.undoRedo.add(new ChangePropertyCommand(sel, key, value)); 599 changedKey = key; 600 } 601 602 private void disableTagIfNeeded(final Tag t, final JosmAction action) { 603 // Disable action if its key is already set on the object (the key being absent from the keys list for this reason 604 // performing this action leads to autocomplete to the next key (see #7671 comments) 605 for (int j = 0; j < propertyData.getRowCount(); ++j) { 606 if (t.getKey().equals(propertyData.getValueAt(j, 0))) { 607 action.setEnabled(false); 475 608 break; 476 609 } 477 610 } 478 Collection<Command> commands=new Vector<Command>(); 479 commands.add(new ChangePropertyCommand(sel, key, null)); 480 if (value.equals(tr("<different>"))) { 481 HashMap<String, Vector<OsmPrimitive>> map=new HashMap<String, Vector<OsmPrimitive>>(); 482 for (OsmPrimitive osm: sel) { 483 String val=osm.get(key); 484 if(val != null) 485 { 486 if (map.containsKey(val)) { 487 map.get(val).add(osm); 488 } else { 489 Vector<OsmPrimitive> v = new Vector<OsmPrimitive>(); 490 v.add(osm); 491 map.put(val, v); 492 } 493 } 494 } 495 for (Map.Entry<String, Vector<OsmPrimitive>> e: map.entrySet()) { 496 commands.add(new ChangePropertyCommand(e.getValue(), newkey, e.getKey())); 497 } 498 } else { 499 commands.add(new ChangePropertyCommand(sel, newkey, value)); 500 } 501 Main.main.undoRedo.add(new SequenceCommand( 502 trn("Change properties of up to {0} object", 503 "Change properties of up to {0} objects", sel.size(), sel.size()), 504 commands)); 505 } 506 507 changedKey = newkey; 508 } 509 510 /** 511 * If during last editProperty call user changed the key name, this key will be returned 512 * Elsewhere, returns null. 513 */ 514 public String getChangedKey() { 515 return changedKey; 516 } 517 518 public void resetChangedKey() { 519 changedKey = null; 520 } 521 522 /** 523 * For a given key k, return a list of keys which are used as keys for 524 * auto-completing values to increase the search space. 525 * @param key the key k 526 * @return a list of keys 527 */ 528 private static List<String> getAutocompletionKeys(String key) { 529 if ("name".equals(key) || "addr:street".equals(key)) 530 return Arrays.asList("addr:street", "name"); 531 else 532 return Arrays.asList(key); 533 } 534 535 611 } 612 613 /** 614 * @param autoCloseActionListener will be called when we need to close the entire dialog 615 */ 616 public void setCloseActionListener(ActionListener autoCloseActionListener) { 617 this.autoCloseActionListener = autoCloseActionListener; 618 } 619 } 536 620 } 537 621
Note:
See TracChangeset
for help on using the changeset viewer.