Ticket #12281: 12281-v1-plugin.patch
File 12281-v1-plugin.patch, 31.8 KB (added by , 8 years ago) |
---|
-
plugins/OSMRecPlugin/src/org/openstreetmap/josm/plugins/osmrec/OSMRecPluginHelper.java
diff --git a/plugins/OSMRecPlugin/src/org/openstreetmap/josm/plugins/osmrec/OSMRecPluginHelper.java b/plugins/OSMRecPlugin/src/org/openstreetmap/josm/plugins/osmrec/OSMRecPluginHelper.java index 2779071..c45639f 100644
a b import static org.openstreetmap.josm.tools.I18n.trn; 16 16 import java.awt.BorderLayout; 17 17 import java.awt.Color; 18 18 import java.awt.Component; 19 import java.awt.Cursor;20 19 import java.awt.Dimension; 21 20 import java.awt.FlowLayout; 22 import java.awt.Font;23 import java.awt.GridBagConstraints;24 21 import java.awt.GridBagLayout; 25 import java.awt.Toolkit;26 import java.awt.datatransfer.Clipboard;27 import java.awt.datatransfer.Transferable;28 22 import java.awt.event.ActionEvent; 29 import java.awt.event.FocusAdapter;30 import java.awt.event.FocusEvent;31 import java.awt.event.KeyEvent;32 import java.awt.event.MouseAdapter;33 import java.awt.event.MouseEvent;34 23 import java.awt.event.WindowAdapter; 35 24 import java.awt.event.WindowEvent; 36 import java.awt.image.BufferedImage;37 25 import java.beans.PropertyChangeEvent; 38 26 import java.beans.PropertyChangeListener; 39 27 import java.io.File; … … import java.util.ArrayList; 49 37 import java.util.Arrays; 50 38 import java.util.Collection; 51 39 import java.util.Collections; 52 import java.util.Comparator;53 40 import java.util.HashMap; 54 41 import java.util.Iterator; 55 42 import java.util.LinkedHashMap; 56 import java.util.LinkedList;57 43 import java.util.List; 58 44 import java.util.Map; 59 45 import java.util.Map.Entry; … … import java.util.logging.Level; 63 49 import java.util.logging.Logger; 64 50 65 51 import javax.swing.AbstractAction; 66 import javax.swing.Action;67 52 import javax.swing.BorderFactory; 68 53 import javax.swing.BoxLayout; 69 54 import javax.swing.ButtonGroup; 70 import javax.swing.DefaultListCellRenderer;71 55 import javax.swing.DefaultListModel; 72 56 import javax.swing.GroupLayout; 73 57 import javax.swing.GroupLayout.Alignment; 74 import javax.swing.ImageIcon;75 58 import javax.swing.JButton; 76 59 import javax.swing.JCheckBox; 77 60 import javax.swing.JCheckBoxMenuItem; 78 import javax.swing.JComponent;79 61 import javax.swing.JDialog; 80 62 import javax.swing.JFileChooser; 81 63 import javax.swing.JLabel; 82 64 import javax.swing.JList; 83 65 import javax.swing.JOptionPane; 84 66 import javax.swing.JPanel; 85 import javax.swing.JPopupMenu;86 67 import javax.swing.JProgressBar; 87 68 import javax.swing.JRadioButton; 88 69 import javax.swing.JScrollPane; 70 import javax.swing.JTable; 89 71 import javax.swing.JTextField; 90 import javax.swing.ListCellRenderer;91 72 import javax.swing.SwingConstants; 92 73 import javax.swing.border.EtchedBorder; 93 74 import javax.swing.border.TitledBorder; 94 75 import javax.swing.event.ListSelectionEvent; 95 76 import javax.swing.event.ListSelectionListener; 96 77 import javax.swing.table.DefaultTableModel; 97 import javax.swing.text.JTextComponent;98 78 import org.geotools.geometry.jts.JTS; 99 79 import org.geotools.referencing.CRS; 100 80 import org.geotools.referencing.crs.DefaultGeocentricCRS; … … import org.opengis.referencing.operation.MathTransform; 106 86 import org.opengis.referencing.operation.TransformException; 107 87 108 88 import org.openstreetmap.josm.Main; 109 import org.openstreetmap.josm.actions.JosmAction;110 import org.openstreetmap.josm.command.ChangePropertyCommand;111 89 import org.openstreetmap.josm.data.osm.Node; 112 90 import org.openstreetmap.josm.data.osm.OsmPrimitive; 113 91 import org.openstreetmap.josm.data.osm.Tag; 114 92 import org.openstreetmap.josm.data.osm.Way; 115 import org.openstreetmap.josm.data.preferences.BooleanProperty; 116 import org.openstreetmap.josm.data.preferences.IntegerProperty; 117 import org.openstreetmap.josm.gui.ExtendedDialog; 118 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles; 119 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingComboBox; 93 import org.openstreetmap.josm.gui.dialogs.properties.TagEditHelper; 120 94 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionListItem; 121 95 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager; 122 //import org.openstreetmap.josm.gui.tagging.presets.TaggingPreset;123 import org.openstreetmap.josm.gui.util.GuiHelper;124 import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;125 import org.openstreetmap.josm.io.XmlWriter;126 96 import org.openstreetmap.josm.plugins.container.OSMWay; 127 97 import org.openstreetmap.josm.plugins.core.TrainWorker; 128 98 import org.openstreetmap.josm.plugins.extractor.LanguageDetector; … … import org.openstreetmap.josm.plugins.parsers.OSMParser; 137 107 import org.openstreetmap.josm.plugins.parsers.Ontology; 138 108 import org.openstreetmap.josm.plugins.parsers.TextualStatistics; 139 109 import org.openstreetmap.josm.tools.GBC; 140 import org.openstreetmap.josm.tools.Shortcut;141 import org.openstreetmap.josm.tools.WindowGeometry;142 110 143 111 /** 144 112 * Modified PropertiesDialog(since 5633) to serve the plugin functionality. … … import org.openstreetmap.josm.tools.WindowGeometry; 146 114 * @author imis-nkarag 147 115 */ 148 116 149 class OSMRecPluginHelper {117 class OSMRecPluginHelper extends TagEditHelper { 150 118 151 private final DefaultTableModel tagData;152 private final Map<String, Map<String, Integer>> valueCount;153 119 private static Collection<String> fileHistory; 154 120 private Map<File, Double> filesAndWeights = new HashMap<>(); 155 121 private boolean useCombinedModel = false; … … class OSMRecPluginHelper { 170 136 private String customSVMModelPath; 171 137 private final String combinedModelClasses; 172 138 private final String combinedModel; 173 174 // Selection that we are editing by using both dialogs175 Collection<OsmPrimitive> sel;176 177 private String changedKey;178 private String objKey;179 180 Comparator<AutoCompletionListItem> defaultACItemComparator = new Comparator<AutoCompletionListItem>() {181 @Override182 public int compare(AutoCompletionListItem o1, AutoCompletionListItem o2) {183 return String.CASE_INSENSITIVE_ORDER.compare(o1.getValue(), o2.getValue());184 }185 };186 139 187 140 private String lastAddKey = null; 188 141 private String lastAddValue = null; … … class OSMRecPluginHelper { 197 150 return size() > MAX_LRU_TAGS_NUMBER; 198 151 } 199 152 }; 200 201 153 202 OSMRecPluginHelper(DefaultTableModel propertyData, Map<String, Map<String, Integer>> valueCount) { 203 this.tagData = propertyData; 204 this.valueCount = valueCount; 154 OSMRecPluginHelper(JTable tagTable, DefaultTableModel propertyData, Map<String, Map<String, Integer>> valueCount) { 155 super(tagTable, propertyData, valueCount); 205 156 fileHistory = Main.pref.getCollection("file-open.history"); 206 157 if(!fileHistory.isEmpty()){ 207 158 MAIN_PATH = (String) fileHistory.toArray()[0]; … … class OSMRecPluginHelper { 225 176 226 177 } 227 178 228 /** 229 * Open the add selection dialog and add a new key/value to the table (and 230 * to the dataset, of course). 231 */ 232 public void addTag() { 233 changedKey = null; 234 sel = Main.main.getInProgressSelection(); 235 if (sel == null || sel.isEmpty()) return; 236 237 final AddTagsDialog addDialog = new AddTagsDialog(); 238 239 addDialog.showDialog(); 240 241 addDialog.destroyActions(); 242 if (addDialog.getValue() == 1) 243 addDialog.performTagAdding(); 244 else 245 addDialog.undoAllTagsAdding(); 246 } 247 248 /** 249 * Edit the value in the tags table row. 250 * @param row The row of the table from which the value is edited. 251 * @param focusOnKey Determines if the initial focus should be set on key instead of value 252 * @since 5653 253 */ 254 public void editTag(final int row, boolean focusOnKey) { 255 changedKey = null; 256 sel = Main.main.getInProgressSelection(); 257 //if (sel == null || sel.isEmpty()) return; 258 // String key = tagData.getValueAt(row, 0).toString(); 259 String key = ""; 260 // objKey=key; 261 262 @SuppressWarnings("unchecked") 179 @Override 180 protected IEditTagDialog getEditTagDialog(int row, boolean focusOnKey, String key) { 263 181 Map<String, Integer> dumPar = new HashMap<>(); 264 182 dumPar.put(" ", -1); 265 final TrainingDialog editDialog = new TrainingDialog(key, row, 266 dumPar, focusOnKey); 267 editDialog.showDialog(); 268 //if (editDialog.getValue() !=1 ) return; 269 //editDialog.performTagEdit(); 183 return new TrainingDialog(key, row, dumPar, focusOnKey); 270 184 } 271 185 272 /** 273 * If during last editProperty call user changed the key name, this key will be returned 274 * Elsewhere, returns null. 275 * @return The modified key, or {@code null} 276 */ 277 public String getChangedKey() { 278 return changedKey; 279 } 280 281 public void resetChangedKey() { 282 changedKey = null; 283 } 284 285 /** 286 * For a given key k, return a list of keys which are used as keys for 287 * auto-completing values to increase the search space. 288 * @param key the key k 289 * @return a list of keys 290 */ 291 private static List<String> getAutocompletionKeys(String key) { 292 if ("name".equals(key) || "addr:street".equals(key)) 293 return Arrays.asList("addr:street", "name"); 294 else 295 return Arrays.asList(key); 296 } 297 298 /** 299 * Load recently used tags from preferences if needed. 300 */ 301 public void loadTagsIfNeeded() { 302 if (PROPERTY_REMEMBER_TAGS.get() && recentTags.isEmpty()) { 303 recentTags.clear(); 304 Collection<String> c = Main.pref.getCollection("properties.recent-tags"); 305 Iterator<String> it = c.iterator(); 306 String key, value; 307 while (it.hasNext()) { 308 key = it.next(); 309 value = it.next(); 310 recentTags.put(new Tag(key, value), null); 311 } 312 } 313 } 314 315 /** 316 * Store recently used tags in preferences if needed. 317 */ 318 public void saveTagsIfNeeded() { 319 if (PROPERTY_REMEMBER_TAGS.get() && !recentTags.isEmpty()) { 320 List<String> c = new ArrayList<>( recentTags.size()*2 ); 321 for (Tag t: recentTags.keySet()) { 322 c.add(t.getKey()); 323 c.add(t.getValue()); 324 } 325 Main.pref.putCollection("properties.recent-tags", c); 326 } 327 } 328 329 /** 330 * Warns user about a key being overwritten. 331 * @param action The action done by the user. Must state what key is changed 332 * @param togglePref The preference to save the checkbox state to 333 * @return {@code true} if the user accepts to overwrite key, {@code false} otherwise 334 */ 335 private boolean warnOverwriteKey(String action, String togglePref) { 336 ExtendedDialog ed = new ExtendedDialog( 337 Main.parent, 338 tr("Overwrite key"), 339 new String[]{tr("Replace"), tr("Cancel")}); 340 ed.setButtonIcons(new String[]{"purge", "cancel"}); 341 ed.setContent(action+"\n"+ tr("The new key is already used, overwrite values?")); 342 ed.setCancelButton(2); 343 ed.toggleEnable(togglePref); 344 ed.showDialog(); 345 346 return ed.getValue() == 1; 347 } 348 349 public final class TrainingDialog extends AbstractTagsDialog { 186 public final class TrainingDialog extends AbstractTagsDialog implements IEditTagDialog { 350 187 351 ListCellRenderer<AutoCompletionListItem> cellRenderer = new ListCellRenderer<AutoCompletionListItem>() {352 final DefaultListCellRenderer def = new DefaultListCellRenderer();353 @Override354 public Component getListCellRendererComponent(JList<? extends AutoCompletionListItem> list,355 AutoCompletionListItem value, int index, boolean isSelected, boolean cellHasFocus){356 Component c = def.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);357 if (c instanceof JLabel) {358 String str = value.getValue();359 if (valueCount.containsKey(objKey)) {360 Map<String, Integer> m = valueCount.get(objKey);361 if (m.containsKey(str)) {362 str = tr("{0} ({1})", str, m.get(str));363 c.setFont(c.getFont().deriveFont(Font.ITALIC + Font.BOLD));364 }365 }366 ((JLabel) c).setText(str);367 }368 return c;369 }370 };371 188 private static final int FIELD_COLUMNS = 4; 372 189 private final JTextField inputFileField; 373 190 private final JLabel inputFileLabel; … … class OSMRecPluginHelper { 975 792 }); 976 793 } 977 794 } 978 }979 980 public static final BooleanProperty PROPERTY_FIX_TAG_LOCALE = new BooleanProperty("properties.fix-tag-combobox-locale", false);981 public static final BooleanProperty PROPERTY_REMEMBER_TAGS = new BooleanProperty("properties.remember-recently-added-tags", true);982 public static final IntegerProperty PROPERTY_RECENT_TAGS_NUMBER = new IntegerProperty("properties.recently-added-tags", DEFAULT_LRU_TAGS_NUMBER);983 984 abstract class AbstractTagsDialog extends ExtendedDialog {985 AutoCompletingComboBox keys;986 AutoCompletingComboBox values;987 Component componentUnderMouse;988 989 public AbstractTagsDialog(Component parent, String title, String[] buttonTexts) {990 super(parent, title, buttonTexts);991 addMouseListener(new PopupMenuLauncher(popupMenu));992 }993 795 994 796 @Override 995 public void setupDialog() { 996 super.setupDialog(); 997 final Dimension size = getSize(); 998 // Set resizable only in width 999 setMinimumSize(size); 1000 setPreferredSize(size); 1001 // setMaximumSize does not work, and never worked, but still it seems not to bother Oracle to fix this 10-year-old bug 1002 // https://bugs.openjdk.java.net/browse/JDK-6200438 1003 // https://bugs.openjdk.java.net/browse/JDK-6464548 1004 1005 setRememberWindowGeometry(getClass().getName() + ".geometry", 1006 WindowGeometry.centerInWindow(Main.parent, size)); 797 public void performTagEdit() { 798 // do nothing 1007 799 } 1008 800 1009 801 @Override 1010 public void setVisible(boolean visible) {1011 // Do not want dialog to be resizable in height, as its size may increase each time because of the recently added tags1012 // So need to modify the stored geometry (size part only) in order to use the automatic positioning mechanism1013 if (visible) {1014 WindowGeometry geometry = initWindowGeometry();1015 Dimension storedSize = geometry.getSize();1016 Dimension size = getSize();1017 if (!storedSize.equals(size)) {1018 if (storedSize.width < size.width) {1019 storedSize.width = size.width;1020 }1021 if (storedSize.height != size.height) {1022 storedSize.height = size.height;1023 }1024 rememberWindowGeometry(geometry);1025 }1026 if(keys != null){1027 keys.setFixedLocale(PROPERTY_FIX_TAG_LOCALE.get());1028 }1029 }1030 super.setVisible(visible);1031 }1032 1033 private void selectACComboBoxSavingUnixBuffer(AutoCompletingComboBox cb) {1034 // select combobox with saving unix system selection (middle mouse paste)1035 Clipboard sysSel = Toolkit.getDefaultToolkit().getSystemSelection();1036 if(sysSel != null) {1037 Transferable old = sysSel.getContents(null);1038 cb.requestFocusInWindow();1039 cb.getEditor().selectAll();1040 sysSel.setContents(old, null);1041 } else {1042 cb.requestFocusInWindow();1043 cb.getEditor().selectAll();1044 }1045 }1046 1047 802 public void selectKeysComboBox() { 1048 // selectACComboBoxSavingUnixBuffer(keys);803 // do nothing 1049 804 } 1050 805 1051 public void selectValuesCombobox() { 1052 //selectACComboBoxSavingUnixBuffer(values); 806 @Override 807 public void selectValuesCombobox() { 808 // do nothing 1053 809 } 1054 1055 /**1056 * Create a focus handling adapter and apply in to the editor component of value1057 * autocompletion box.1058 * @param autocomplete Manager handling the autocompletion1059 * @param comparator Class to decide what values are offered on autocompletion1060 * @return The created adapter1061 */1062 protected FocusAdapter addFocusAdapter(final AutoCompletionManager autocomplete, final Comparator<AutoCompletionListItem> comparator) {1063 // get the combo box' editor component1064 JTextComponent editor = (JTextComponent)values.getEditor().getEditorComponent();1065 // Refresh the values model when focus is gained1066 FocusAdapter focus = new FocusAdapter() {1067 @Override1068 public void focusGained(FocusEvent e) {1069 String key = keys.getEditor().getItem().toString();1070 1071 List<AutoCompletionListItem> valueList = autocomplete.getValues(getAutocompletionKeys(key));1072 Collections.sort(valueList, comparator);1073 1074 values.setPossibleACItems(valueList);1075 values.getEditor().selectAll();1076 objKey=key;1077 }1078 };1079 editor.addFocusListener(focus);1080 return focus;1081 }1082 1083 protected JPopupMenu popupMenu = new JPopupMenu() {1084 JCheckBoxMenuItem fixTagLanguageCb = new JCheckBoxMenuItem(1085 new AbstractAction(tr("Use English language for tag by default")){1086 @Override1087 public void actionPerformed(ActionEvent e) {1088 boolean sel=((JCheckBoxMenuItem) e.getSource()).getState();1089 PROPERTY_FIX_TAG_LOCALE.put(sel);1090 }1091 });1092 {1093 add(fixTagLanguageCb);1094 fixTagLanguageCb.setState(PROPERTY_FIX_TAG_LOCALE.get());1095 }1096 };1097 810 } 1098 811 1099 812 class ModelSettingsDialog extends JPanel{ … … class OSMRecPluginHelper { 1536 1249 } 1537 1250 } 1538 1251 1539 class AddTagsDialog extends AbstractTagsDialog { 1540 List<JosmAction> recentTagsActions = new ArrayList<>(); 1541 1542 // Counter of added commands for possible undo 1543 private int commandCount; 1252 class AddTagsDialog extends TagEditHelper.AddTagsDialog { 1544 1253 private final JLabel recommendedClassesLabel; 1545 1254 private final JButton modelSettingsButton; 1546 1255 private final JButton addAndContinueButton; … … class OSMRecPluginHelper { 1559 1268 private static final int RECOMMENDATIONS_SIZE = 10; 1560 1269 1561 1270 public AddTagsDialog() { 1562 super(Main.parent, tr("Add value?"), new String[] {tr("OK"),tr("Cancel")}); 1563 setButtonIcons(new String[] {"ok","cancel"}); 1564 setCancelButton(2); 1565 configureContextsensitiveHelp("/Dialog/AddValue", true /* show help button */); 1271 super(); 1566 1272 final AddTagsDialog addTagsDialog = this; 1567 1273 1568 1274 loadOntology(); … … class OSMRecPluginHelper { 1682 1388 } 1683 1389 } 1684 1390 }); 1685 1686 keys = new AutoCompletingComboBox();1687 values = new AutoCompletingComboBox();1688 1391 1689 1392 mainPanel.add(new JLabel("<html>"+trn("This will change up to {0} object.", 1690 1393 "This will change up to {0} objects.", sel.size(),sel.size()) 1691 1394 +"<br><br>"+tr("Please select a key")), GBC.eol().fill(GBC.HORIZONTAL)); 1692 1395 1693 AutoCompletionManager autocomplete = Main.main.getEditLayer().data.getAutoCompletionManager();1694 List<AutoCompletionListItem> keyList = autocomplete.getKeys();1695 1696 AutoCompletionListItem itemToSelect = null;1697 // remove the object's tag keys from the list1698 Iterator<AutoCompletionListItem> iter = keyList.iterator();1699 while (iter.hasNext()) {1700 AutoCompletionListItem item = iter.next();1701 if (item.getValue().equals(lastAddKey)) {1702 itemToSelect = item;1703 }1704 for (int i = 0; i < tagData.getRowCount(); ++i) {1705 if (item.getValue().equals(tagData.getValueAt(i, 0))) {1706 if (itemToSelect == item) {1707 itemToSelect = null;1708 }1709 iter.remove();1710 break;1711 }1712 }1713 }1714 1715 Collections.sort(keyList, defaultACItemComparator);1716 keys.setPossibleACItems(keyList);1717 keys.setEditable(true);1718 1719 1396 mainPanel.add(keys, GBC.eop().fill()); 1720 1397 mainPanel.add(new JLabel(tr("Please select a value")), GBC.eol()); 1721 1398 … … class OSMRecPluginHelper { 1779 1456 categoryList.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED, Color.GRAY, Color.WHITE)); 1780 1457 categoryList.setModel(model); 1781 1458 1782 values.setEditable(true);1783 1459 mainPanel.add(values, GBC.eop().fill()); 1784 if (itemToSelect != null) {1785 keys.setSelectedItem(itemToSelect);1786 if (lastAddValue != null) {1787 values.setSelectedItem(lastAddValue);1788 }1789 }1790 1460 1791 FocusAdapter focus = addFocusAdapter(autocomplete, defaultACItemComparator); 1792 // fire focus event in advance or otherwise the popup list will be too small at first 1793 focus.focusGained(null); 1794 1795 int recentTagsToShow = PROPERTY_RECENT_TAGS_NUMBER.get(); 1796 if (recentTagsToShow > MAX_LRU_TAGS_NUMBER) { 1797 recentTagsToShow = MAX_LRU_TAGS_NUMBER; 1798 } 1799 1800 // Add tag on Shift-Enter 1801 // mainPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( 1802 // KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_MASK), "addAndContinue"); 1803 // mainPanel.getActionMap().put("addAndContinue", new AbstractAction() { 1804 // @Override 1805 // public void actionPerformed(ActionEvent e) { 1806 // performTagAdding(); 1807 // selectKeysComboBox(); 1808 // } 1809 // }); 1810 1811 suggestRecentlyAddedTags(mainPanel, recentTagsToShow, focus); 1461 suggestRecentlyAddedTags(mainPanel, focus); 1812 1462 1813 1463 mainPanel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED, Color.GRAY, Color.WHITE)); 1814 1464 listPanel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED, Color.GRAY, Color.WHITE)); … … class OSMRecPluginHelper { 1854 1504 performTagAdding(); 1855 1505 selectKeysComboBox(); 1856 1506 } 1857 1858 private void selectNumberOfTags() {1859 String s = JOptionPane.showInputDialog(this, tr("Please enter the number of recently added tags to display"));1860 if (s!=null) try {1861 int v = Integer.parseInt(s);1862 if (v>=0 && v<=MAX_LRU_TAGS_NUMBER) {1863 PROPERTY_RECENT_TAGS_NUMBER.put(v);1864 return;1865 }1866 } catch (NumberFormatException ex) {1867 Main.warn(ex);1868 }1869 JOptionPane.showMessageDialog(this, tr("Please enter integer number between 0 and {0}", MAX_LRU_TAGS_NUMBER));1870 }1871 1507 1872 private void suggestRecentlyAddedTags(JPanel mainPanel, int tagsToShow, final FocusAdapter focus) { 1873 if (!(tagsToShow > 0 && !recentTags.isEmpty())) 1874 return; 1875 1876 mainPanel.add(new JLabel(tr("Recently added tags")), GBC.eol()); 1877 1878 int count = 1; 1879 // We store the maximum number (9) of recent tags to allow dynamic change of number of tags shown in the preferences. 1880 // This implies to iterate in descending order, as the oldest elements will only be removed after we reach the maximum numbern and not the number of tags to show. 1881 // However, as Set does not allow to iterate in descending order, we need to copy its elements into a List we can access in reverse order. 1882 List<Tag> tags = new LinkedList<>(recentTags.keySet()); 1883 for (int i = tags.size()-1; i >= 0 && count <= tagsToShow; i--, count++) { 1884 final Tag t = tags.get(i); 1885 // Create action for reusing the tag, with keyboard shortcut Ctrl+(1-5) 1886 String actionShortcutKey = "properties:recent:"+count; 1887 String actionShortcutShiftKey = "properties:recent:shift:"+count; 1888 Shortcut sc = Shortcut.registerShortcut(actionShortcutKey, tr("Choose recent tag {0}", count), KeyEvent.VK_0+count, Shortcut.CTRL); 1889 final JosmAction action = new JosmAction(actionShortcutKey, null, tr("Use this tag again"), sc, false) { 1890 @Override 1891 public void actionPerformed(ActionEvent e) { 1892 keys.setSelectedItem(t.getKey()); 1893 // fix #7951, #8298 - update list of values before setting value (?) 1894 focus.focusGained(null); 1895 values.setSelectedItem(t.getValue()); 1896 selectValuesCombobox(); 1897 } 1898 }; 1899 Shortcut scShift = Shortcut.registerShortcut(actionShortcutShiftKey, tr("Apply recent tag {0}", count), KeyEvent.VK_0+count, Shortcut.CTRL_SHIFT); 1900 final JosmAction actionShift = new JosmAction(actionShortcutShiftKey, null, tr("Use this tag again"), scShift, false) { 1901 @Override 1902 public void actionPerformed(ActionEvent e) { 1903 action.actionPerformed(null); 1904 performTagAdding(); 1905 selectKeysComboBox(); 1906 } 1907 }; 1908 recentTagsActions.add(action); 1909 recentTagsActions.add(actionShift); 1910 disableTagIfNeeded(t, action); 1911 // Find and display icon 1912 ImageIcon icon = MapPaintStyles.getNodeIcon(t, false); // Filters deprecated icon 1913 if (icon == null) { 1914 // If no icon found in map style look at presets 1915 Map<String, String> map = new HashMap<>(); 1916 map.put(t.getKey(), t.getValue()); 1917 // for (TaggingPreset tp : TaggingPreset.getMatchingPresets(null, map, false)) { 1918 // icon = tp.getIcon(); 1919 // if (icon != null) { 1920 // break; 1921 // } 1922 // } 1923 // If still nothing display an empty icon 1924 if (icon == null) { 1925 icon = new ImageIcon(new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB)); 1926 } 1927 } 1928 GridBagConstraints gbc = new GridBagConstraints(); 1929 gbc.ipadx = 5; 1930 mainPanel.add(new JLabel(action.isEnabled() ? icon : GuiHelper.getDisabledIcon(icon)), gbc); 1931 // Create tag label 1932 final String color = action.isEnabled() ? "" : "; color:gray"; 1933 final JLabel tagLabel = new JLabel("<html>" 1934 + "<style>td{border:1px solid gray; font-weight:normal"+color+"}</style>" 1935 + "<table><tr><td>" + XmlWriter.encode(t.toString(), true) + "</td></tr></table></html>"); 1936 if (action.isEnabled()) { 1937 // Register action 1938 mainPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), actionShortcutKey); 1939 mainPanel.getActionMap().put(actionShortcutKey, action); 1940 mainPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(scShift.getKeyStroke(), actionShortcutShiftKey); 1941 mainPanel.getActionMap().put(actionShortcutShiftKey, actionShift); 1942 // Make the tag label clickable and set tooltip to the action description (this displays also the keyboard shortcut) 1943 tagLabel.setToolTipText((String) action.getValue(Action.SHORT_DESCRIPTION)); 1944 tagLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); 1945 tagLabel.addMouseListener(new MouseAdapter() { 1946 @Override 1947 public void mouseClicked(MouseEvent e) { 1948 action.actionPerformed(null); 1949 // add tags and close window on double-click 1950 1951 if (e.getClickCount()>1) { 1952 buttonAction(0, null); // emulate OK click and close the dialog 1953 } 1954 // add tags on Shift-Click 1955 if (e.isShiftDown()) { 1956 performTagAdding(); 1957 selectKeysComboBox(); 1958 } 1959 } 1960 }); 1961 } else { 1962 // Disable tag label 1963 tagLabel.setEnabled(false); 1964 // Explain in the tooltip why 1965 tagLabel.setToolTipText(tr("The key ''{0}'' is already used", t.getKey())); 1966 } 1967 // Finally add label to the resulting panel 1968 JPanel tagPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); 1969 tagPanel.add(tagLabel); 1970 mainPanel.add(tagPanel, GBC.eol().fill(GBC.HORIZONTAL)); 1971 } 1972 } 1973 1974 public void destroyActions() { 1975 for (JosmAction action : recentTagsActions) { 1976 action.destroy(); 1977 } 1978 } 1979 1980 /** 1981 * Read tags from comboboxes and add it to all selected objects 1982 */ 1983 public final void performTagAdding() { 1984 String key = Tag.removeWhiteSpaces(keys.getEditor().getItem().toString()); 1985 String value = Tag.removeWhiteSpaces(values.getEditor().getItem().toString()); 1986 if (key.isEmpty() || value.isEmpty()) return; 1987 for (OsmPrimitive osm: sel) { 1988 String val = osm.get(key); 1989 if (val != null && !val.equals(value)) { 1990 if (!warnOverwriteKey(tr("You changed the value of ''{0}'' from ''{1}'' to ''{2}''.", key, val, value), 1991 "overwriteAddKey")) 1992 return; 1993 break; 1994 } 1995 } 1996 lastAddKey = key; 1997 lastAddValue = value; 1998 recentTags.put(new Tag(key, value), null); 1999 AutoCompletionManager.rememberUserInput(key, value, false); 2000 commandCount++; 2001 Main.main.undoRedo.add(new ChangePropertyCommand(sel, key, value)); 2002 changedKey = key; 2003 } 2004 2005 public void undoAllTagsAdding() { 2006 Main.main.undoRedo.undo(commandCount); 2007 } 2008 2009 private void disableTagIfNeeded(final Tag t, final JosmAction action) { 2010 // Disable action if its key is already set on the object (the key being absent from the keys list for this reason 2011 // performing this action leads to autocomplete to the next key (see #7671 comments) 2012 for (int j = 0; j < tagData.getRowCount(); ++j) { 2013 if (t.getKey().equals(tagData.getValueAt(j, 0))) { 2014 action.setEnabled(false); 2015 break; 2016 } 2017 } 1508 @Override 1509 protected void clearEntries() { 1510 // do nothing 2018 1511 } 2019 1512 2020 1513 private void loadSVMmodel() {