001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.preferences.sources;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.util.ArrayList;
007import java.util.Arrays;
008import java.util.Collection;
009import java.util.List;
010import java.util.Map;
011import java.util.Objects;
012import java.util.TreeSet;
013
014import org.openstreetmap.josm.spi.preferences.Config;
015import org.openstreetmap.josm.tools.ImageProvider;
016import org.openstreetmap.josm.tools.Utils;
017
018/**
019 * Helper class for map paint styles preferences.
020 * @since 12649 (extracted from gui.preferences package)
021 */
022public class MapPaintPrefHelper extends SourcePrefHelper {
023
024    /**
025     * The unique instance.
026     */
027    public static final MapPaintPrefHelper INSTANCE = new MapPaintPrefHelper();
028
029    /**
030     * Constructs a new {@code MapPaintPrefHelper}.
031     */
032    public MapPaintPrefHelper() {
033        super("mappaint.style.entries", SourceType.MAP_PAINT_STYLE);
034    }
035
036    @Override
037    public List<SourceEntry> get() {
038        List<SourceEntry> ls = super.get();
039        if (insertNewDefaults(ls)) {
040            put(ls);
041        }
042        return ls;
043    }
044
045    /**
046     * If the selection of default styles changes in future releases, add
047     * the new entries to the user-configured list. Remember the known URLs,
048     * so an item that was deleted explicitly is not added again.
049     * @param list new defaults
050     * @return {@code true} if a change occurred
051     */
052    private boolean insertNewDefaults(List<SourceEntry> list) {
053        boolean changed = false;
054
055        Collection<String> knownDefaults = new TreeSet<>(Config.getPref().getList("mappaint.style.known-defaults"));
056
057        Collection<ExtendedSourceEntry> defaults = getDefault();
058        int insertionIdx = 0;
059        for (final SourceEntry def : defaults) {
060            int i = Utils.indexOf(list, se -> Objects.equals(def.url, se.url));
061            if (i == -1 && !knownDefaults.contains(def.url)) {
062                def.active = false;
063                list.add(insertionIdx, def);
064                insertionIdx++;
065                changed = true;
066            } else {
067                if (i >= insertionIdx) {
068                    insertionIdx = i + 1;
069                }
070            }
071            knownDefaults.add(def.url);
072        }
073        Config.getPref().putList("mappaint.style.known-defaults", new ArrayList<>(knownDefaults));
074
075        // XML style is not bundled anymore
076        list.removeIf(se -> "resource://styles/standard/elemstyles.xml".equals(se.url));
077
078        return changed;
079    }
080
081    @Override
082    public Collection<ExtendedSourceEntry> getDefault() {
083        ExtendedSourceEntry defJosmMapcss = new ExtendedSourceEntry(type, "elemstyles.mapcss", "resource://styles/standard/elemstyles.mapcss");
084        defJosmMapcss.active = true;
085        defJosmMapcss.name = "standard";
086        defJosmMapcss.icon = new ImageProvider("logo").getResource();
087        defJosmMapcss.title = tr("JOSM default (MapCSS)");
088        defJosmMapcss.description = tr("Internal style to be used as base for runtime switchable overlay styles");
089        ExtendedSourceEntry defPL2 = new ExtendedSourceEntry(type, "potlatch2.mapcss", "resource://styles/standard/potlatch2.mapcss");
090        defPL2.active = false;
091        defPL2.name = "standard";
092        defPL2.icon = new ImageProvider("dialogs/mappaint", "pl2_small").getResource();
093        defPL2.title = tr("Potlatch 2");
094        defPL2.description = tr("the main Potlatch 2 style");
095
096        return Arrays.asList(defJosmMapcss, defPL2);
097    }
098
099    @Override
100    public Map<String, String> serialize(SourceEntry entry) {
101        Map<String, String> res = super.serialize(entry);
102        res.put("active", Boolean.toString(entry.active));
103        if (entry.name != null) {
104            res.put("ptoken", entry.name);
105        }
106        return res;
107    }
108
109    @Override
110    public SourceEntry deserialize(Map<String, String> s) {
111        return new SourceEntry(type, s.get("url"), s.get("ptoken"), s.get("title"), Boolean.parseBoolean(s.get("active")));
112    }
113}