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

Last change on this file since 8674 was 8510, checked in by Don-vip, 9 years ago

checkstyle: enable relevant whitespace checks and fix them

  • Property svn:eol-style set to native
File size: 12.8 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;
20import javax.swing.event.TableModelEvent;
21import javax.swing.event.TableModelListener;
22import javax.swing.table.TableModel;
23
24import org.openstreetmap.josm.Main;
25import org.openstreetmap.josm.actions.AutoScaleAction;
26import org.openstreetmap.josm.data.osm.OsmPrimitive;
27import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
28import org.openstreetmap.josm.data.osm.PrimitiveId;
29import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
30import org.openstreetmap.josm.data.osm.history.History;
31import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
32import org.openstreetmap.josm.gui.layer.OsmDataLayer;
33import org.openstreetmap.josm.gui.util.AdjustmentSynchronizer;
34import org.openstreetmap.josm.gui.util.GuiHelper;
35import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
36import org.openstreetmap.josm.tools.ImageProvider;
37
38/**
39 * NodeListViewer is a UI component which displays the node list of two
40 * version of a {@link OsmPrimitive} in a {@link History}.
41 *
42 * <ul>
43 * <li>on the left, it displays the node list for the version at {@link PointInTimeType#REFERENCE_POINT_IN_TIME}</li>
44 * <li>on the right, it displays the node list for the version at {@link PointInTimeType#CURRENT_POINT_IN_TIME}</li>
45 * </ul>
46 *
47 */
48public class NodeListViewer extends JPanel {
49
50 private transient HistoryBrowserModel model;
51 private VersionInfoPanel referenceInfoPanel;
52 private VersionInfoPanel currentInfoPanel;
53 private transient AdjustmentSynchronizer adjustmentSynchronizer;
54 private transient SelectionSynchronizer selectionSynchronizer;
55 private NodeListPopupMenu popupMenu;
56
57 protected JScrollPane embeddInScrollPane(JTable table) {
58 JScrollPane pane = new JScrollPane(table);
59 adjustmentSynchronizer.participateInSynchronizedScrolling(pane.getVerticalScrollBar());
60 return pane;
61 }
62
63 protected JTable buildReferenceNodeListTable() {
64 final DiffTableModel tableModel = model.getNodeListTableModel(PointInTimeType.REFERENCE_POINT_IN_TIME);
65 final NodeListTableColumnModel columnModel = new NodeListTableColumnModel();
66 final JTable table = new JTable(tableModel, columnModel);
67 tableModel.addTableModelListener(newReversedChangeListener(table, columnModel));
68 table.setName("table.referencenodelisttable");
69 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
70 selectionSynchronizer.participateInSynchronizedSelection(table.getSelectionModel());
71 table.addMouseListener(new InternalPopupMenuLauncher());
72 table.addMouseListener(new DoubleClickAdapter(table));
73 return table;
74 }
75
76 protected JTable buildCurrentNodeListTable() {
77 final DiffTableModel tableModel = model.getNodeListTableModel(PointInTimeType.CURRENT_POINT_IN_TIME);
78 final NodeListTableColumnModel columnModel = new NodeListTableColumnModel();
79 final JTable table = new JTable(tableModel, columnModel);
80 tableModel.addTableModelListener(newReversedChangeListener(table, columnModel));
81 table.setName("table.currentnodelisttable");
82 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
83 selectionSynchronizer.participateInSynchronizedSelection(table.getSelectionModel());
84 table.addMouseListener(new InternalPopupMenuLauncher());
85 table.addMouseListener(new DoubleClickAdapter(table));
86 return table;
87 }
88
89 protected TableModelListener newReversedChangeListener(final JTable table, final NodeListTableColumnModel columnModel) {
90 return new TableModelListener() {
91 private Boolean reversed = null;
92 private final String nonReversedText = tr("Nodes") + (table.getFont().canDisplay('\u25bc') ? " \u25bc" : " (1-n)");
93 private final String reversedText = tr("Nodes") + (table.getFont().canDisplay('\u25b2') ? " \u25b2" : " (n-1)");
94
95 @Override
96 public void tableChanged(TableModelEvent e) {
97 if (e.getSource() instanceof DiffTableModel) {
98 final DiffTableModel model = (DiffTableModel) e.getSource();
99 if (reversed == null || reversed != model.isReversed()) {
100 reversed = model.isReversed();
101 columnModel.getColumn(0).setHeaderValue(reversed ? reversedText : nonReversedText);
102 table.getTableHeader().repaint();
103 }
104 }
105 }
106 };
107 }
108
109 protected void build() {
110 setLayout(new GridBagLayout());
111 GridBagConstraints gc = new GridBagConstraints();
112
113 // ---------------------------
114 gc.gridx = 0;
115 gc.gridy = 0;
116 gc.gridwidth = 1;
117 gc.gridheight = 1;
118 gc.weightx = 0.5;
119 gc.weighty = 0.0;
120 gc.insets = new Insets(5, 5, 5, 0);
121 gc.fill = GridBagConstraints.HORIZONTAL;
122 gc.anchor = GridBagConstraints.FIRST_LINE_START;
123 referenceInfoPanel = new VersionInfoPanel(model, PointInTimeType.REFERENCE_POINT_IN_TIME);
124 add(referenceInfoPanel, gc);
125
126 gc.gridx = 1;
127 gc.gridy = 0;
128 gc.gridwidth = 1;
129 gc.gridheight = 1;
130 gc.fill = GridBagConstraints.HORIZONTAL;
131 gc.weightx = 0.5;
132 gc.weighty = 0.0;
133 gc.anchor = GridBagConstraints.FIRST_LINE_START;
134 currentInfoPanel = new VersionInfoPanel(model, PointInTimeType.CURRENT_POINT_IN_TIME);
135 add(currentInfoPanel, gc);
136
137 adjustmentSynchronizer = new AdjustmentSynchronizer();
138 selectionSynchronizer = new SelectionSynchronizer();
139
140 popupMenu = new NodeListPopupMenu();
141
142 // ---------------------------
143 gc.gridx = 0;
144 gc.gridy = 1;
145 gc.gridwidth = 1;
146 gc.gridheight = 1;
147 gc.weightx = 0.5;
148 gc.weighty = 1.0;
149 gc.fill = GridBagConstraints.BOTH;
150 gc.anchor = GridBagConstraints.NORTHWEST;
151 add(embeddInScrollPane(buildReferenceNodeListTable()), gc);
152
153 gc.gridx = 1;
154 gc.gridy = 1;
155 gc.gridwidth = 1;
156 gc.gridheight = 1;
157 gc.weightx = 0.5;
158 gc.weighty = 1.0;
159 gc.fill = GridBagConstraints.BOTH;
160 gc.anchor = GridBagConstraints.NORTHWEST;
161 add(embeddInScrollPane(buildCurrentNodeListTable()), gc);
162 }
163
164 public NodeListViewer(HistoryBrowserModel model) {
165 setModel(model);
166 build();
167 }
168
169 protected void unregisterAsObserver(HistoryBrowserModel model) {
170 if (currentInfoPanel != null) {
171 model.deleteObserver(currentInfoPanel);
172 }
173 if (referenceInfoPanel != null) {
174 model.deleteObserver(referenceInfoPanel);
175 }
176 }
177
178 protected void registerAsObserver(HistoryBrowserModel model) {
179 if (currentInfoPanel != null) {
180 model.addObserver(currentInfoPanel);
181 }
182 if (referenceInfoPanel != null) {
183 model.addObserver(referenceInfoPanel);
184 }
185 }
186
187 public void setModel(HistoryBrowserModel model) {
188 if (this.model != null) {
189 unregisterAsObserver(model);
190 }
191 this.model = model;
192 if (this.model != null) {
193 registerAsObserver(model);
194 }
195 }
196
197 static class NodeListPopupMenu extends JPopupMenu {
198 private final ZoomToNodeAction zoomToNodeAction;
199 private final ShowHistoryAction showHistoryAction;
200
201 public NodeListPopupMenu() {
202 zoomToNodeAction = new ZoomToNodeAction();
203 add(zoomToNodeAction);
204 showHistoryAction = new ShowHistoryAction();
205 add(showHistoryAction);
206 }
207
208 public void prepare(PrimitiveId pid) {
209 zoomToNodeAction.setPrimitiveId(pid);
210 zoomToNodeAction.updateEnabledState();
211
212 showHistoryAction.setPrimitiveId(pid);
213 showHistoryAction.updateEnabledState();
214 }
215 }
216
217 static class ZoomToNodeAction extends AbstractAction {
218 private transient PrimitiveId primitiveId;
219
220 /**
221 * Constructs a new {@code ZoomToNodeAction}.
222 */
223 public ZoomToNodeAction() {
224 putValue(NAME, tr("Zoom to node"));
225 putValue(SHORT_DESCRIPTION, tr("Zoom to this node in the current data layer"));
226 putValue(SMALL_ICON, ImageProvider.get("dialogs", "zoomin"));
227 }
228
229 @Override
230 public void actionPerformed(ActionEvent e) {
231 if (!isEnabled()) return;
232 OsmPrimitive p = getPrimitiveToZoom();
233 if (p != null) {
234 OsmDataLayer editLayer = Main.main.getEditLayer();
235 if (editLayer != null) {
236 editLayer.data.setSelected(p.getPrimitiveId());
237 AutoScaleAction.autoScale("selection");
238 }
239 }
240 }
241
242 public void setPrimitiveId(PrimitiveId pid) {
243 this.primitiveId = pid;
244 updateEnabledState();
245 }
246
247 protected OsmPrimitive getPrimitiveToZoom() {
248 if (primitiveId == null) return null;
249 OsmDataLayer editLayer = Main.main.getEditLayer();
250 if (editLayer == null) return null;
251 return editLayer.data.getPrimitiveById(primitiveId);
252 }
253
254 public void updateEnabledState() {
255 if (!Main.main.hasEditLayer()) {
256 setEnabled(false);
257 return;
258 }
259 setEnabled(getPrimitiveToZoom() != null);
260 }
261 }
262
263 static class ShowHistoryAction extends AbstractAction {
264 private transient PrimitiveId primitiveId;
265
266 /**
267 * Constructs a new {@code ShowHistoryAction}.
268 */
269 public ShowHistoryAction() {
270 putValue(NAME, tr("Show history"));
271 putValue(SHORT_DESCRIPTION, tr("Open a history browser with the history of this node"));
272 putValue(SMALL_ICON, ImageProvider.get("dialogs", "history"));
273 }
274
275 @Override
276 public void actionPerformed(ActionEvent e) {
277 if (!isEnabled()) return;
278 run();
279 }
280
281 public void setPrimitiveId(PrimitiveId pid) {
282 this.primitiveId = pid;
283 updateEnabledState();
284 }
285
286 public void run() {
287 if (HistoryDataSet.getInstance().getHistory(primitiveId) == null) {
288 Main.worker.submit(new HistoryLoadTask().add(primitiveId));
289 }
290 Runnable r = new Runnable() {
291 @Override
292 public void run() {
293 final History h = HistoryDataSet.getInstance().getHistory(primitiveId);
294 if (h == null)
295 return;
296 GuiHelper.runInEDT(new Runnable() {
297 @Override public void run() {
298 HistoryBrowserDialogManager.getInstance().show(h);
299 }
300 });
301 }
302 };
303 Main.worker.submit(r);
304 }
305
306 public void updateEnabledState() {
307 setEnabled(primitiveId != null && !primitiveId.isNew());
308 }
309 }
310
311 private static PrimitiveId primitiveIdAtRow(TableModel model, int row) {
312 DiffTableModel castedModel = (DiffTableModel) model;
313 Long id = (Long) castedModel.getValueAt(row, 0).value;
314 if (id == null) return null;
315 return new SimplePrimitiveId(id, OsmPrimitiveType.NODE);
316 }
317
318 class InternalPopupMenuLauncher extends PopupMenuLauncher {
319 public InternalPopupMenuLauncher() {
320 super(popupMenu);
321 }
322
323 @Override protected int checkTableSelection(JTable table, Point p) {
324 int row = super.checkTableSelection(table, p);
325 popupMenu.prepare(primitiveIdAtRow(table.getModel(), row));
326 return row;
327 }
328 }
329
330 static class DoubleClickAdapter extends MouseAdapter {
331 private JTable table;
332 private ShowHistoryAction showHistoryAction;
333
334 public DoubleClickAdapter(JTable table) {
335 this.table = table;
336 showHistoryAction = new ShowHistoryAction();
337 }
338
339 @Override
340 public void mouseClicked(MouseEvent e) {
341 if (e.getClickCount() < 2) return;
342 int row = table.rowAtPoint(e.getPoint());
343 if (row <= 0) return;
344 PrimitiveId pid = primitiveIdAtRow(table.getModel(), row);
345 if (pid == null || pid.isNew())
346 return;
347 showHistoryAction.setPrimitiveId(pid);
348 showHistoryAction.run();
349 }
350 }
351}
Note: See TracBrowser for help on using the repository browser.