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.help.ContextSensitiveHelpAction;
026import org.openstreetmap.josm.gui.help.HelpUtil;
027import org.openstreetmap.josm.gui.util.GuiHelper;
028import org.openstreetmap.josm.tools.ImageProvider;
029import org.openstreetmap.josm.tools.InputMapUtils;
030
031/**
032 * This is non-modal dialog, always showing on top, which displays history information
033 * about a given {@link org.openstreetmap.josm.data.osm.OsmPrimitive}.
034 * @since 1709
035 */
036public class HistoryBrowserDialog extends JDialog implements HistoryDataSetListener {
037
038    /** the embedded browser */
039    private final HistoryBrowser browser = new HistoryBrowser();
040    private final CloseAction closeAction = new CloseAction();
041    private final JLabel titleLabel = new JLabel("", JLabel.CENTER);
042
043    /**
044     * Constructs a new {@code HistoryBrowserDialog}.
045     *
046     * @param history the history to be displayed
047     */
048    public HistoryBrowserDialog(History history) {
049        super(GuiHelper.getFrameForComponent(Main.parent), false);
050        build();
051        setHistory(history);
052        setTitle(buildTitle(history));
053        pack();
054        if (getInsets().top > 0) {
055            titleLabel.setVisible(false);
056        }
057        HistoryDataSet.getInstance().addHistoryDataSetListener(this);
058        addWindowListener(new WindowClosingAdapter());
059    }
060
061    /**
062     * Constructs the title for this dialog
063     *
064     * @param h the current history
065     * @return the title for this dialog
066     */
067    static String buildTitle(History h) {
068        String title;
069        switch (h.getEarliest().getType()) {
070        case NODE: title = marktr("History for node {0}");
071            break;
072        case WAY: title = marktr("History for way {0}");
073            break;
074        case RELATION: title = marktr("History for relation {0}");
075            break;
076        default: title = "";
077        }
078        return tr(title, Long.toString(h.getId()));
079    }
080
081    @Override
082    public void setTitle(String title) {
083        super.setTitle(title);
084        if (titleLabel != null) {
085            titleLabel.setText(title);
086        }
087    }
088
089    /**
090     * builds the GUI
091     */
092    protected void build() {
093        setLayout(new BorderLayout());
094
095        add(titleLabel, BorderLayout.NORTH);
096
097        add(browser, BorderLayout.CENTER);
098
099        JPanel pnl = new JPanel(new FlowLayout(FlowLayout.CENTER));
100
101        JButton btn = new JButton(new ReloadAction());
102        btn.setName("btn.reload");
103        pnl.add(btn);
104
105        btn = new JButton(closeAction);
106        final String closeHistoryBrowserDialogKey = "CloseHistoryBrowserDialog";
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        closeAction.run();
151    }
152
153    class CloseAction extends AbstractAction {
154        CloseAction() {
155            putValue(NAME, tr("Close"));
156            putValue(SHORT_DESCRIPTION, tr("Close the dialog"));
157            new ImageProvider("ok").getResource().attachImageIcon(this);
158        }
159
160        public void run() {
161            getHistoryBrowser().getModel().unlinkAsListener();
162            HistoryDataSet.getInstance().removeHistoryDataSetListener(HistoryBrowserDialog.this);
163            HistoryBrowserDialogManager.getInstance().hide(HistoryBrowserDialog.this);
164        }
165
166        @Override
167        public void actionPerformed(ActionEvent e) {
168            run();
169        }
170    }
171
172    class ReloadAction extends AbstractAction {
173        ReloadAction() {
174            putValue(NAME, tr("Reload"));
175            putValue(SHORT_DESCRIPTION, tr("Reload the history from the server"));
176            new ImageProvider("dialogs", "refresh").getResource().attachImageIcon(this);
177        }
178
179        @Override
180        public void actionPerformed(ActionEvent e) {
181            HistoryLoadTask task = new HistoryLoadTask();
182            task.add(browser.getHistory());
183            Main.worker.submit(task);
184        }
185    }
186
187    class WindowClosingAdapter extends WindowAdapter {
188        @Override
189        public void windowClosing(WindowEvent e) {
190            closeAction.run();
191        }
192    }
193
194    /**
195     * Replies the history browser.
196     * @return the history browser
197     */
198    public HistoryBrowser getHistoryBrowser() {
199        return browser;
200    }
201}