001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.command.conflict;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.util.Objects;
007
008import org.openstreetmap.josm.Main;
009import org.openstreetmap.josm.command.Command;
010import org.openstreetmap.josm.data.conflict.Conflict;
011import org.openstreetmap.josm.data.conflict.ConflictCollection;
012import org.openstreetmap.josm.gui.layer.OsmDataLayer;
013
014/**
015 * This is the common base class for {@link Command}s which manipulate {@link Conflict}s in
016 * addition to {@link org.openstreetmap.josm.data.osm.OsmPrimitive}s.
017 *
018 * A ConflictResolverCommand can remember a collection of conflicts it resolves. Upon undoing
019 * it reconstitutes them.
020 *
021 */
022public abstract class ConflictResolveCommand extends Command {
023    /** the list of resolved conflicts */
024    private final ConflictCollection resolvedConflicts;
025
026    /**
027     * Constructs a new {@code ConflictResolveCommand} in the context of the current edit layer, if any.
028     */
029    public ConflictResolveCommand() {
030        super();
031        resolvedConflicts = new ConflictCollection();
032    }
033
034    /**
035     * Constructs a new {@code ConflictResolveCommand} in the context of a given data layer.
036     * @param layer the data layer. Must not be null.
037     */
038    public ConflictResolveCommand(OsmDataLayer layer) {
039        super(layer);
040        resolvedConflicts = new ConflictCollection();
041    }
042
043    /**
044     * remembers a conflict in the internal list of remembered conflicts
045     *
046     * @param c the remembered conflict
047     */
048    protected void rememberConflict(Conflict<?> c) {
049        if (!resolvedConflicts.hasConflictForMy(c.getMy())) {
050            resolvedConflicts.add(c);
051        }
052    }
053
054    /**
055     * reconstitutes all remembered conflicts. Add the remembered conflicts to the
056     * set of conflicts of the {@link OsmDataLayer} this command was applied to.
057     *
058     */
059    protected void reconstituteConflicts() {
060        OsmDataLayer editLayer = getLayer();
061        for (Conflict<?> c : resolvedConflicts) {
062            if (!editLayer.getConflicts().hasConflictForMy(c.getMy())) {
063                editLayer.getConflicts().add(c);
064            }
065        }
066    }
067
068    @Override
069    public void undoCommand() {
070        super.undoCommand();
071
072        if (Main.isDisplayingMapView()) {
073            if (!Main.map.mapView.hasLayer(getLayer())) {
074                Main.warn(tr("Cannot undo command ''{0}'' because layer ''{1}'' is not present any more",
075                        this.toString(),
076                        getLayer().toString()
077                ));
078                return;
079            }
080
081            Main.map.mapView.setActiveLayer(getLayer());
082        }
083        reconstituteConflicts();
084    }
085
086    @Override
087    public int hashCode() {
088        return Objects.hash(super.hashCode(), resolvedConflicts);
089    }
090
091    @Override
092    public boolean equals(Object obj) {
093        if (this == obj) return true;
094        if (obj == null || getClass() != obj.getClass()) return false;
095        if (!super.equals(obj)) return false;
096        ConflictResolveCommand that = (ConflictResolveCommand) obj;
097        return Objects.equals(resolvedConflicts, that.resolvedConflicts);
098    }
099}