001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.io;
003
004import java.awt.BorderLayout;
005import java.util.HashMap;
006import java.util.Map;
007import java.util.Observable;
008import java.util.Observer;
009
010import javax.swing.JPanel;
011import javax.swing.event.TableModelEvent;
012import javax.swing.event.TableModelListener;
013
014import org.openstreetmap.josm.Main;
015import org.openstreetmap.josm.data.Version;
016import org.openstreetmap.josm.data.osm.Changeset;
017import org.openstreetmap.josm.gui.tagging.TagEditorPanel;
018import org.openstreetmap.josm.gui.tagging.TagModel;
019import org.openstreetmap.josm.tools.CheckParameterUtil;
020
021public class TagSettingsPanel extends JPanel implements TableModelListener {
022
023    /** checkbox for selecting whether an atomic upload is to be used  */
024    private final TagEditorPanel pnlTagEditor = new TagEditorPanel(null, null, Changeset.MAX_CHANGESET_TAG_LENGTH);
025    /** the model for the changeset comment */
026    private final transient ChangesetCommentModel changesetCommentModel;
027    private final transient ChangesetCommentModel changesetSourceModel;
028    /** tags that applied to uploaded changesets by default*/
029    private final transient Map<String, String> defaultTags = new HashMap<>();
030
031    protected void build() {
032        setLayout(new BorderLayout());
033        add(pnlTagEditor, BorderLayout.CENTER);
034    }
035
036    /**
037     * Creates a new panel
038     *
039     * @param changesetCommentModel the changeset comment model. Must not be null.
040     * @param changesetSourceModel the changeset source model. Must not be null.
041     * @throws IllegalArgumentException if {@code changesetCommentModel} is null
042     */
043    public TagSettingsPanel(ChangesetCommentModel changesetCommentModel, ChangesetCommentModel changesetSourceModel) {
044        CheckParameterUtil.ensureParameterNotNull(changesetCommentModel, "changesetCommentModel");
045        CheckParameterUtil.ensureParameterNotNull(changesetSourceModel, "changesetSourceModel");
046        this.changesetCommentModel = changesetCommentModel;
047        this.changesetSourceModel = changesetSourceModel;
048        this.changesetCommentModel.addObserver(new ChangesetCommentObserver("comment"));
049        this.changesetSourceModel.addObserver(new ChangesetCommentObserver("source"));
050        build();
051        pnlTagEditor.getModel().addTableModelListener(this);
052    }
053
054    protected void setProperty(String key, String value) {
055        if (value == null) {
056            value = "";
057        }
058        value = value.trim();
059        String commentInTag = getTagEditorValue(key);
060        if (value.equals(commentInTag))
061            return;
062
063        if (value.isEmpty()) {
064            pnlTagEditor.getModel().delete(key);
065            return;
066        }
067        TagModel tag = pnlTagEditor.getModel().get(key);
068        if (tag == null) {
069            tag = new TagModel(key, value);
070            pnlTagEditor.getModel().add(tag);
071        } else {
072            pnlTagEditor.getModel().updateTagValue(tag, value);
073        }
074    }
075
076    protected String getTagEditorValue(String key) {
077        TagModel tag = pnlTagEditor.getModel().get(key);
078        if (tag == null) return null;
079        return tag.getValue();
080    }
081
082    /**
083     * Initialize panel from changeset.
084     * @param cs changeset
085     */
086    public void initFromChangeset(Changeset cs) {
087        Map<String, String> tags = getDefaultTags();
088        if (cs != null) {
089            tags.putAll(cs.getKeys());
090        }
091        if (tags.get("comment") == null) {
092            tags.put("comment", getTagEditorValue("comment"));
093        }
094        if (tags.get("source") == null) {
095            tags.put("source", getTagEditorValue("source"));
096        }
097        String agent = Version.getInstance().getAgentString(false);
098        String created_by = tags.get("created_by");
099        if (created_by == null || created_by.isEmpty()) {
100            tags.put("created_by", agent);
101        } else if (!created_by.contains(agent)) {
102            tags.put("created_by", created_by + ';' + agent);
103        }
104        pnlTagEditor.getModel().initFromTags(tags);
105    }
106
107    /**
108     * Replies the map with the current tags in the tag editor model.
109     * @param keepEmpty {@code true} to keep empty tags
110     * @return the map with the current tags in the tag editor model.
111     */
112    public Map<String, String> getTags(boolean keepEmpty) {
113        return pnlTagEditor.getModel().getTags(keepEmpty);
114    }
115
116    /**
117     * Replies the map with the default tags.
118     * @return the map with the default tags
119     */
120    public Map<String, String> getDefaultTags() {
121        Map<String, String> tags = new HashMap<>();
122        tags.putAll(defaultTags);
123        return tags;
124    }
125
126    /**
127     * Sets the map with the default tags.
128     * @param tags the map with the default tags
129     */
130    public void setDefaultTags(Map<String, String> tags) {
131        defaultTags.clear();
132        defaultTags.putAll(tags);
133        tableChanged(null);
134    }
135
136    public void startUserInput() {
137        pnlTagEditor.initAutoCompletion(Main.main.getEditLayer());
138    }
139
140    /* -------------------------------------------------------------------------- */
141    /* Interface TableChangeListener                                              */
142    /* -------------------------------------------------------------------------- */
143    @Override
144    public void tableChanged(TableModelEvent e) {
145        changesetCommentModel.setComment(getTagEditorValue("comment"));
146        changesetSourceModel.setComment(getTagEditorValue("source"));
147    }
148
149    /**
150     * Observes the changeset comment model and keeps the tag editor in sync
151     * with the current changeset comment
152     *
153     */
154    class ChangesetCommentObserver implements Observer {
155
156        private final String key;
157
158        ChangesetCommentObserver(String key) {
159            this.key = key;
160        }
161
162        @Override
163        public void update(Observable o, Object arg) {
164            if (!(o instanceof ChangesetCommentModel)) return;
165            String newValue = (String) arg;
166            String oldValue = getTagEditorValue(key);
167            if (oldValue == null) {
168                oldValue = "";
169            }
170            if (!oldValue.equals(newValue)) {
171                setProperty(key, (String) arg);
172            }
173        }
174    }
175}