source: josm/trunk/src/org/openstreetmap/josm/gui/history/NodeListViewer.java@ 2448

Last change on this file since 2448 was 2448, checked in by Gubaer, 14 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.

File size: 11.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.history;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.GridBagConstraints;
7import java.awt.GridBagLayout;
8import java.awt.Insets;
9import java.awt.Point;
10import java.awt.event.ActionEvent;
11import java.awt.event.MouseAdapter;
12import java.awt.event.MouseEvent;
13
14import javax.swing.AbstractAction;
15import javax.swing.JPanel;
16import javax.swing.JPopupMenu;
17import javax.swing.JScrollPane;
18import javax.swing.JTable;
19import javax.swing.ListSelectionModel;
20
21import org.openstreetmap.josm.Main;
22import org.openstreetmap.josm.actions.AutoScaleAction;
23import org.openstreetmap.josm.data.osm.OsmPrimitive;
24import org.openstreetmap.josm.data.osm.PrimitiveId;
25import org.openstreetmap.josm.data.osm.history.History;
26import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
27import org.openstreetmap.josm.gui.history.HistoryBrowserModel.NodeListTableModel;
28import org.openstreetmap.josm.gui.layer.OsmDataLayer;
29import org.openstreetmap.josm.tools.ImageProvider;
30
31/**
32 * NodeListViewer is a UI component which displays the node list of two
33 * version of a {@see OsmPrimitive} in a {@see History}.
34 *
35 * <ul>
36 * <li>on the left, it displays the node list for the version at {@see PointInTimeType#REFERENCE_POINT_IN_TIME}</li>
37 * <li>on the right, it displays the node list for the version at {@see PointInTimeType#CURRENT_POINT_IN_TIME}</li>
38 * </ul>
39 *
40 */
41public class NodeListViewer extends JPanel {
42
43 private HistoryBrowserModel model;
44 private VersionInfoPanel referenceInfoPanel;
45 private VersionInfoPanel currentInfoPanel;
46 private AdjustmentSynchronizer adjustmentSynchronizer;
47 private SelectionSynchronizer selectionSynchronizer;
48 private NodeListPopupMenu popupMenu;
49
50 protected JScrollPane embeddInScrollPane(JTable table) {
51 JScrollPane pane = new JScrollPane(table);
52 pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
53 pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
54 adjustmentSynchronizer.participateInSynchronizedScrolling(pane.getVerticalScrollBar());
55 return pane;
56 }
57
58 protected JTable buildReferenceNodeListTable() {
59 JTable table = new JTable(
60 model.getNodeListTableModel(PointInTimeType.REFERENCE_POINT_IN_TIME),
61 new NodeListTableColumnModel()
62 );
63 table.setName("table.referencenodelisttable");
64 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
65 selectionSynchronizer.participateInSynchronizedSelection(table.getSelectionModel());
66 table.addMouseListener(new PopupMenuLauncher(table));
67 table.addMouseListener(new DoubleClickAdapter(table));
68 return table;
69 }
70
71 protected JTable buildCurrentNodeListTable() {
72 JTable table = new JTable(
73 model.getNodeListTableModel(PointInTimeType.CURRENT_POINT_IN_TIME),
74 new NodeListTableColumnModel()
75 );
76 table.setName("table.currentnodelisttable");
77 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
78 selectionSynchronizer.participateInSynchronizedSelection(table.getSelectionModel());
79 table.addMouseListener(new PopupMenuLauncher(table));
80 table.addMouseListener(new DoubleClickAdapter(table));
81 return table;
82 }
83
84 protected void build() {
85 setLayout(new GridBagLayout());
86 GridBagConstraints gc = new GridBagConstraints();
87
88 // ---------------------------
89 gc.gridx = 0;
90 gc.gridy = 0;
91 gc.gridwidth = 1;
92 gc.gridheight = 1;
93 gc.weightx = 0.5;
94 gc.weighty = 0.0;
95 gc.insets = new Insets(5,5,5,0);
96 gc.fill = GridBagConstraints.HORIZONTAL;
97 gc.anchor = GridBagConstraints.FIRST_LINE_START;
98 referenceInfoPanel = new VersionInfoPanel(model, PointInTimeType.REFERENCE_POINT_IN_TIME);
99 add(referenceInfoPanel,gc);
100
101 gc.gridx = 1;
102 gc.gridy = 0;
103 gc.gridwidth = 1;
104 gc.gridheight = 1;
105 gc.fill = GridBagConstraints.HORIZONTAL;
106 gc.weightx = 0.5;
107 gc.weighty = 0.0;
108 gc.anchor = GridBagConstraints.FIRST_LINE_START;
109 currentInfoPanel = new VersionInfoPanel(model, PointInTimeType.CURRENT_POINT_IN_TIME);
110 add(currentInfoPanel,gc);
111
112 adjustmentSynchronizer = new AdjustmentSynchronizer();
113 selectionSynchronizer = new SelectionSynchronizer();
114
115 // ---------------------------
116 gc.gridx = 0;
117 gc.gridy = 1;
118 gc.gridwidth = 1;
119 gc.gridheight = 1;
120 gc.weightx = 0.5;
121 gc.weighty = 1.0;
122 gc.fill = GridBagConstraints.BOTH;
123 gc.anchor = GridBagConstraints.NORTHWEST;
124 add(embeddInScrollPane(buildReferenceNodeListTable()),gc);
125
126 gc.gridx = 1;
127 gc.gridy = 1;
128 gc.gridwidth = 1;
129 gc.gridheight = 1;
130 gc.weightx = 0.5;
131 gc.weighty = 1.0;
132 gc.fill = GridBagConstraints.BOTH;
133 gc.anchor = GridBagConstraints.NORTHWEST;
134 add(embeddInScrollPane(buildCurrentNodeListTable()),gc);
135
136 popupMenu = new NodeListPopupMenu();
137 }
138
139 public NodeListViewer(HistoryBrowserModel model) {
140 setModel(model);
141 build();
142 }
143
144 protected void unregisterAsObserver(HistoryBrowserModel model) {
145 if (currentInfoPanel != null) {
146 model.deleteObserver(currentInfoPanel);
147 }
148 if (referenceInfoPanel != null) {
149 model.deleteObserver(referenceInfoPanel);
150 }
151 }
152 protected void registerAsObserver(HistoryBrowserModel model) {
153 if (currentInfoPanel != null) {
154 model.addObserver(currentInfoPanel);
155 }
156 if (referenceInfoPanel != null) {
157 model.addObserver(referenceInfoPanel);
158 }
159 }
160
161 public void setModel(HistoryBrowserModel model) {
162 if (this.model != null) {
163 unregisterAsObserver(model);
164 }
165 this.model = model;
166 if (this.model != null) {
167 registerAsObserver(model);
168 }
169 }
170
171
172 class NodeListPopupMenu extends JPopupMenu {
173 private ZoomToNodeAction zoomToNodeAction;
174 private ShowHistoryAction showHistoryAction;
175
176 public NodeListPopupMenu() {
177 zoomToNodeAction = new ZoomToNodeAction();
178 add(zoomToNodeAction);
179 showHistoryAction = new ShowHistoryAction();
180 add(showHistoryAction);
181 }
182
183 public void prepare(PrimitiveId pid){
184 zoomToNodeAction.setPrimitiveId(pid);
185 zoomToNodeAction.updateEnabledState();
186
187 showHistoryAction.setPrimitiveId(pid);
188 showHistoryAction.updateEnabledState();
189 }
190 }
191
192 class ZoomToNodeAction extends AbstractAction {
193 private PrimitiveId primitiveId;
194
195 public ZoomToNodeAction() {
196 putValue(NAME, tr("Zoom to node"));
197 putValue(SHORT_DESCRIPTION, tr("Zoom to this node in the current data layer"));
198 putValue(SMALL_ICON, ImageProvider.get("dialogs", "zoomin"));
199 }
200
201 public void actionPerformed(ActionEvent e) {
202 if (!isEnabled()) return;
203 OsmPrimitive p = getPrimitiveToZoom();
204 if (p!= null) {
205 getEditLayer().data.setSelected(p.getPrimitiveId());
206 new AutoScaleAction("selection").autoScale();
207 }
208 }
209
210 public void setPrimitiveId(PrimitiveId pid) {
211 this.primitiveId = pid;
212 updateEnabledState();
213 }
214
215 protected OsmDataLayer getEditLayer() {
216 try {
217 return Main.map.mapView.getEditLayer();
218 } catch(NullPointerException e) {
219 return null;
220 }
221 }
222
223 protected OsmPrimitive getPrimitiveToZoom() {
224 if (primitiveId == null) return null;
225 OsmPrimitive p = getEditLayer().data.getPrimitiveById(primitiveId);
226 return p;
227 }
228
229 public void updateEnabledState() {
230 if (getEditLayer() == null) {
231 setEnabled(false);
232 return;
233 }
234 setEnabled(getPrimitiveToZoom() != null);
235 }
236 }
237
238 class ShowHistoryAction extends AbstractAction {
239 private PrimitiveId primitiveId;
240
241 public ShowHistoryAction() {
242 putValue(NAME, tr("Show history"));
243 putValue(SHORT_DESCRIPTION, tr("Open a history browser with the history of this node"));
244 putValue(SMALL_ICON, ImageProvider.get("dialogs", "history"));
245 }
246
247 public void actionPerformed(ActionEvent e) {
248 if (!isEnabled()) return;
249 run();
250 }
251
252 public void setPrimitiveId(PrimitiveId pid) {
253 this.primitiveId = pid;
254 updateEnabledState();
255 }
256
257 public void run() {
258 if (HistoryDataSet.getInstance().getHistory(primitiveId) == null) {
259 Main.worker.submit(new HistoryLoadTask().add(primitiveId));
260 }
261 Runnable r = new Runnable() {
262 public void run() {
263 History h = HistoryDataSet.getInstance().getHistory(primitiveId);
264 if (h == null)
265 return;
266 HistoryBrowserDialogManager.getInstance().show(h);
267 }
268 };
269 Main.worker.submit(r);
270 }
271
272 public void updateEnabledState() {
273 setEnabled(primitiveId != null && primitiveId.getUniqueId() > 0);
274 }
275 }
276
277 class PopupMenuLauncher extends MouseAdapter {
278 private JTable table;
279
280 public PopupMenuLauncher(JTable table) {
281 this.table = table;
282 }
283
284 @Override
285 public void mousePressed(MouseEvent e) {
286 showPopup(e);
287 }
288
289 @Override
290 public void mouseReleased(MouseEvent e) {
291 showPopup(e);
292 }
293
294 private void showPopup(MouseEvent e) {
295 if (!e.isPopupTrigger()) return;
296 Point p = e.getPoint();
297 int row = table.rowAtPoint(p);
298 NodeListTableModel model = (NodeListTableModel) table.getModel();
299 PrimitiveId pid = model.getNodeId(row);
300 popupMenu.prepare(pid);
301 popupMenu.show(e.getComponent(), e.getX(), e.getY());
302 }
303 }
304
305 class DoubleClickAdapter extends MouseAdapter {
306 private JTable table;
307 private ShowHistoryAction showHistoryAction;
308
309 public DoubleClickAdapter(JTable table) {
310 this.table = table;
311 showHistoryAction = new ShowHistoryAction();
312 }
313
314 protected NodeListTableModel getModel() {
315 return (NodeListTableModel)table.getModel();
316 }
317
318 @Override
319 public void mouseClicked(MouseEvent e) {
320 if (e.getClickCount() < 2) return;
321 int row = table.rowAtPoint(e.getPoint());
322 PrimitiveId pid = getModel().getNodeId(row);
323 if (pid == null)
324 return;
325 showHistoryAction.setPrimitiveId(pid);
326 showHistoryAction.run();
327 }
328 }
329}
Note: See TracBrowser for help on using the repository browser.