001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.actions.relation;
003
004import java.util.Collection;
005import java.util.Collections;
006
007import javax.swing.AbstractAction;
008
009import org.openstreetmap.josm.actions.IPrimitiveAction;
010import org.openstreetmap.josm.data.osm.DownloadPolicy;
011import org.openstreetmap.josm.data.osm.IPrimitive;
012import org.openstreetmap.josm.data.osm.IRelation;
013import org.openstreetmap.josm.data.osm.OsmData;
014import org.openstreetmap.josm.data.osm.OsmUtils;
015import org.openstreetmap.josm.data.osm.Relation;
016import org.openstreetmap.josm.io.NetworkManager;
017import org.openstreetmap.josm.io.OnlineResource;
018import org.openstreetmap.josm.tools.Destroyable;
019import org.openstreetmap.josm.tools.SubclassFilteredCollection;
020import org.openstreetmap.josm.tools.Utils;
021
022/**
023 * Ancestor for all actions that want to work with relation collection and
024 * to be disabled if the collection is empty
025 * @since 5793
026 * @since 13957 (signature)
027 */
028public abstract class AbstractRelationAction extends AbstractAction implements IPrimitiveAction, Destroyable {
029    /** relation collection */
030    protected transient Collection<IRelation<?>> relations = Collections.<IRelation<?>>emptySet();
031
032    /**
033     * Returns the relations contained in the given collection.
034     * @param primitives collection of primitives
035     * @return the relation contained in {@code primitives}
036     */
037    protected static final Collection<IRelation<?>> getRelations(Collection<? extends IPrimitive> primitives) {
038        if (Utils.isEmpty(primitives)) {
039            return Collections.<IRelation<?>>emptySet();
040        } else {
041            return new SubclassFilteredCollection<>(primitives, IRelation.class::isInstance);
042        }
043    }
044
045    @Override
046    public void setPrimitives(Collection<? extends IPrimitive> primitives) {
047        this.relations = getRelations(primitives);
048        updateEnabledState();
049    }
050
051    /**
052     * Override in subclasses to update the enabled state of the action when something changes.
053     */
054    protected void updateEnabledState() {
055        setEnabled(!relations.isEmpty());
056    }
057
058    protected final boolean canModify() {
059        SubclassFilteredCollection<IRelation<?>, Relation> filteredRelations = Utils.filteredCollection(relations, Relation.class);
060        return OsmUtils.isOsmCollectionEditable(filteredRelations) && filteredRelations.parallelStream().anyMatch(r -> !r.isDeleted());
061    }
062
063    protected final boolean canDownload() {
064        if (relations.isEmpty()) {
065            return false;
066        }
067        OsmData<?, ?, ?, ?> ds = relations.iterator().next().getDataSet();
068        return !NetworkManager.isOffline(OnlineResource.OSM_API)
069            && ds != null && !ds.isLocked() && DownloadPolicy.BLOCKED != ds.getDownloadPolicy();
070    }
071
072    protected void setHelpId(String helpId) {
073        putValue("help", helpId);
074    }
075
076    @Override
077    public void destroy() {
078        relations = null;
079    }
080}