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

Last change on this file since 12713 was 12636, checked in by Don-vip, 7 years ago

see #15182 - deprecate Main.getLayerManager(). Replacement: gui.MainApplication.getLayerManager()

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