001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.dialogs.relation;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.beans.PropertyChangeListener;
007import java.beans.PropertyChangeSupport;
008import java.util.Collection;
009
010import org.openstreetmap.josm.Main;
011import org.openstreetmap.josm.data.osm.Relation;
012import org.openstreetmap.josm.data.osm.RelationMember;
013import org.openstreetmap.josm.gui.ExtendedDialog;
014import org.openstreetmap.josm.gui.layer.OsmDataLayer;
015import org.openstreetmap.josm.tools.CheckParameterUtil;
016
017/**
018 * Abstract relation editor.
019 * @since 1599
020 */
021public abstract class RelationEditor extends ExtendedDialog implements IRelationEditor {
022    private static final long serialVersionUID = 1L;
023
024    /** the property name for the current relation.
025     * @see #setRelation(Relation)
026     * @see #getRelation()
027     */
028    public static final String RELATION_PROP = RelationEditor.class.getName() + ".relation";
029
030    /** the property name for the current relation snapshot
031     * @see #getRelationSnapshot()
032     */
033    public static final String RELATION_SNAPSHOT_PROP = RelationEditor.class.getName() + ".relationSnapshot";
034
035    /** The relation that this editor is working on. */
036    private transient Relation relation;
037
038    /** The version of the relation when editing is started. This is null if a new relation is created. */
039    private transient Relation relationSnapshot;
040
041    /** The data layer the relation belongs to */
042    private final transient OsmDataLayer layer;
043
044    private final PropertyChangeSupport support = new PropertyChangeSupport(this);
045
046    /**
047     * Creates a new relation editor
048     *
049     * @param layer the {@link OsmDataLayer} in whose context a relation is edited. Must not be null.
050     * @param relation the relation. Can be null if a new relation is to be edited.
051     * @throws IllegalArgumentException if layer is null
052     */
053    protected RelationEditor(OsmDataLayer layer, Relation relation) {
054        super(Main.parent,
055                "",
056                new String[] {tr("Apply Changes"), tr("Cancel")},
057                false,
058                false
059        );
060        CheckParameterUtil.ensureParameterNotNull(layer, "layer");
061        this.layer = layer;
062        setRelation(relation);
063        layer.removeRecentRelation(relation);
064    }
065
066    /**
067     * This is a factory method that creates an appropriate RelationEditor instance suitable for editing the relation
068     * that was passed in as an argument.
069     *
070     * This method is guaranteed to return a working RelationEditor.
071     *
072     * @param layer the data layer the relation is a member of
073     * @param r the relation to be edited
074     * @param selectedMembers a collection of relation members which shall be selected when the editor is first launched
075     * @return an instance of RelationEditor suitable for editing that kind of relation
076     */
077    public static RelationEditor getEditor(OsmDataLayer layer, Relation r, Collection<RelationMember> selectedMembers) {
078        if (RelationDialogManager.getRelationDialogManager().isOpenInEditor(layer, r))
079            return RelationDialogManager.getRelationDialogManager().getEditorForRelation(layer, r);
080        else {
081            RelationEditor editor = new GenericRelationEditor(layer, r, selectedMembers);
082            RelationDialogManager.getRelationDialogManager().positionOnScreen(editor);
083            RelationDialogManager.getRelationDialogManager().register(layer, r, editor);
084            return editor;
085        }
086    }
087
088    /**
089     * updates the title of the relation editor
090     */
091    protected void updateTitle() {
092        if (getRelation() == null) {
093            setTitle(tr("Create new relation in layer ''{0}''", layer.getName()));
094        } else if (getRelation().isNew()) {
095            setTitle(tr("Edit new relation in layer ''{0}''", layer.getName()));
096        } else {
097            setTitle(tr("Edit relation #{0} in layer ''{1}''", relation.getId(), layer.getName()));
098        }
099    }
100
101    @Override
102    public final Relation getRelation() {
103        return relation;
104    }
105
106    @Override
107    public final void setRelation(Relation relation) {
108        setRelationSnapshot((relation == null) ? null : new Relation(relation));
109        Relation oldValue = this.relation;
110        this.relation = relation;
111        if (this.relation != oldValue) {
112            support.firePropertyChange(RELATION_PROP, oldValue, this.relation);
113        }
114        updateTitle();
115    }
116
117    @Override
118    public final OsmDataLayer getLayer() {
119        return layer;
120    }
121
122    @Override
123    public final Relation getRelationSnapshot() {
124        return relationSnapshot;
125    }
126
127    protected final void setRelationSnapshot(Relation snapshot) {
128        Relation oldValue = relationSnapshot;
129        relationSnapshot = snapshot;
130        if (relationSnapshot != oldValue) {
131            support.firePropertyChange(RELATION_SNAPSHOT_PROP, oldValue, relationSnapshot);
132        }
133    }
134
135    @Override
136    public final boolean isDirtyRelation() {
137        return !relation.hasEqualSemanticAttributes(relationSnapshot);
138    }
139
140    /* ----------------------------------------------------------------------- */
141    /* property change support                                                 */
142    /* ----------------------------------------------------------------------- */
143
144    @Override
145    public final void addPropertyChangeListener(PropertyChangeListener listener) {
146        this.support.addPropertyChangeListener(listener);
147    }
148
149    @Override
150    public final void removePropertyChangeListener(PropertyChangeListener listener) {
151        this.support.removePropertyChangeListener(listener);
152    }
153
154    @Override
155    public void dispose() {
156        layer.setRecentRelation(relation);
157        super.dispose();
158    }
159}