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.data.osm.PrimitiveId;
021import org.openstreetmap.josm.data.osm.history.History;
022import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
023import org.openstreetmap.josm.data.osm.history.HistoryDataSetListener;
024import org.openstreetmap.josm.gui.MainApplication;
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(MainApplication.getMainFrame()), 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        btn.setName("btn.close");
107        pnl.add(btn);
108        InputMapUtils.addEscapeAction(getRootPane(), closeAction);
109
110        btn = new JButton(new ContextSensitiveHelpAction(ht("/Action/ObjectHistory")));
111        btn.setName("btn.help");
112        pnl.add(btn);
113        add(pnl, BorderLayout.SOUTH);
114
115        HelpUtil.setHelpContext(getRootPane(), ht("/Action/ObjectHistory"));
116    }
117
118    /**
119     * Sets the current history.
120     * @param history current history
121     */
122    protected void setHistory(History history) {
123        browser.populate(history);
124    }
125
126    /**
127     * Removes this history browser model as listener for data change and layer change events.
128     * @deprecated not needeed anymore, job is done in {@link #dispose}
129     */
130    @Deprecated
131    public void unlinkAsListener() {
132        getHistoryBrowser().getModel().unlinkAsListener();
133    }
134
135    /* ---------------------------------------------------------------------------------- */
136    /* interface HistoryDataSetListener                                                   */
137    /* ---------------------------------------------------------------------------------- */
138
139    @Override
140    public void historyUpdated(HistoryDataSet source, PrimitiveId primitiveId) {
141        if (primitiveId == null || primitiveId.equals(browser.getHistory().getPrimitiveId())) {
142            History history = source.getHistory(browser.getHistory().getPrimitiveId());
143            if (history != null) {
144                browser.populate(history);
145            }
146        }
147    }
148
149    @Override
150    public void historyDataSetCleared(HistoryDataSet source) {
151        if (isVisible()) {
152            closeAction.run();
153        }
154    }
155
156    class CloseAction extends AbstractAction {
157        CloseAction() {
158            putValue(NAME, tr("Close"));
159            putValue(SHORT_DESCRIPTION, tr("Close the dialog"));
160            new ImageProvider("ok").getResource().attachImageIcon(this);
161        }
162
163        void run() {
164            HistoryBrowserDialogManager.getInstance().hide(HistoryBrowserDialog.this);
165        }
166
167        @Override
168        public void actionPerformed(ActionEvent e) {
169            run();
170        }
171    }
172
173    class ReloadAction extends AbstractAction {
174        ReloadAction() {
175            putValue(NAME, tr("Reload"));
176            putValue(SHORT_DESCRIPTION, tr("Reload the history from the server"));
177            new ImageProvider("dialogs", "refresh").getResource().attachImageIcon(this);
178        }
179
180        @Override
181        public void actionPerformed(ActionEvent e) {
182            HistoryLoadTask task = new HistoryLoadTask();
183            task.add(browser.getHistory());
184            MainApplication.worker.submit(task);
185        }
186    }
187
188    class WindowClosingAdapter extends WindowAdapter {
189        @Override
190        public void windowClosing(WindowEvent e) {
191            if (isVisible()) {
192                closeAction.run();
193            }
194        }
195    }
196
197    /**
198     * Replies the history browser.
199     * @return the history browser
200     */
201    public HistoryBrowser getHistoryBrowser() {
202        return browser;
203    }
204
205    @Override
206    public void dispose() {
207        HistoryDataSet.getInstance().removeHistoryDataSetListener(this);
208        GuiHelper.destroyComponents(this, false);
209        super.dispose();
210    }
211}