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