source: josm/trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java@ 2055

Last change on this file since 2055 was 2055, checked in by Gubaer, 15 years ago

fixed #3393: loooong delay when using presets with a large osm file
Initializing only one cache for autocompletion; now initializing in background thread, preset dialog should pop up immediately

  • Property svn:eol-style set to native
File size: 29.5 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.gui.tagging;
3
4import static org.openstreetmap.josm.tools.I18n.marktr;
5import static org.openstreetmap.josm.tools.I18n.tr;
6import static org.openstreetmap.josm.tools.I18n.trn;
7
8import java.awt.Component;
9import java.awt.GridBagLayout;
10import java.awt.Image;
11import java.awt.event.ActionEvent;
12import java.io.BufferedReader;
13import java.io.IOException;
14import java.io.InputStreamReader;
15import java.io.Reader;
16import java.io.UnsupportedEncodingException;
17import java.util.Arrays;
18import java.util.Collection;
19import java.util.HashMap;
20import java.util.LinkedHashMap;
21import java.util.LinkedList;
22import java.util.List;
23import java.util.TreeSet;
24
25import javax.swing.AbstractAction;
26import javax.swing.Action;
27import javax.swing.ImageIcon;
28import javax.swing.JComboBox;
29import javax.swing.JComponent;
30import javax.swing.JLabel;
31import javax.swing.JOptionPane;
32import javax.swing.JPanel;
33import javax.swing.JTextField;
34
35import org.openstreetmap.josm.Main;
36import org.openstreetmap.josm.command.ChangePropertyCommand;
37import org.openstreetmap.josm.command.Command;
38import org.openstreetmap.josm.command.SequenceCommand;
39import org.openstreetmap.josm.data.osm.Node;
40import org.openstreetmap.josm.data.osm.OsmPrimitive;
41import org.openstreetmap.josm.data.osm.OsmUtils;
42import org.openstreetmap.josm.data.osm.Relation;
43import org.openstreetmap.josm.data.osm.Way;
44import org.openstreetmap.josm.gui.ExtendedDialog;
45import org.openstreetmap.josm.gui.QuadStateCheckBox;
46import org.openstreetmap.josm.gui.layer.OsmDataLayer;
47import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionCache;
48import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionItemPritority;
49import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
50import org.openstreetmap.josm.io.MirroredInputStream;
51import org.openstreetmap.josm.tools.GBC;
52import org.openstreetmap.josm.tools.ImageProvider;
53import org.openstreetmap.josm.tools.UrlLabel;
54import org.openstreetmap.josm.tools.XmlObjectParser;
55import org.xml.sax.SAXException;
56
57/**
58 * This class read encapsulate one tagging preset. A class method can
59 * read in all predefined presets, either shipped with JOSM or that are
60 * in the config directory.
61 *
62 * It is also able to construct dialogs out of preset definitions.
63 */
64public class TaggingPreset extends AbstractAction {
65
66 public TaggingPresetMenu group = null;
67 public String name;
68 public String locale_name;
69
70 private static AutoCompletionList autoCompletionList;
71
72 public static AutoCompletionList getPresetAutocompletionList() {
73 if (autoCompletionList == null) {
74 autoCompletionList = new AutoCompletionList();
75 }
76 return autoCompletionList;
77 }
78
79 public static abstract class Item {
80 protected void initAutoCompletionField(AutoCompletingTextField field, String key) {
81 OsmDataLayer layer = Main.main.getEditLayer();
82 if (layer == null) return;
83 field.setAutoCompletionList(getPresetAutocompletionList());
84 }
85
86 public boolean focus = false;
87 abstract boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel);
88 abstract void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds);
89 boolean requestFocusInWindow() {return false;}
90 }
91
92 public static class Usage {
93 TreeSet<String> values;
94 boolean hadKeys = false;
95 boolean hadEmpty = false;
96 public boolean hasUniqueValue() {
97 return values.size() == 1 && !hadEmpty;
98 }
99
100 public boolean unused() {
101 return values.size() == 0;
102 }
103 public String getFirst() {
104 return values.first();
105 }
106
107 public boolean hadKeys() {
108 return hadKeys;
109 }
110 }
111
112 public static final String DIFFERENT = tr("<different>");
113
114 static Usage determineTextUsage(Collection<OsmPrimitive> sel, String key) {
115 Usage returnValue = new Usage();
116 returnValue.values = new TreeSet<String>();
117 for (OsmPrimitive s : sel) {
118 String v = s.get(key);
119 if (v != null) {
120 returnValue.values.add(v);
121 } else {
122 returnValue.hadEmpty = true;
123 }
124 returnValue.hadKeys = ! returnValue.values.isEmpty() | returnValue.hadEmpty;
125 }
126 return returnValue;
127 }
128
129 static Usage determineBooleanUsage(Collection<OsmPrimitive> sel, String key) {
130
131 Usage returnValue = new Usage();
132 returnValue.values = new TreeSet<String>();
133 for (OsmPrimitive s : sel) {
134 returnValue.values.add(OsmUtils.getNamedOsmBoolean(s.get(key)));
135 }
136 return returnValue;
137 }
138
139 public static class Text extends Item {
140
141 public String key;
142 public String text;
143 public String locale_text;
144 public String default_;
145 public String originalValue;
146 public boolean use_last_as_default = false;
147 public boolean delete_if_empty = false;
148
149 private JComponent value;
150
151
152 @Override public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
153
154 // find out if our key is already used in the selection.
155 Usage usage = determineTextUsage(sel, key);
156 if (usage.unused()){
157 AutoCompletingTextField textField = new AutoCompletingTextField();
158 initAutoCompletionField(textField, key);
159 if (use_last_as_default && lastValue.containsKey(key)) {
160 textField.setText(lastValue.get(key));
161 } else {
162 textField.setText(default_);
163 }
164 value = textField;
165 originalValue = null;
166 } else if (usage.hasUniqueValue()) {
167 // all objects use the same value
168 AutoCompletingTextField textField = new AutoCompletingTextField();
169 initAutoCompletionField(textField, key);
170 textField.setText(usage.getFirst());
171 value = textField;
172 originalValue = usage.getFirst();
173 } else {
174 // the objects have different values
175 AutoCompletingTextField textField = new AutoCompletingTextField();
176 initAutoCompletionField(textField, key);
177 JComboBox comboBox = new JComboBox(usage.values.toArray());
178 comboBox.setEditable(true);
179 comboBox.setEditor(textField);
180 comboBox.getEditor().setItem(DIFFERENT);
181 value=comboBox;
182 originalValue = DIFFERENT;
183 }
184 if(locale_text == null) {
185 locale_text = tr(text);
186 }
187 p.add(new JLabel(locale_text+":"), GBC.std().insets(0,0,10,0));
188 p.add(value, GBC.eol().fill(GBC.HORIZONTAL));
189 return true;
190 }
191
192 @Override public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {
193
194 // return if unchanged
195 String v = (value instanceof JComboBox) ?
196 ((JComboBox)value).getEditor().getItem().toString() :
197 ((JTextField)value).getText();
198
199 if (use_last_as_default) {
200 lastValue.put(key, v);
201 }
202 if (v.equals(originalValue) || (originalValue == null && v.length() == 0)) return;
203
204 if (delete_if_empty && v.length() == 0) {
205 v = null;
206 }
207 cmds.add(new ChangePropertyCommand(sel, key, v));
208 }
209 @Override boolean requestFocusInWindow() {return value.requestFocusInWindow();}
210 }
211
212 public static class Check extends Item {
213
214 public String key;
215 public String text;
216 public String locale_text;
217 public boolean default_ = false; // only used for tagless objects
218 public boolean use_last_as_default = false;
219
220 private QuadStateCheckBox check;
221 private QuadStateCheckBox.State initialState;
222 private boolean def;
223
224 @Override public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
225
226 // find out if our key is already used in the selection.
227 Usage usage = determineBooleanUsage(sel, key);
228 def = default_;
229
230 if(locale_text == null) {
231 locale_text = tr(text);
232 }
233
234 String oneValue = null;
235 for (String s : usage.values) {
236 oneValue = s;
237 }
238 if (usage.values.size() < 2 && (oneValue == null || OsmUtils.trueval.equals(oneValue) || OsmUtils.falseval.equals(oneValue))) {
239 if(def)
240 {
241 for (OsmPrimitive s : sel)
242 if(s.hasKeys()) {
243 def = false;
244 }
245 }
246
247 // all selected objects share the same value which is either true or false or unset,
248 // we can display a standard check box.
249 initialState = OsmUtils.trueval.equals(oneValue) ?
250 QuadStateCheckBox.State.SELECTED :
251 OsmUtils.falseval.equals(oneValue) ?
252 QuadStateCheckBox.State.NOT_SELECTED :
253 def ? QuadStateCheckBox.State.SELECTED
254 : QuadStateCheckBox.State.UNSET;
255 check = new QuadStateCheckBox(locale_text, initialState,
256 new QuadStateCheckBox.State[] {
257 QuadStateCheckBox.State.SELECTED,
258 QuadStateCheckBox.State.NOT_SELECTED,
259 QuadStateCheckBox.State.UNSET });
260 } else {
261 def = false;
262 // the objects have different values, or one or more objects have something
263 // else than true/false. we display a quad-state check box
264 // in "partial" state.
265 initialState = QuadStateCheckBox.State.PARTIAL;
266 check = new QuadStateCheckBox(locale_text, QuadStateCheckBox.State.PARTIAL,
267 new QuadStateCheckBox.State[] {
268 QuadStateCheckBox.State.PARTIAL,
269 QuadStateCheckBox.State.SELECTED,
270 QuadStateCheckBox.State.NOT_SELECTED,
271 QuadStateCheckBox.State.UNSET });
272 }
273 p.add(check, GBC.eol().fill(GBC.HORIZONTAL));
274 return true;
275 }
276
277 @Override public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {
278 // if the user hasn't changed anything, don't create a command.
279 if (check.getState() == initialState && !def) return;
280
281 // otherwise change things according to the selected value.
282 cmds.add(new ChangePropertyCommand(sel, key,
283 check.getState() == QuadStateCheckBox.State.SELECTED ? OsmUtils.trueval :
284 check.getState() == QuadStateCheckBox.State.NOT_SELECTED ? OsmUtils.falseval :
285 null));
286 }
287 @Override boolean requestFocusInWindow() {return check.requestFocusInWindow();}
288 }
289
290 public static class Combo extends Item {
291
292 public String key;
293 public String text;
294 public String locale_text;
295 public String values;
296 public String display_values;
297 public String locale_display_values;
298 public String default_;
299 public boolean delete_if_empty = false;
300 public boolean editable = true;
301 public boolean use_last_as_default = false;
302
303 private JComboBox combo;
304 private LinkedHashMap<String,String> lhm;
305 private Usage usage;
306 private String originalValue;
307
308 @Override public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
309
310 // find out if our key is already used in the selection.
311 usage = determineTextUsage(sel, key);
312
313 String[] value_array = values.split(",");
314 String[] display_array;
315 if(locale_display_values != null) {
316 display_array = locale_display_values.split(",");
317 } else if(display_values != null) {
318 display_array = display_values.split(",");
319 } else {
320 display_array = value_array;
321 }
322
323 lhm = new LinkedHashMap<String,String>();
324 if (!usage.hasUniqueValue() && !usage.unused()){
325 lhm.put(DIFFERENT, DIFFERENT);
326 }
327 for (int i=0; i<value_array.length; i++) {
328 lhm.put(value_array[i],
329 (locale_display_values == null) ?
330 tr(display_array[i]) : display_array[i]);
331 }
332 if(!usage.unused()){
333 for (String s : usage.values) {
334 if (!lhm.containsKey(s)) {
335 lhm.put(s, s);
336 }
337 }
338 }
339 if (default_ != null && !lhm.containsKey(default_)) {
340 lhm.put(default_, default_);
341 }
342 if(!lhm.containsKey("")) {
343 lhm.put("", "");
344 }
345
346 combo = new JComboBox(lhm.values().toArray());
347 combo.setEditable(editable);
348 AutoCompletingTextField tf = new AutoCompletingTextField();
349 initAutoCompletionField(tf, key);
350 tf.getAutoCompletionList().add(Arrays.asList(display_array), AutoCompletionItemPritority.IS_IN_STANDARD);
351 combo.setEditor(tf);
352
353 if (usage.hasUniqueValue() && !usage.unused()){
354 originalValue=usage.getFirst();
355 combo.setSelectedItem(lhm.get(originalValue));
356 }
357 // use default only in case it is a totally new entry
358 else if(default_ != null && !usage.hadKeys()) {
359 combo.setSelectedItem(default_);
360 originalValue=DIFFERENT;
361 }
362 else if(usage.unused()){
363 combo.setSelectedItem("");
364 originalValue="";
365 }
366 else{
367 combo.setSelectedItem(DIFFERENT);
368 originalValue=DIFFERENT;
369 }
370
371 if(locale_text == null) {
372 locale_text = tr(text);
373 }
374 p.add(new JLabel(locale_text+":"), GBC.std().insets(0,0,10,0));
375 p.add(combo, GBC.eol().fill(GBC.HORIZONTAL));
376 return true;
377 }
378 @Override public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {
379 Object obj = combo.getSelectedItem();
380 String display = (obj == null) ? null : obj.toString();
381 String value = null;
382 if(display == null && combo.isEditable()) {
383 display = combo.getEditor().getItem().toString();
384 }
385
386 if (display != null)
387 {
388 for (String key : lhm.keySet()) {
389 String k = lhm.get(key);
390 if (k != null && k.equals(display)) {
391 value=key;
392 }
393 }
394 if(value == null) {
395 value = display;
396 }
397 } else {
398 value = "";
399 }
400
401 // no change if same as before
402 if (value.equals(originalValue) || (originalValue == null && value.length() == 0)) return;
403
404 if (delete_if_empty && value.length() == 0) {
405 value = null;
406 }
407 cmds.add(new ChangePropertyCommand(sel, key, value));
408 }
409 @Override boolean requestFocusInWindow() {return combo.requestFocusInWindow();}
410 }
411
412 public static class Label extends Item {
413 public String text;
414 public String locale_text;
415
416 @Override public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
417 if(locale_text == null) {
418 locale_text = tr(text);
419 }
420 p.add(new JLabel(locale_text), GBC.eol());
421 return false;
422 }
423 @Override public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {}
424 }
425
426 public static class Link extends Item {
427 public String href;
428 public String text;
429 public String locale_text;
430 public String locale_href;
431
432 @Override public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
433 if(locale_text == null) {
434 locale_text = text == null ? tr("More information about this feature") : tr(text);
435 }
436 String url = locale_href;
437 if (url == null) {
438 url = href;
439 }
440 if (url != null) {
441 p.add(new UrlLabel(url, locale_text), GBC.eol().anchor(GBC.WEST));
442 }
443 return false;
444 }
445 @Override public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {}
446 }
447
448 public static class Optional extends Item {
449 // TODO: Draw a box around optional stuff
450 @Override public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
451 p.add(new JLabel(" "), GBC.eol()); // space
452 p.add(new JLabel(tr("Optional Attributes:")), GBC.eol());
453 p.add(new JLabel(" "), GBC.eol()); // space
454 return false;
455 }
456 @Override public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {}
457 }
458
459 public static class Space extends Item {
460 @Override public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
461 p.add(new JLabel(" "), GBC.eol()); // space
462 return false;
463 }
464 @Override public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {}
465 }
466
467 public static class Key extends Item {
468 public String key;
469 public String value;
470
471 @Override public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel) { return false; }
472 @Override public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {
473 cmds.add(new ChangePropertyCommand(sel, key, value != null && !value.equals("") ? value : null));
474 }
475 }
476
477 /**
478 * The types as preparsed collection.
479 */
480 public List<String> types;
481 public List<Item> data = new LinkedList<Item>();
482 private static HashMap<String,String> lastValue = new HashMap<String,String>();
483
484 /**
485 * Create an empty tagging preset. This will not have any items and
486 * will be an empty string as text. createPanel will return null.
487 * Use this as default item for "do not select anything".
488 */
489 public TaggingPreset() {}
490
491 /**
492 * Change the display name without changing the toolbar value.
493 */
494 public void setDisplayName() {
495 putValue(Action.NAME, getName());
496 putValue("toolbar", "tagging_" + getRawName());
497 putValue(SHORT_DESCRIPTION, (group != null ?
498 tr("Use preset ''{0}'' of group ''{1}''", getLocaleName(), group.getName()) :
499 tr("Use preset ''{0}''", getLocaleName())));
500 }
501
502 public String getLocaleName() {
503 if(locale_name == null) {
504 locale_name = tr(name);
505 }
506 return locale_name;
507 }
508
509 public String getName() {
510 return group != null ? group.getName() + "/" + getLocaleName() : getLocaleName();
511 }
512 public String getRawName() {
513 return group != null ? group.getRawName() + "/" + name : name;
514 }
515 /**
516 * Called from the XML parser to set the icon
517 *
518 * FIXME for Java 1.6 - use 24x24 icons for LARGE_ICON_KEY (button bar)
519 * and the 16x16 icons for SMALL_ICON.
520 */
521 public void setIcon(String iconName) {
522 Collection<String> s = Main.pref.getCollection("taggingpreset.icon.sources", null);
523 ImageIcon icon = ImageProvider.getIfAvailable(s, "presets", null, iconName);
524 if (icon == null)
525 {
526 System.out.println("Could not get presets icon " + iconName);
527 icon = new ImageIcon(iconName);
528 }
529 if (Math.max(icon.getIconHeight(), icon.getIconWidth()) != 16) {
530 icon = new ImageIcon(icon.getImage().getScaledInstance(16, 16, Image.SCALE_SMOOTH));
531 }
532 putValue(Action.SMALL_ICON, icon);
533 }
534
535 /**
536 * Called from the XML parser to set the types this preset affects
537 */
538 private static Collection<String> allowedtypes = Arrays.asList(new String[]
539 {marktr("way"), marktr("node"), marktr("relation"), marktr("closedway")});
540 public void setType(String types) throws SAXException {
541 this.types = Arrays.asList(types.split(","));
542 for (String type : this.types) {
543 if(!allowedtypes.contains(type))
544 throw new SAXException(tr("Unknown type: {0}", type));
545 }
546 }
547
548 public static List<TaggingPreset> readAll(Reader in) throws SAXException {
549 XmlObjectParser parser = new XmlObjectParser();
550 parser.mapOnStart("item", TaggingPreset.class);
551 parser.mapOnStart("separator", TaggingPresetSeparator.class);
552 parser.mapBoth("group", TaggingPresetMenu.class);
553 parser.map("text", Text.class);
554 parser.map("link", Link.class);
555 parser.mapOnStart("optional", Optional.class);
556 parser.map("check", Check.class);
557 parser.map("combo", Combo.class);
558 parser.map("label", Label.class);
559 parser.map("space", Space.class);
560 parser.map("key", Key.class);
561 LinkedList<TaggingPreset> all = new LinkedList<TaggingPreset>();
562 TaggingPresetMenu lastmenu = null;
563 parser.start(in);
564 while(parser.hasNext()) {
565 Object o = parser.next();
566 if (o instanceof TaggingPresetMenu) {
567 TaggingPresetMenu tp = (TaggingPresetMenu) o;
568 if(tp == lastmenu) {
569 lastmenu = tp.group;
570 } else
571 {
572 tp.setDisplayName();
573 tp.group = lastmenu;
574 lastmenu = tp;
575 all.add(tp);
576 Main.toolbar.register(tp);
577
578 }
579 } else if (o instanceof TaggingPresetSeparator) {
580 TaggingPresetSeparator tp = (TaggingPresetSeparator) o;
581 tp.group = lastmenu;
582 all.add(tp);
583 } else if (o instanceof TaggingPreset) {
584 TaggingPreset tp = (TaggingPreset) o;
585 tp.group = lastmenu;
586 tp.setDisplayName();
587 all.add(tp);
588 Main.toolbar.register(tp);
589 } else {
590 all.getLast().data.add((Item)o);
591 }
592 }
593 return all;
594 }
595
596 public static Collection<TaggingPreset> readFromPreferences() {
597 LinkedList<TaggingPreset> allPresets = new LinkedList<TaggingPreset>();
598 LinkedList<String> sources = new LinkedList<String>();
599
600 if(Main.pref.getBoolean("taggingpreset.enable-defaults", true)) {
601 sources.add("resource://presets/presets.xml");
602 }
603 sources.addAll(Main.pref.getCollection("taggingpreset.sources", new LinkedList<String>()));
604
605 for(String source : sources)
606 {
607 try {
608 MirroredInputStream s = new MirroredInputStream(source);
609 InputStreamReader r;
610 try
611 {
612 r = new InputStreamReader(s, "UTF-8");
613 }
614 catch (UnsupportedEncodingException e)
615 {
616 r = new InputStreamReader(s);
617 }
618 allPresets.addAll(TaggingPreset.readAll(new BufferedReader(r)));
619 } catch (IOException e) {
620 e.printStackTrace();
621 JOptionPane.showMessageDialog(
622 Main.parent,
623 tr("Could not read tagging preset source: {0}",source),
624 tr("Error"),
625 JOptionPane.ERROR_MESSAGE
626 );
627 } catch (SAXException e) {
628 e.printStackTrace();
629 JOptionPane.showMessageDialog(
630 Main.parent,
631 tr("Error parsing {0}: ", source)+e.getMessage(),
632 tr("Error"),
633 JOptionPane.ERROR_MESSAGE
634 );
635 }
636 }
637 return allPresets;
638 }
639
640 private class PresetPanel extends JPanel {
641 boolean hasElements = false;
642 PresetPanel()
643 {
644 super(new GridBagLayout());
645 }
646 }
647
648 protected void refreshAutocompletionList(final OsmDataLayer layer) {
649 Runnable task = new Runnable() {
650 public void run() {
651 System.out.print("refreshing preset auto completion list ...");
652 AutoCompletionCache.getCacheForLayer(layer).initFromDataSet();
653 AutoCompletionCache.getCacheForLayer(layer).populateWithValues( getPresetAutocompletionList(), false /* don't append */);
654 System.out.println("DONE");
655 }
656 };
657 new Thread(task).run();
658
659 }
660 public PresetPanel createPanel(Collection<OsmPrimitive> selected) {
661 if (data == null)
662 return null;
663 OsmDataLayer layer = Main.main.getEditLayer();
664 if (layer != null) {
665 refreshAutocompletionList(layer);
666 }
667 PresetPanel p = new PresetPanel();
668 LinkedList<Item> l = new LinkedList<Item>();
669 if(types != null){
670 JPanel pp = new JPanel();
671 for(String t : types){
672 JLabel la = new JLabel(ImageProvider.get("Mf_" + t));
673 la.setToolTipText(tr("Elements of type {0} are supported.", tr(t)));
674 pp.add(la);
675 }
676 p.add(pp, GBC.eol());
677 }
678
679 for (Item i : data){
680 if(i instanceof Link) {
681 l.add(i);
682 } else {
683 if(i.addToPanel(p, selected)) {
684 p.hasElements = true;
685 }
686 }
687 }
688 for(Item link : l) {
689 link.addToPanel(p, selected);
690 }
691 return p;
692 }
693
694 public void actionPerformed(ActionEvent e) {
695 Collection<OsmPrimitive> sel = createSelection(Main.main.getCurrentDataSet().getSelected());
696 PresetPanel p = createPanel(sel);
697 if (p == null)
698 return;
699
700 int answer = 1;
701 if (p.getComponentCount() != 0 && (sel.size() == 0 || p.hasElements)) {
702 String title = trn("Change {0} object", "Change {0} objects", sel.size(), sel.size());
703 if(sel.size() == 0) {
704 if(originalSelectionEmpty) {
705 title = tr("Nothing selected!");
706 } else {
707 title = tr("Selection unsuitable!");
708 }
709 }
710
711 class PresetDialog extends ExtendedDialog {
712 public PresetDialog(Component content, String title, boolean disableApply) {
713 super(Main.parent,
714 title,
715 new String[] { tr("Apply Preset"), tr("Cancel") },
716 true);
717 contentConstraints = GBC.eol().fill().insets(5,10,5,0);
718 setButtonIcons(new String[] {"ok.png", "cancel.png" });
719 setContent(content);
720 setupDialog();
721 buttons.get(0).setEnabled(!disableApply);
722 buttons.get(0).setToolTipText(title);
723 setVisible(true);
724 }
725 }
726
727 answer = new PresetDialog(p, title, (sel.size() == 0)).getValue();
728 }
729 if (sel.size() != 0 && answer == 1) {
730 Command cmd = createCommand(sel);
731 if (cmd != null) {
732 Main.main.undoRedo.add(cmd);
733 }
734 }
735 Main.main.getCurrentDataSet().setSelected(Main.main.getCurrentDataSet().getSelected()); // force update
736 }
737
738 /**
739 * True whenever the original selection given into createSelection was empty
740 */
741 private boolean originalSelectionEmpty = false;
742
743 /**
744 * Removes all unsuitable OsmPrimitives from the given list
745 * @param participants List of possibile OsmPrimitives to tag
746 * @return Cleaned list with suitable OsmPrimitives only
747 */
748 private Collection<OsmPrimitive> createSelection(Collection<OsmPrimitive> participants) {
749 originalSelectionEmpty = participants.size() == 0;
750 Collection<OsmPrimitive> sel = new LinkedList<OsmPrimitive>();
751 for (OsmPrimitive osm : participants)
752 {
753 if (types != null)
754 {
755 if(osm instanceof Relation)
756 {
757 if(!types.contains("relation")) {
758 continue;
759 }
760 }
761 else if(osm instanceof Node)
762 {
763 if(!types.contains("node")) {
764 continue;
765 }
766 }
767 else if(osm instanceof Way)
768 {
769 if(!types.contains("way") &&
770 !(types.contains("closedway") && ((Way)osm).isClosed())) {
771 continue;
772 }
773 }
774 }
775 sel.add(osm);
776 }
777 return sel;
778 }
779
780 private Command createCommand(Collection<OsmPrimitive> sel) {
781 List<Command> cmds = new LinkedList<Command>();
782 for (Item i : data) {
783 i.addCommands(sel, cmds);
784 }
785 if (cmds.size() == 0)
786 return null;
787 else if (cmds.size() == 1)
788 return cmds.get(0);
789 else
790 return new SequenceCommand(tr("Change Properties"), cmds);
791 }
792}
Note: See TracBrowser for help on using the repository browser.