001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.history;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.BorderLayout;
007import java.awt.Dimension;
008
009import javax.swing.JPanel;
010import javax.swing.JScrollPane;
011import javax.swing.JSplitPane;
012import javax.swing.JTabbedPane;
013
014import org.openstreetmap.josm.data.osm.OsmPrimitive;
015import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
016import org.openstreetmap.josm.data.osm.history.History;
017import org.openstreetmap.josm.tools.Destroyable;
018
019/**
020 * HistoryBrowser is an UI component which displays history information about an {@link OsmPrimitive}.
021 *
022 * @since 1709
023 */
024public class HistoryBrowser extends JPanel implements Destroyable {
025
026    /** the model */
027    private transient HistoryBrowserModel model;
028    private TagInfoViewer tagInfoViewer;
029    private NodeListViewer nodeListViewer;
030    private RelationMemberListViewer relationMemberListViewer;
031    private CoordinateInfoViewer coordinateInfoViewer;
032    private JTabbedPane tpViewers;
033
034    /**
035     * Constructs a new {@code HistoryBrowser}.
036     */
037    public HistoryBrowser() {
038        model = new HistoryBrowserModel();
039        build();
040    }
041
042    /**
043     * Constructs a new {@code HistoryBrowser}.
044     * @param history the history of an {@link OsmPrimitive}
045     */
046    public HistoryBrowser(History history) {
047        this();
048        populate(history);
049    }
050
051    /**
052     * creates the table which shows the list of versions
053     *
054     * @return  the panel with the version table
055     */
056    protected JPanel createVersionTablePanel() {
057        JPanel pnl = new JPanel(new BorderLayout());
058        pnl.add(new JScrollPane(new VersionTable(model)), BorderLayout.CENTER);
059        return pnl;
060    }
061
062    /**
063     * creates the panel which shows information about two different versions
064     * of the same {@link OsmPrimitive}.
065     *
066     * @return the panel
067     */
068    protected JPanel createVersionComparePanel() {
069        tpViewers = new JTabbedPane();
070
071        // create the viewers, but don't add them yet.
072        // see populate()
073        //
074        tagInfoViewer = new TagInfoViewer(model);
075        nodeListViewer = new NodeListViewer(model);
076        relationMemberListViewer = new RelationMemberListViewer(model);
077        coordinateInfoViewer = new CoordinateInfoViewer(model);
078        JPanel pnl = new JPanel(new BorderLayout());
079        pnl.add(tpViewers, BorderLayout.CENTER);
080
081        tpViewers.addChangeListener(e -> {
082            if (tpViewers.getSelectedComponent() == coordinateInfoViewer) {
083                // while building the component size is not yet known, thus panning does not give reasonable results
084                coordinateInfoViewer.setDisplayToFitMapMarkers();
085            }
086        });
087
088        return pnl;
089    }
090
091    /**
092     * builds the GUI
093     */
094    protected void build() {
095        JPanel left = createVersionTablePanel();
096        JPanel right = createVersionComparePanel();
097        setLayout(new BorderLayout());
098        JSplitPane pane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, left, right);
099        add(pane, BorderLayout.CENTER);
100
101        pane.setOneTouchExpandable(true);
102        pane.setDividerLocation(300);
103
104        Dimension minimumSize = new Dimension(100, 50);
105        left.setMinimumSize(minimumSize);
106        right.setMinimumSize(minimumSize);
107    }
108
109    /**
110     * populates the browser with the history of a specific {@link OsmPrimitive}
111     *
112     * @param history the history
113     */
114    public void populate(History history) {
115        model.setHistory(history);
116
117        tpViewers.removeAll();
118
119        tpViewers.add(tagInfoViewer);
120        tpViewers.setTitleAt(0, tr("Tags"));
121
122        if (history.getEarliest().getType() == OsmPrimitiveType.NODE) {
123            tpViewers.add(coordinateInfoViewer);
124            tpViewers.setTitleAt(1, tr("Coordinates"));
125        } else if (history.getEarliest().getType() == OsmPrimitiveType.WAY) {
126            tpViewers.add(nodeListViewer);
127            tpViewers.setTitleAt(1, tr("Nodes"));
128        } else if (history.getEarliest().getType() == OsmPrimitiveType.RELATION) {
129            tpViewers.add(relationMemberListViewer);
130            tpViewers.setTitleAt(1, tr("Members"));
131        }
132        revalidate();
133    }
134
135    /**
136     * replies the {@link History} currently displayed by this browser
137     *
138     * @return the current history
139     */
140    public History getHistory() {
141        return model.getHistory();
142    }
143
144    /**
145     * replies the model used by this browser
146     * @return the model
147     */
148    public HistoryBrowserModel getModel() {
149        return model;
150    }
151
152    @Override
153    public void destroy() {
154        model.unlinkAsListener();
155        for (Destroyable component : new Destroyable[] {
156                tagInfoViewer, nodeListViewer, relationMemberListViewer, coordinateInfoViewer}) {
157            component.destroy();
158        }
159    }
160}