001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.util;
003
004import java.util.Collection;
005import java.util.Collections;
006import java.util.HashSet;
007import java.util.Iterator;
008import java.util.Set;
009
010import org.openstreetmap.josm.Main;
011import org.openstreetmap.josm.data.osm.DataSet;
012import org.openstreetmap.josm.data.osm.OsmPrimitive;
013import org.openstreetmap.josm.data.osm.Relation;
014
015/**
016 * This class stores the set of highlited primitives and
017 * allows easy and fast change of highlighting
018 */
019public class HighlightHelper {
020    Set<OsmPrimitive> highlightedPrimitives = new HashSet<>();
021
022    /**
023     * Highlight and remember given primitives
024     * @param prims - primitives to highlight/unhighlight
025     */
026    public boolean highlight(Collection <? extends OsmPrimitive> prims) {
027        return highlight(prims, false);
028    }
029
030    /**
031     * Highlight and remember given primitives
032     * @param prims - primitives to highlight/unhighlight
033     * @param only - remove previous highlighting
034     */
035    public boolean highlight(Collection <? extends OsmPrimitive> prims, boolean only) {
036        boolean needsRepaint = false;
037        if (only) {
038            Iterator<OsmPrimitive> it = highlightedPrimitives.iterator();
039            while (it.hasNext()) {
040                OsmPrimitive p = it.next();
041                if (!prims.contains(p)) {
042                    p.setHighlighted(false);
043                    it.remove();
044                    needsRepaint = true;
045                }
046            }
047        }
048        for (OsmPrimitive p: prims) {
049            needsRepaint |= setHighlight(p, true);
050        }
051
052        return needsRepaint;
053    }
054
055    /**
056     * Highlight and remember given primitives, forgetting previously highlighted by this instance
057     * @param prims - primitives to highlight/unhighlight
058     */
059    public boolean highlightOnly(Collection <? extends OsmPrimitive> prims) {
060        return highlight(prims, true);
061    }
062
063    /**
064     * Highlight and remember given primitive, forgetting previously highlighted by this instance
065     * @param p - primitives to highlight/unhighlight
066     */
067    public boolean highlightOnly(OsmPrimitive p) {
068        return highlight(Collections.singleton(p), true);
069    }
070
071    /**
072     * Highlight and remember given primitive
073     * @param p - primitive to highlight/unhighlight
074     * @param flag - true to highlight
075     */
076    public boolean setHighlight(OsmPrimitive p, boolean flag) {
077        return setHighlight(p, flag, new HashSet<Relation>());
078    }
079
080    private boolean setHighlight(OsmPrimitive p, boolean flag, Set<Relation> seenRelations) {
081        if (p instanceof Relation) {
082            Relation r = (Relation) p;
083            seenRelations.add(r);
084            boolean needRepaint = false;
085            for (OsmPrimitive m : r.getMemberPrimitives()) {
086                if (!(m instanceof Relation) || !seenRelations.contains(m)) {
087                    needRepaint |= setHighlight(m, flag, seenRelations);
088                }
089            }
090            return needRepaint;
091        } else if (flag) {
092            if (highlightedPrimitives.add(p)) {
093                p.setHighlighted(true);
094                return true;
095            }
096        } else {
097            if (highlightedPrimitives.remove(p)) {
098                p.setHighlighted(false);
099                return true;
100            }
101        }
102        return false;
103    }
104
105    /**
106     * Clear highlighting of all remembered primitives
107     */
108    public void clear() {
109        for (OsmPrimitive p: highlightedPrimitives) {
110            p.setHighlighted(false);
111        }
112        highlightedPrimitives.clear();
113    }
114
115    /**
116     * Slow method to import all currently highlighted primitives into this instance
117     */
118    public void findAllHighlighted() {
119        DataSet ds = Main.main.getCurrentDataSet();
120        if (ds!=null) {
121            highlightedPrimitives.addAll( ds.allNonDeletedPrimitives() );
122        }
123    }
124
125    /**
126     * Slow method to remove highlights from all primitives
127     */
128    public static void clearAllHighlighted() {
129        DataSet ds = Main.main.getCurrentDataSet();
130        if (ds!=null) {
131            for (OsmPrimitive p: ds.allNonDeletedPrimitives()) {
132                p.setHighlighted(false);
133            }
134        }
135    }
136}