001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.tagging.presets.items; 003 004import java.util.ArrayList; 005import java.util.Arrays; 006import java.util.Collection; 007import java.util.List; 008 009import javax.swing.JPanel; 010 011import org.openstreetmap.josm.data.osm.OsmPrimitive; 012import org.openstreetmap.josm.data.osm.OsmUtils; 013import org.openstreetmap.josm.data.osm.Tag; 014import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetItemGuiSupport; 015import org.openstreetmap.josm.gui.widgets.IconTextCheckBox; 016import org.openstreetmap.josm.gui.widgets.QuadStateCheckBox; 017import org.openstreetmap.josm.tools.GBC; 018 019/** 020 * Checkbox type. 021 */ 022public class Check extends KeyedItem { 023 024 /** the value to set when checked (default is "yes") */ 025 public String value_on = OsmUtils.TRUE_VALUE; // NOSONAR 026 /** the value to set when unchecked (default is "no") */ 027 public String value_off = OsmUtils.FALSE_VALUE; // NOSONAR 028 /** whether the off value is disabled in the dialog, i.e., only unset or yes are provided */ 029 public boolean disable_off; // NOSONAR 030 /** "on" or "off" or unset (default is unset) */ 031 public String default_; // only used for tagless objects // NOSONAR 032 033 private QuadStateCheckBox check; 034 private QuadStateCheckBox.State initialState; 035 private Boolean def; 036 037 @Override 038 public boolean addToPanel(JPanel p, TaggingPresetItemGuiSupport support) { 039 040 // find out if our key is already used in the selection. 041 final Usage usage = determineBooleanUsage(support.getSelected(), key); 042 final String oneValue = usage.map.isEmpty() ? null : usage.map.lastKey(); 043 def = "on".equals(default_) ? Boolean.TRUE : "off".equals(default_) ? Boolean.FALSE : null; 044 045 initializeLocaleText(null); 046 047 if (usage.map.size() < 2 && (oneValue == null || value_on.equals(oneValue) || value_off.equals(oneValue))) { 048 if (def != null && !PROP_FILL_DEFAULT.get()) { 049 // default is set and filling default values feature is disabled - check if all primitives are untagged 050 for (OsmPrimitive s : support.getSelected()) { 051 if (s.hasKeys()) { 052 def = null; 053 } 054 } 055 } 056 057 // all selected objects share the same value which is either true or false or unset, 058 // we can display a standard check box. 059 initialState = value_on.equals(oneValue) || Boolean.TRUE.equals(def) 060 ? QuadStateCheckBox.State.SELECTED 061 : value_off.equals(oneValue) || Boolean.FALSE.equals(def) 062 ? QuadStateCheckBox.State.NOT_SELECTED 063 : QuadStateCheckBox.State.UNSET; 064 065 } else { 066 def = null; 067 // the objects have different values, or one or more objects have something 068 // else than true/false. we display a quad-state check box 069 // in "partial" state. 070 initialState = QuadStateCheckBox.State.PARTIAL; 071 } 072 073 final List<QuadStateCheckBox.State> allowedStates = new ArrayList<>(4); 074 if (QuadStateCheckBox.State.PARTIAL == initialState) 075 allowedStates.add(QuadStateCheckBox.State.PARTIAL); 076 allowedStates.add(QuadStateCheckBox.State.SELECTED); 077 if (!disable_off || value_off.equals(oneValue)) 078 allowedStates.add(QuadStateCheckBox.State.NOT_SELECTED); 079 allowedStates.add(QuadStateCheckBox.State.UNSET); 080 check = new QuadStateCheckBox(icon == null ? locale_text : null, initialState, 081 allowedStates.toArray(new QuadStateCheckBox.State[0])); 082 check.setPropertyText(key); 083 check.setState(check.getState()); // to update the tooltip text 084 check.setComponentPopupMenu(getPopupMenu()); 085 086 if (icon != null) { 087 JPanel checkPanel = IconTextCheckBox.wrap(check, locale_text, getIcon()); 088 checkPanel.applyComponentOrientation(support.getDefaultComponentOrientation()); 089 p.add(checkPanel, GBC.eol()); // Do not fill, see #15104 090 } else { 091 check.applyComponentOrientation(support.getDefaultComponentOrientation()); 092 p.add(check, GBC.eol()); // Do not fill, see #15104 093 } 094 check.addChangeListener(l -> support.fireItemValueModified(this, key, getValue())); 095 return true; 096 } 097 098 @Override 099 public void addCommands(List<Tag> changedTags) { 100 // if the user hasn't changed anything, don't create a command. 101 if (def == null && check.getState() == initialState) return; 102 103 // otherwise change things according to the selected value. 104 changedTags.add(new Tag(key, getValue())); 105 } 106 107 protected String getValue() { 108 return check.getState() == QuadStateCheckBox.State.SELECTED ? value_on : 109 check.getState() == QuadStateCheckBox.State.NOT_SELECTED ? value_off : 110 null; 111 } 112 113 @Override 114 public MatchType getDefaultMatch() { 115 return MatchType.NONE; 116 } 117 118 @Override 119 public Collection<String> getValues() { 120 return disable_off ? Arrays.asList(value_on) : Arrays.asList(value_on, value_off); 121 } 122 123 @Override 124 public String toString() { 125 return "Check [key=" + key + ", text=" + text + ", " 126 + (locale_text != null ? "locale_text=" + locale_text + ", " : "") 127 + (value_on != null ? "value_on=" + value_on + ", " : "") 128 + (value_off != null ? "value_off=" + value_off + ", " : "") 129 + "default_=" + default_ + ", " 130 + (check != null ? "check=" + check + ", " : "") 131 + (initialState != null ? "initialState=" + initialState 132 + ", " : "") + "def=" + def + ']'; 133 } 134}