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("/Dialog/HistoryBrowser")));
100        btn.setName("btn.help");
101        pnl.add(btn);
102        add(pnl, BorderLayout.SOUTH);
103
104        HelpUtil.setHelpContext(getRootPane(), ht("/Dialog/HistoryBrowser"));
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
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
156    class CloseAction extends AbstractAction {
157        public CloseAction() {
158            putValue(NAME, tr("Close"));
159            putValue(SHORT_DESCRIPTION, tr("Close the dialog"));
160            putValue(SMALL_ICON, ImageProvider.get("ok"));
161        }
162
163        public void run() {
164            getHistoryBrowser().getModel().unlinkAsListener();
165            HistoryDataSet.getInstance().removeHistoryDataSetListener(HistoryBrowserDialog.this);
166            HistoryBrowserDialogManager.getInstance().hide(HistoryBrowserDialog.this);
167        }
168
169        @Override
170        public void actionPerformed(ActionEvent e) {
171            run();
172        }
173    }
174
175    class ReloadAction extends AbstractAction {
176        public ReloadAction() {
177            putValue(NAME, tr("Reload"));
178            putValue(SHORT_DESCRIPTION, tr("Reload the history from the server"));
179            putValue(SMALL_ICON, ImageProvider.get("dialogs", "refresh"));
180        }
181
182        @Override
183        public void actionPerformed(ActionEvent e) {
184            HistoryLoadTask task = new HistoryLoadTask();
185            task.add(browser.getHistory());
186            Main.worker.submit(task);
187        }
188    }
189
190    class WindowClosingAdapter extends WindowAdapter {
191        @Override
192        public void windowClosing(WindowEvent e) {
193            closeAction.run();
194        }
195    }
196
197    /**
198     * Replies the history browser.
199     * @return the history browser
200     */
201    public HistoryBrowser getHistoryBrowser() {
202        return browser;
203    }
204}