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