source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java@ 2492

Last change on this file since 2492 was 2448, checked in by Gubaer, 15 years ago

fixed #3352: History doesn't get invalidated on upload?
fixed #3912: Extend history dialog to contain the currently modified version
new: zoom to node in list of nodes in history dialog (popup menu)
new: load history of node from node list in history dialog (popup menu or double click)
fixed: close all history dialogs when the number of layers drop to 0
fixed: implemented equals() and hashCode() on SimplePrimitiveId
fixed: history features now usePrimitiveId instead of long.

  • Property svn:eol-style set to native
File size: 12.7 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.gui.dialogs;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.BorderLayout;
7import java.awt.Component;
8import java.awt.GridLayout;
9import java.awt.event.ActionEvent;
10import java.awt.event.KeyEvent;
11import java.awt.event.MouseAdapter;
12import java.awt.event.MouseEvent;
13import java.util.ArrayList;
14import java.util.Collection;
15import java.util.Collections;
16import java.util.List;
17
18import javax.swing.AbstractAction;
19import javax.swing.Action;
20import javax.swing.DefaultListSelectionModel;
21import javax.swing.JComponent;
22import javax.swing.JLabel;
23import javax.swing.JPanel;
24import javax.swing.JScrollPane;
25import javax.swing.JTable;
26import javax.swing.ListSelectionModel;
27import javax.swing.event.ListSelectionEvent;
28import javax.swing.event.ListSelectionListener;
29import javax.swing.table.DefaultTableCellRenderer;
30import javax.swing.table.DefaultTableColumnModel;
31import javax.swing.table.DefaultTableModel;
32import javax.swing.table.TableCellRenderer;
33import javax.swing.table.TableColumn;
34
35import org.openstreetmap.josm.Main;
36import org.openstreetmap.josm.data.SelectionChangedListener;
37import org.openstreetmap.josm.data.osm.DataSet;
38import org.openstreetmap.josm.data.osm.OsmPrimitive;
39import org.openstreetmap.josm.data.osm.PrimitiveId;
40import org.openstreetmap.josm.data.osm.history.History;
41import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
42import org.openstreetmap.josm.data.osm.history.HistoryDataSetListener;
43import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
44import org.openstreetmap.josm.gui.SideButton;
45import org.openstreetmap.josm.gui.history.HistoryBrowserDialogManager;
46import org.openstreetmap.josm.gui.history.HistoryLoadTask;
47import org.openstreetmap.josm.tools.ImageProvider;
48import org.openstreetmap.josm.tools.Shortcut;
49
50/**
51 * HistoryDialog displays a list of the currently selected primitives and provides
52 * two actions for (1) (re)loading the history of the selected primitives and (2)
53 * for launching a history browser for each selected primitive.
54 *
55 */
56public class HistoryDialog extends ToggleDialog implements HistoryDataSetListener {
57
58 /** the table model */
59 protected HistoryItemTableModel model;
60 /** the table with the history items */
61 protected JTable historyTable;
62
63 protected ShowHistoryAction showHistoryAction;
64 protected ReloadAction reloadAction;
65
66 /**
67 * builds the row with the command buttons
68 *
69 * @return the rows with the command buttons
70 */
71 protected JPanel buildButtonRow() {
72 JPanel buttons = new JPanel(new GridLayout(1,2));
73
74 SideButton btn = new SideButton(reloadAction = new ReloadAction());
75 btn.setName("btn.reload");
76 buttons.add(btn);
77
78 btn = new SideButton(showHistoryAction = new ShowHistoryAction());
79 btn.setName("btn.showhistory");
80 buttons.add(btn);
81
82 return buttons;
83 }
84
85 /**
86 * builds the GUI
87 */
88 protected void build() {
89 DefaultListSelectionModel selectionModel = new DefaultListSelectionModel();
90 historyTable = new JTable(
91 model = new HistoryItemTableModel(selectionModel),
92 new HistoryTableColumnModel(),
93 selectionModel
94 );
95 historyTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
96 historyTable.setName("table.historyitems");
97 final TableCellRenderer oldRenderer = historyTable.getTableHeader().getDefaultRenderer();
98 historyTable.getTableHeader().setDefaultRenderer(new DefaultTableCellRenderer(){
99 @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
100 JComponent c = (JComponent)oldRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
101 if (!value.equals(""))
102 return c;
103 JLabel l = new JLabel(ImageProvider.get("misc","showhide"));
104 l.setForeground(c.getForeground());
105 l.setBackground(c.getBackground());
106 l.setFont(c.getFont());
107 l.setBorder(c.getBorder());
108 l.setOpaque(true);
109 return l;
110 }
111 });
112 historyTable.addMouseListener(new ShowHistoryMouseAdapter());
113
114 JScrollPane pane = new JScrollPane(historyTable);
115 pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
116 pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
117 historyTable.setTableHeader(null);
118 pane.setColumnHeaderView(null);
119 add(pane, BorderLayout.CENTER);
120
121 add(buildButtonRow(), BorderLayout.SOUTH);
122
123 // wire actions
124 //
125 historyTable.getSelectionModel().addListSelectionListener(showHistoryAction);
126 historyTable.getSelectionModel().addListSelectionListener(reloadAction);
127 }
128
129 public HistoryDialog() {
130 super(tr("History"), "history", tr("Display the history of all selected items."),
131 Shortcut.registerShortcut("subwindow:history", tr("Toggle: {0}", tr("History")), KeyEvent.VK_H,
132 Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 150);
133 build();
134 DataSet.selListeners.add(model);
135 HistoryDataSet.getInstance().addHistoryDataSetListener(this);
136 }
137
138 public void historyUpdated(HistoryDataSet source, PrimitiveId primitiveId) {
139 model.refresh();
140 }
141
142 /**
143 * The table model with the history items
144 *
145 */
146 static class HistoryItemTableModel extends DefaultTableModel implements SelectionChangedListener{
147 private ArrayList<OsmPrimitive> data;
148 private DefaultListSelectionModel selectionModel;
149
150 public HistoryItemTableModel(DefaultListSelectionModel selectionModel) {
151 data = new ArrayList<OsmPrimitive>();
152 this.selectionModel = selectionModel;
153 }
154
155 @Override
156 public int getRowCount() {
157 if (data == null)
158 return 0;
159 return data.size();
160 }
161
162 @Override
163 public Object getValueAt(int row, int column) {
164 return data.get(row);
165 }
166
167 @Override
168 public boolean isCellEditable(int row, int column) {
169 return false;
170 }
171
172 protected List<OsmPrimitive> getSelectedPrimitives() {
173 ArrayList<OsmPrimitive> ret = new ArrayList<OsmPrimitive>();
174 for (int i=0; i< data.size(); i++) {
175 if (selectionModel.isSelectedIndex(i)) {
176 ret.add(data.get(i));
177 }
178 }
179 return ret;
180 }
181
182 protected void selectPrimitives(Collection<OsmPrimitive> primitives) {
183 for (OsmPrimitive p: primitives) {
184 int idx = data.indexOf(p);
185 if (idx < 0) {
186 continue;
187 }
188 selectionModel.addSelectionInterval(idx, idx);
189 }
190 }
191
192 public void refresh() {
193 List<OsmPrimitive> selectedPrimitives = getSelectedPrimitives();
194 data.clear();
195 if (Main.main.getCurrentDataSet() == null)
196 return;
197 for (OsmPrimitive primitive: Main.main.getCurrentDataSet().getSelected()) {
198 if (primitive.isNew()) {
199 continue;
200 }
201 data.add(primitive);
202 }
203 fireTableDataChanged();
204 selectPrimitives(selectedPrimitives);
205 }
206
207 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
208 data.clear();
209 selectionModel.clearSelection();
210 if (newSelection == null || newSelection.isEmpty()) return;
211 for (OsmPrimitive primitive: newSelection) {
212 if (primitive.isNew()) {
213 continue;
214 }
215 data.add(primitive);
216 }
217 fireTableDataChanged();
218 selectionModel.addSelectionInterval(0, data.size()-1);
219 }
220
221 public List<OsmPrimitive> getPrimitives(int [] rows) {
222 if (rows == null || rows.length == 0) return Collections.emptyList();
223 ArrayList<OsmPrimitive> ret = new ArrayList<OsmPrimitive>(rows.length);
224 for (int row: rows) {
225 ret.add(data.get(row));
226 }
227 return ret;
228 }
229
230 public OsmPrimitive getPrimitive(int row) {
231 return data.get(row);
232 }
233 }
234
235 /**
236 * The column model
237 */
238 static class HistoryTableColumnModel extends DefaultTableColumnModel {
239 protected void createColumns() {
240 TableColumn col = null;
241 OsmPrimitivRenderer renderer = new OsmPrimitivRenderer();
242 // column 0 - History item
243 col = new TableColumn(0);
244 col.setHeaderValue(tr("Object with history"));
245 col.setCellRenderer(renderer);
246 addColumn(col);
247 }
248
249 public HistoryTableColumnModel() {
250 createColumns();
251 }
252 }
253
254 /**
255 * The action for reloading history information of the currently selected primitives.
256 *
257 */
258 class ReloadAction extends AbstractAction implements ListSelectionListener {
259 public ReloadAction() {
260 putValue(Action.SMALL_ICON, ImageProvider.get("dialogs","refresh"));
261 putValue(Action.NAME, tr("Reload"));
262 putValue(Action.SHORT_DESCRIPTION, tr("Reload all currently selected objects and refresh the list."));
263 updateEnabledState();
264 }
265
266 public void actionPerformed(ActionEvent e) {
267 int [] rows = historyTable.getSelectedRows();
268 if (rows == null || rows.length == 0) return;
269
270 List<OsmPrimitive> selectedItems = model.getPrimitives(rows);
271 HistoryLoadTask task = new HistoryLoadTask();
272 task.add(selectedItems);
273 Main.worker.execute(task);
274 }
275
276 protected void updateEnabledState() {
277 setEnabled(historyTable.getSelectedRowCount() > 0);
278 }
279
280 public void valueChanged(ListSelectionEvent e) {
281 updateEnabledState();
282 }
283 }
284
285 class ShowHistoryMouseAdapter extends MouseAdapter {
286 @Override
287 public void mouseClicked(MouseEvent e) {
288 if (e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1) {
289 int row = historyTable.rowAtPoint(e.getPoint());
290 new ShowHistoryAction().showHistory(Collections.singletonList(model.getPrimitive(row)));
291 }
292 }
293 }
294
295 /**
296 * The action for showing history information of the current history item.
297 */
298 class ShowHistoryAction extends AbstractAction implements ListSelectionListener {
299 public ShowHistoryAction() {
300 putValue(Action.SMALL_ICON, ImageProvider.get("dialogs","history"));
301 putValue(Action.NAME, tr("Show"));
302 putValue(Action.SHORT_DESCRIPTION, tr("Display the history of the selected objects."));
303 updateEnabledState();
304 }
305
306 protected List<OsmPrimitive> filterPrimitivesWithUnloadedHistory(Collection<OsmPrimitive> primitives) {
307 ArrayList<OsmPrimitive> ret = new ArrayList<OsmPrimitive>(primitives.size());
308 for (OsmPrimitive p: primitives) {
309 if (HistoryDataSet.getInstance().getHistory(p.getPrimitiveId()) == null) {
310 ret.add(p);
311 }
312 }
313 return ret;
314 }
315
316 public void showHistory(final List<OsmPrimitive> primitives) {
317 List<OsmPrimitive> toLoad = filterPrimitivesWithUnloadedHistory(primitives);
318 if (!toLoad.isEmpty()) {
319 HistoryLoadTask task = new HistoryLoadTask();
320 task.add(primitives);
321 Main.worker.submit(task);
322 }
323
324 Runnable r = new Runnable() {
325 public void run() {
326 for (OsmPrimitive p : primitives) {
327 History h = HistoryDataSet.getInstance().getHistory(p.getPrimitiveId());
328 if (h == null) {
329 continue;
330 }
331 HistoryBrowserDialogManager.getInstance().show(h);
332 }
333 }
334 };
335 Main.worker.submit(r);
336 }
337
338 public void actionPerformed(ActionEvent e) {
339 int [] rows = historyTable.getSelectedRows();
340 if (rows == null || rows.length == 0) return;
341 showHistory(model.getPrimitives(rows));
342 }
343
344 protected void updateEnabledState() {
345 setEnabled(historyTable.getSelectedRowCount() > 0);
346 }
347
348 public void valueChanged(ListSelectionEvent e) {
349 updateEnabledState();
350 }
351 }
352}
Note: See TracBrowser for help on using the repository browser.