001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.history;
003
004import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
005import static org.openstreetmap.josm.tools.I18n.marktr;
006import static org.openstreetmap.josm.tools.I18n.tr;
007
008import java.awt.BorderLayout;
009import java.awt.FlowLayout;
010import java.awt.event.ActionEvent;
011import java.awt.event.WindowAdapter;
012import java.awt.event.WindowEvent;
013
014import javax.swing.AbstractAction;
015import javax.swing.JButton;
016import javax.swing.JDialog;
017import javax.swing.JLabel;
018import javax.swing.JPanel;
019
020import org.openstreetmap.josm.Main;
021import org.openstreetmap.josm.data.osm.PrimitiveId;
022import org.openstreetmap.josm.data.osm.history.History;
023import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
024import org.openstreetmap.josm.data.osm.history.HistoryDataSetListener;
025import org.openstreetmap.josm.gui.MainApplication;
026import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
027import org.openstreetmap.josm.gui.help.HelpUtil;
028import org.openstreetmap.josm.gui.util.GuiHelper;
029import org.openstreetmap.josm.tools.ImageProvider;
030import org.openstreetmap.josm.tools.InputMapUtils;
031
032/**
033 * This is non-modal dialog, always showing on top, which displays history information
034 * about a given {@link org.openstreetmap.josm.data.osm.OsmPrimitive}.
035 * @since 1709
036 */
037public class HistoryBrowserDialog extends JDialog implements HistoryDataSetListener {
038
039    /** the embedded browser */
040    private final HistoryBrowser browser = new HistoryBrowser();
041    private final CloseAction closeAction = new CloseAction();
042    private final JLabel titleLabel = new JLabel("", JLabel.CENTER);
043
044    /**
045     * Constructs a new {@code HistoryBrowserDialog}.
046     *
047     * @param history the history to be displayed
048     */
049    public HistoryBrowserDialog(History history) {
050        super(GuiHelper.getFrameForComponent(Main.parent), false);
051        build();
052        setHistory(history);
053        setTitle(buildTitle(history));
054        pack();
055        if (getInsets().top > 0) {
056            titleLabel.setVisible(false);
057        }
058        HistoryDataSet.getInstance().addHistoryDataSetListener(this);
059        addWindowListener(new WindowClosingAdapter());
060    }
061
062    /**
063     * Constructs the title for this dialog
064     *
065     * @param h the current history
066     * @return the title for this dialog
067     */
068    static String buildTitle(History h) {
069        String title;
070        switch (h.getEarliest().getType()) {
071        case NODE: title = marktr("History for node {0}");
072            break;
073        case WAY: title = marktr("History for way {0}");
074            break;
075        case RELATION: title = marktr("History for relation {0}");
076            break;
077        default: title = "";
078        }
079        return tr(title, Long.toString(h.getId()));
080    }
081
082    @Override
083    public void setTitle(String title) {
084        super.setTitle(title);
085        if (titleLabel != null) {
086            titleLabel.setText(title);
087        }
088    }
089
090    /**
091     * builds the GUI
092     */
093    protected void build() {
094        setLayout(new BorderLayout());
095
096        add(titleLabel, BorderLayout.NORTH);
097
098        add(browser, BorderLayout.CENTER);
099
100        JPanel pnl = new JPanel(new FlowLayout(FlowLayout.CENTER));
101
102        JButton btn = new JButton(new ReloadAction());
103        btn.setName("btn.reload");
104        pnl.add(btn);
105
106        btn = new JButton(closeAction);
107        btn.setName("btn.close");
108        pnl.add(btn);
109        InputMapUtils.addEscapeAction(getRootPane(), closeAction);
110
111        btn = new JButton(new ContextSensitiveHelpAction(ht("/Action/ObjectHistory")));
112        btn.setName("btn.help");
113        pnl.add(btn);
114        add(pnl, BorderLayout.SOUTH);
115
116        HelpUtil.setHelpContext(getRootPane(), ht("/Action/ObjectHistory"));
117    }
118
119    /**
120     * Sets the current history.
121     * @param history current history
122     */
123    protected void setHistory(History history) {
124        browser.populate(history);
125    }
126
127    /**
128     * Removes this history browser model as listener for data change and layer change events.
129     */
130    public void unlinkAsListener() {
131        getHistoryBrowser().getModel().unlinkAsListener();
132    }
133
134    /* ---------------------------------------------------------------------------------- */
135    /* interface HistoryDataSetListener                                                   */
136    /* ---------------------------------------------------------------------------------- */
137
138    @Override
139    public void historyUpdated(HistoryDataSet source, PrimitiveId primitiveId) {
140        if (primitiveId == null || primitiveId.equals(browser.getHistory().getPrimitiveId())) {
141            History history = source.getHistory(browser.getHistory().getPrimitiveId());
142            if (history != null) {
143                browser.populate(history);
144            }
145        }
146    }
147
148    @Override
149    public void historyDataSetCleared(HistoryDataSet source) {
150        if (isVisible()) {
151            closeAction.run();
152        }
153    }
154
155    class CloseAction extends AbstractAction {
156        CloseAction() {
157            putValue(NAME, tr("Close"));
158            putValue(SHORT_DESCRIPTION, tr("Close the dialog"));
159            new ImageProvider("ok").getResource().attachImageIcon(this);
160        }
161
162        void run() {
163            getHistoryBrowser().getModel().unlinkAsListener();
164            HistoryDataSet.getInstance().removeHistoryDataSetListener(HistoryBrowserDialog.this);
165            HistoryBrowserDialogManager.getInstance().hide(HistoryBrowserDialog.this);
166        }
167
168        @Override
169        public void actionPerformed(ActionEvent e) {
170            run();
171        }
172    }
173
174    class ReloadAction extends AbstractAction {
175        ReloadAction() {
176            putValue(NAME, tr("Reload"));
177            putValue(SHORT_DESCRIPTION, tr("Reload the history from the server"));
178            new ImageProvider("dialogs", "refresh").getResource().attachImageIcon(this);
179        }
180
181        @Override
182        public void actionPerformed(ActionEvent e) {
183            HistoryLoadTask task = new HistoryLoadTask();
184            task.add(browser.getHistory());
185            MainApplication.worker.submit(task);
186        }
187    }
188
189    class WindowClosingAdapter extends WindowAdapter {
190        @Override
191        public void windowClosing(WindowEvent e) {
192            if (isVisible()) {
193                closeAction.run();
194            }
195        }
196    }
197
198    /**
199     * Replies the history browser.
200     * @return the history browser
201     */
202    public HistoryBrowser getHistoryBrowser() {
203        return browser;
204    }
205}