Ticket #21408: 21408-2.patch

File 21408-2.patch, 15.4 KB (added by marcello@…, 4 years ago)

Fixes vanishing icons, and scrollpane size if icons have different sizes. Also disables multiselect if the selected primitives have different values.

  • src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetItemGuiSupport.java

     
    3030    private final ListenerList<ChangeListener> listeners = ListenerList.create();
    3131
    3232    /** whether to fire events or not */
    33     private boolean enabled = false;
     33    private boolean enabled;
    3434
    3535    /**
    3636     * Returns whether firing of events is enabled
  • src/org/openstreetmap/josm/gui/tagging/presets/items/Combo.java

     
    1212import java.awt.event.ComponentEvent;
    1313import java.util.Arrays;
    1414import java.util.Comparator;
    15 import java.util.TreeMap;
    1615
    1716import javax.swing.AbstractAction;
    1817import javax.swing.JButton;
     
    8887    protected boolean addToPanel(JPanel p, TaggingPresetItemGuiSupport support) {
    8988        initializeLocaleText(null);
    9089        usage = determineTextUsage(support.getSelected(), key);
    91         seenValues = new TreeMap<>();
     90        seenValues.clear();
    9291        // get the standard values from the preset definition
    9392        initListEntries();
    9493
    9594        // init the model
    96         dropDownModel = new AutoCompComboBoxModel<PresetListEntry>(Comparator.naturalOrder());
     95        dropDownModel = new AutoCompComboBoxModel<>(Comparator.<PresetListEntry>naturalOrder());
    9796
    9897        if (!usage.hasUniqueValue() && !usage.unused()) {
    9998            addEntry(PresetListEntry.ENTRY_DIFFERENT);
     
    124123        combobox.setRenderer(new ComboMultiSelectListCellRenderer(combobox, combobox.getRenderer(), 200, key));
    125124        combobox.setEditable(editable);
    126125
    127         autoCompModel = new AutoCompComboBoxModel<AutoCompletionItem>(Comparator.naturalOrder());
     126        autoCompModel = new AutoCompComboBoxModel<>(Comparator.<AutoCompletionItem>naturalOrder());
    128127        getAllForKeys(Arrays.asList(key)).forEach(autoCompModel::addElement);
    129128        getDisplayValues().forEach(s -> autoCompModel.addElement(new AutoCompletionItem(s, AutoCompletionPriority.IS_IN_STANDARD)));
    130129
     
    154153            p.add(combobox, GBC.eol().fill(GBC.HORIZONTAL)); // NOSONAR
    155154        }
    156155
    157         String valueToSelect = getInitialValue(default_);
     156        String valueToSelect = getInitialValue(usage);
    158157        if (valueToSelect != null) {
    159158            PresetListEntry selItem = find(valueToSelect);
    160159            if (selItem != null) {
  • src/org/openstreetmap/josm/gui/tagging/presets/items/ComboMultiSelect.java

     
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
    66import java.awt.Component;
     7import java.awt.Font;
    78import java.lang.reflect.Method;
    89import java.lang.reflect.Modifier;
    910import java.util.ArrayList;
     
    9091     */
    9192    protected final List<PresetListEntry> presetListEntries = new ArrayList<>();
    9293    /** Helps avoid duplicate list entries */
    93     protected Map<String, PresetListEntry> seenValues = new TreeMap<>();
     94    protected final Map<String, PresetListEntry> seenValues = new TreeMap<>();
    9495    protected Usage usage;
    9596    /** Used to see if the user edited the value. May be null. */
    9697    protected String originalValue;
     
    130131            JList<? extends PresetListEntry> list, PresetListEntry value, int index, boolean isSelected, boolean cellHasFocus) {
    131132
    132133            JLabel l = (JLabel) renderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
     134            l.setComponentOrientation(component.getComponentOrientation());
    133135            if (index != -1) {
    134136                // index -1 is set when measuring the size of the cell and when painting the
    135137                // editor-ersatz of a readonly combobox. fixes #6157
    136138                l.setText(value.getListDisplay(width));
    137139            }
     140            if (value.getCount() > 0) {
     141                l.setFont(l.getFont().deriveFont(Font.ITALIC + Font.BOLD));
     142            }
     143            l.setIcon(value.getIcon());
    138144            l.setToolTipText(value.getToolTipText(key));
    139             l.setIcon(value.getIcon());
    140145            return l;
    141146        }
    142147    }
     
    220225        }
    221226    }
    222227
    223     private List<String> getValuesFromCode(String values_from) {
     228    private List<String> getValuesFromCode(String valuesFrom) {
    224229        // get the values from a Java function
    225         String[] classMethod = values_from.split("#", -1);
     230        String[] classMethod = valuesFrom.split("#", -1);
    226231        if (classMethod.length == 2) {
    227232            try {
    228233                Method method = Class.forName(classMethod[0]).getMethod(classMethod[1]);
     
    314319     * <p>
    315320     * The initial value is the value shown in the control when the preset dialogs opens.
    316321     *
    317      * @param def The default value
     322     * @param usage The key Usage
    318323     * @return The initial value to use.
    319324     */
    320     protected String getInitialValue(String def) {
     325    protected String getInitialValue(Usage usage) {
    321326        String initialValue = null;
     327        originalValue = null;
    322328
    323329        if (usage.hasUniqueValue()) {
    324330            // all selected primitives have the same not empty value for this key
    325331            initialValue = usage.getFirst();
     332            originalValue = initialValue;
    326333        } else if (!usage.unused()) {
    327334            // at least one primitive has a value for this key (but not all have the same one)
    328335            initialValue = DIFFERENT;
     336            originalValue = initialValue;
    329337        } else if (PROP_FILL_DEFAULT.get() || isForceUseLastAsDefault()) {
    330338            // at this point no primitive had any value for this key
    331339            // use the last value no matter what
     
    335343            initialValue = LAST_VALUES.get(key);
    336344        } else if (!usage.hadKeys()) {
    337345            // use the default only on objects with no keys at all
    338             initialValue = def;
     346            initialValue = default_;
    339347        }
    340         originalValue = initialValue;
    341348        return initialValue;
    342349    }
    343350
  • src/org/openstreetmap/josm/gui/tagging/presets/items/KeyedItem.java

     
    106106        public final SortedMap<String, Integer> map = new TreeMap<>();
    107107        private boolean hadKeys;
    108108        private boolean hadEmpty;
     109        private int selectedCount;
    109110
    110111        /**
    111112         * Check if there is exactly one value for this key.
     
    139140        public boolean hadKeys() {
    140141            return hadKeys;
    141142        }
     143
     144        /**
     145         * Returns the number of primitives selected.
     146         * @return the number of primitives selected.
     147         */
     148        public int getSelectedCount() {
     149            return selectedCount;
     150        }
     151
     152        /**
     153         * Splits multiple values and adds their usage counts as single value.
     154         * <p>
     155         * A value of {@code regional;pizza} will increment the count of {@code regional} and of
     156         * {@code pizza}.
     157         * @param delimiter The delimiter used for splitting.
     158         * @return A new usage object with the new counts.
     159         */
     160        public Usage splitValues(String delimiter) {
     161            Usage usage = new Usage();
     162            usage.hadEmpty = hadEmpty;
     163            usage.hadKeys = hadKeys;
     164            usage.selectedCount = selectedCount;
     165            map.forEach((value, count) -> {
     166                for (String v : value.split(String.valueOf(delimiter), -1)) {
     167                    usage.map.merge(v, count, Integer::sum);
     168                }
     169            });
     170            return usage;
     171        }
    142172    }
    143173
    144174    /**
     
    149179     */
    150180    public static Usage determineTextUsage(Collection<OsmPrimitive> sel, String key) {
    151181        Usage returnValue = new Usage();
     182        returnValue.selectedCount = sel.size();
    152183        for (OsmPrimitive s : sel) {
    153184            String v = s.get(key);
    154185            if (v != null) {
     
    165196
    166197    protected static Usage determineBooleanUsage(Collection<OsmPrimitive> sel, String key) {
    167198        Usage returnValue = new Usage();
     199        returnValue.selectedCount = sel.size();
    168200        for (OsmPrimitive s : sel) {
    169201            String booleanValue = OsmUtils.getNamedOsmBoolean(s.get(key));
    170202            if (booleanValue != null) {
  • src/org/openstreetmap/josm/gui/tagging/presets/items/MultiSelect.java

     
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.gui.tagging.presets.items;
    33
    4 import java.util.TreeMap;
     4import java.awt.Dimension;
     5import java.awt.Insets;
     6import java.awt.Rectangle;
    57import java.util.stream.Collectors;
    68
    79import javax.swing.DefaultListModel;
     
    4042    protected boolean addToPanel(JPanel p, TaggingPresetItemGuiSupport support) {
    4143        initializeLocaleText(null);
    4244        usage = determineTextUsage(support.getSelected(), key);
    43         seenValues = new TreeMap<>();
     45        seenValues.clear();
    4446        initListEntries();
    4547
    4648        model.clear();
    47         if (!usage.hasUniqueValue() && !usage.unused()) {
    48             addEntry(PresetListEntry.ENTRY_DIFFERENT);
     49        // disable if the selected primitives have different values
     50        list.setEnabled(usage.hasUniqueValue() || usage.unused());
     51        String initialValue = getInitialValue(usage);
     52
     53        // Add values from the preset.
     54        presetListEntries.forEach(this::addEntry);
     55
     56        // Add all values used in the selected primitives. This also adds custom values and makes
     57        // sure we won't lose them.
     58        usage = usage.splitValues(String.valueOf(delimiter));
     59        for (String value: usage.map.keySet()) {
     60            addEntry(new PresetListEntry(value, this));
    4961        }
    5062
    51         String initialValue = getInitialValue(default_);
    52         if (initialValue != null) {
    53             // add all values already present to the list, otherwise we would remove all
    54             // custom entries unknown to the preset
     63        // Select the values in the initial value.
     64        if (initialValue != null && !DIFFERENT.equals(initialValue)) {
    5565            for (String value : initialValue.split(String.valueOf(delimiter), -1)) {
    5666                PresetListEntry e = new PresetListEntry(value, this);
    5767                addEntry(e);
     
    6070            }
    6171        }
    6272
    63         presetListEntries.forEach(this::addEntry);
    64 
    6573        ComboMultiSelectListCellRenderer renderer = new ComboMultiSelectListCellRenderer(list, list.getCellRenderer(), 200, key);
    6674        list.setCellRenderer(renderer);
     75        JLabel label = addLabel(p);
     76        label.setLabelFor(list);
     77        JScrollPane sp = new JScrollPane(list);
    6778
    6879        if (rows > 0) {
    6980            list.setVisibleRowCount(rows);
     81            // setVisibleRowCount() only works when all cells have the same height, but sometimes we
     82            // have icons of different sizes. Calculate the size of the first {@code rows} entries
     83            // and size the scrollpane accordingly.
     84            Rectangle r = list.getCellBounds(0, Math.min(rows, model.size() - 1));
     85            Insets insets = list.getInsets();
     86            r.width += insets.left + insets.right;
     87            r.height += insets.top + insets.bottom;
     88            insets = sp.getInsets();
     89            r.width += insets.left + insets.right;
     90            r.height += insets.top + insets.bottom;
     91            sp.setPreferredSize(new Dimension(r.width, r.height));
    7092        }
    71         JLabel label = addLabel(p);
    72         p.add(new JScrollPane(list), GBC.eol().fill(GBC.HORIZONTAL)); // NOSONAR
    73         label.setLabelFor(list);
     93        p.add(sp, GBC.eol().fill(GBC.HORIZONTAL)); // NOSONAR
    7494
    7595        list.addListSelectionListener(l -> support.fireItemValueModified(this, key, getSelectedItem().value));
    7696        list.setToolTipText(getKeyTooltipText());
     
    82102    @Override
    83103    protected PresetListEntry getSelectedItem() {
    84104        return new PresetListEntry(list.getSelectedValuesList()
    85             .stream().map(e -> e.value).collect(Collectors.joining(String.valueOf(delimiter))), this);
     105            .stream().map(e -> e.value).distinct().sorted().collect(Collectors.joining(String.valueOf(delimiter))), this);
    86106    }
    87107}
  • src/org/openstreetmap/josm/gui/tagging/presets/items/PresetListEntry.java

     
    4747    /** The localized version of {@link #short_description}. */
    4848    public String locale_short_description; // NOSONAR
    4949
    50     private String cachedDisplayValue = null;
    51     private String cachedShortDescription = null;
    52     private ImageIcon cachedIcon = null;
     50    private String cachedDisplayValue;
     51    private String cachedShortDescription;
     52    private ImageIcon cachedIcon;
    5353
    5454    /**
    5555     * Constructs a new {@code PresetListEntry}, uninitialized.
     
    8282     */
    8383    public String getListDisplay(int width) {
    8484        String displayValue = getDisplayValue();
    85         Integer count = cms == null ? null : cms.usage.map.get(value);
     85        Integer count = getCount();
    8686
    87         if (count != null) {
    88             displayValue = String.format("%s (%d)", displayValue, count);
     87        if (count > 0 && cms.usage.getSelectedCount() > 1) {
     88            displayValue = tr("{0} ({1})", displayValue, count);
    8989        }
    9090
    9191        if (this.equals(ENTRY_DIFFERENT)) {
     
    183183        return Objects.hash(value);
    184184    }
    185185
     186    /**
     187     * Returns how many selected primitives had this value set.
     188     * @return see above
     189     */
     190    public int getCount() {
     191        Integer count = cms == null ? null : cms.usage.map.get(value);
     192        return count == null ? 0 : count;
     193    }
     194
    186195    @Override
    187196    public int compareTo(PresetListEntry o) {
    188197        return AlphanumComparator.getInstance().compare(this.value, o.value);
  • src/org/openstreetmap/josm/gui/widgets/JosmComboBox.java

     
    4747    public static final String PROP_MAXIMUM_ROW_COUNT = "gui.combobox.maximum-row-count";
    4848
    4949    /** the configured maximum row count or null */
    50     private Integer configMaximumRowCount = null;
     50    private Integer configMaximumRowCount;
    5151
    5252    /**
    5353     * The preferred height of the combobox when closed.  Use if the items in the list dropdown are