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

Last change on this file since 5958 was 5958, checked in by Don-vip, 11 years ago
  • Improve PopupMenuLauncher to automatically select JTable/JList/JTree line under cursor
  • Simplify all popup menus with this new feature
  • Remove custom popup menus in BoundingBoxSelection and BoundingBoxSelection to use default text field popup menus recently introduced
  • Fix EDT violations in changeset window
  • Make Autoscale actions publicly available in MainMenu
  • Add a new "Zoom to problem" mode in AutoScaleAction
  • Make "Zoom to problem" menu item in validator dialog use this new feature
  • Update enabled state of "Zoom to Conflict" and "Zoom to problem" against selection of conflict/validator dialog
  • Property svn:eol-style set to native
File size: 11.2 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.table.TableModel;
21
22import org.openstreetmap.josm.Main;
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.layer.OsmDataLayer;
31import org.openstreetmap.josm.gui.util.GuiHelper;
32import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
33import org.openstreetmap.josm.tools.ImageProvider;
34
35/**
36 * NodeListViewer is a UI component which displays the node list of two
37 * version of a {@link OsmPrimitive} in a {@link History}.
38 *
39 * <ul>
40 * <li>on the left, it displays the node list for the version at {@link PointInTimeType#REFERENCE_POINT_IN_TIME}</li>
41 * <li>on the right, it displays the node list for the version at {@link PointInTimeType#CURRENT_POINT_IN_TIME}</li>
42 * </ul>
43 *
44 */
45public class NodeListViewer extends JPanel {
46
47 private HistoryBrowserModel model;
48 private VersionInfoPanel referenceInfoPanel;
49 private VersionInfoPanel currentInfoPanel;
50 private AdjustmentSynchronizer adjustmentSynchronizer;
51 private SelectionSynchronizer selectionSynchronizer;
52 private NodeListPopupMenu popupMenu;
53
54 protected JScrollPane embeddInScrollPane(JTable table) {
55 JScrollPane pane = new JScrollPane(table);
56 pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
57 pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
58 adjustmentSynchronizer.participateInSynchronizedScrolling(pane.getVerticalScrollBar());
59 return pane;
60 }
61
62 protected JTable buildReferenceNodeListTable() {
63 JTable table = new JTable(
64 model.getNodeListTableModel(PointInTimeType.REFERENCE_POINT_IN_TIME),
65 new NodeListTableColumnModel()
66 );
67 table.setName("table.referencenodelisttable");
68 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
69 selectionSynchronizer.participateInSynchronizedSelection(table.getSelectionModel());
70 table.addMouseListener(new InternalPopupMenuLauncher());
71 table.addMouseListener(new DoubleClickAdapter(table));
72 return table;
73 }
74
75 protected JTable buildCurrentNodeListTable() {
76 JTable table = new JTable(
77 model.getNodeListTableModel(PointInTimeType.CURRENT_POINT_IN_TIME),
78 new NodeListTableColumnModel()
79 );
80 table.setName("table.currentnodelisttable");
81 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
82 selectionSynchronizer.participateInSynchronizedSelection(table.getSelectionModel());
83 table.addMouseListener(new InternalPopupMenuLauncher());
84 table.addMouseListener(new DoubleClickAdapter(table));
85 return table;
86 }
87
88 protected void build() {
89 setLayout(new GridBagLayout());
90 GridBagConstraints gc = new GridBagConstraints();
91
92 // ---------------------------
93 gc.gridx = 0;
94 gc.gridy = 0;
95 gc.gridwidth = 1;
96 gc.gridheight = 1;
97 gc.weightx = 0.5;
98 gc.weighty = 0.0;
99 gc.insets = new Insets(5,5,5,0);
100 gc.fill = GridBagConstraints.HORIZONTAL;
101 gc.anchor = GridBagConstraints.FIRST_LINE_START;
102 referenceInfoPanel = new VersionInfoPanel(model, PointInTimeType.REFERENCE_POINT_IN_TIME);
103 add(referenceInfoPanel,gc);
104
105 gc.gridx = 1;
106 gc.gridy = 0;
107 gc.gridwidth = 1;
108 gc.gridheight = 1;
109 gc.fill = GridBagConstraints.HORIZONTAL;
110 gc.weightx = 0.5;
111 gc.weighty = 0.0;
112 gc.anchor = GridBagConstraints.FIRST_LINE_START;
113 currentInfoPanel = new VersionInfoPanel(model, PointInTimeType.CURRENT_POINT_IN_TIME);
114 add(currentInfoPanel,gc);
115
116 adjustmentSynchronizer = new AdjustmentSynchronizer();
117 selectionSynchronizer = new SelectionSynchronizer();
118
119 popupMenu = new NodeListPopupMenu();
120
121 // ---------------------------
122 gc.gridx = 0;
123 gc.gridy = 1;
124 gc.gridwidth = 1;
125 gc.gridheight = 1;
126 gc.weightx = 0.5;
127 gc.weighty = 1.0;
128 gc.fill = GridBagConstraints.BOTH;
129 gc.anchor = GridBagConstraints.NORTHWEST;
130 add(embeddInScrollPane(buildReferenceNodeListTable()),gc);
131
132 gc.gridx = 1;
133 gc.gridy = 1;
134 gc.gridwidth = 1;
135 gc.gridheight = 1;
136 gc.weightx = 0.5;
137 gc.weighty = 1.0;
138 gc.fill = GridBagConstraints.BOTH;
139 gc.anchor = GridBagConstraints.NORTHWEST;
140 add(embeddInScrollPane(buildCurrentNodeListTable()),gc);
141 }
142
143 public NodeListViewer(HistoryBrowserModel model) {
144 setModel(model);
145 build();
146 }
147
148 protected void unregisterAsObserver(HistoryBrowserModel model) {
149 if (currentInfoPanel != null) {
150 model.deleteObserver(currentInfoPanel);
151 }
152 if (referenceInfoPanel != null) {
153 model.deleteObserver(referenceInfoPanel);
154 }
155 }
156 protected void registerAsObserver(HistoryBrowserModel model) {
157 if (currentInfoPanel != null) {
158 model.addObserver(currentInfoPanel);
159 }
160 if (referenceInfoPanel != null) {
161 model.addObserver(referenceInfoPanel);
162 }
163 }
164
165 public void setModel(HistoryBrowserModel model) {
166 if (this.model != null) {
167 unregisterAsObserver(model);
168 }
169 this.model = model;
170 if (this.model != null) {
171 registerAsObserver(model);
172 }
173 }
174
175 static class NodeListPopupMenu extends JPopupMenu {
176 private final ZoomToNodeAction zoomToNodeAction;
177 private final ShowHistoryAction showHistoryAction;
178
179 public NodeListPopupMenu() {
180 zoomToNodeAction = new ZoomToNodeAction();
181 add(zoomToNodeAction);
182 showHistoryAction = new ShowHistoryAction();
183 add(showHistoryAction);
184 }
185
186 public void prepare(PrimitiveId pid){
187 zoomToNodeAction.setPrimitiveId(pid);
188 zoomToNodeAction.updateEnabledState();
189
190 showHistoryAction.setPrimitiveId(pid);
191 showHistoryAction.updateEnabledState();
192 }
193 }
194
195 static class ZoomToNodeAction extends AbstractAction {
196 private PrimitiveId primitiveId;
197
198 public ZoomToNodeAction() {
199 putValue(NAME, tr("Zoom to node"));
200 putValue(SHORT_DESCRIPTION, tr("Zoom to this node in the current data layer"));
201 putValue(SMALL_ICON, ImageProvider.get("dialogs", "zoomin"));
202 }
203
204 public void actionPerformed(ActionEvent e) {
205 if (!isEnabled()) return;
206 OsmPrimitive p = getPrimitiveToZoom();
207 if (p!= null) {
208 getEditLayer().data.setSelected(p.getPrimitiveId());
209 AutoScaleAction.autoScale("selection");
210 }
211 }
212
213 public void setPrimitiveId(PrimitiveId pid) {
214 this.primitiveId = pid;
215 updateEnabledState();
216 }
217
218 protected OsmDataLayer getEditLayer() {
219 try {
220 return Main.map.mapView.getEditLayer();
221 } catch(NullPointerException e) {
222 return null;
223 }
224 }
225
226 protected OsmPrimitive getPrimitiveToZoom() {
227 if (primitiveId == null) return null;
228 OsmPrimitive p = getEditLayer().data.getPrimitiveById(primitiveId);
229 return p;
230 }
231
232 public void updateEnabledState() {
233 if (getEditLayer() == null) {
234 setEnabled(false);
235 return;
236 }
237 setEnabled(getPrimitiveToZoom() != null);
238 }
239 }
240
241 static class ShowHistoryAction extends AbstractAction {
242 private PrimitiveId primitiveId;
243
244 public ShowHistoryAction() {
245 putValue(NAME, tr("Show history"));
246 putValue(SHORT_DESCRIPTION, tr("Open a history browser with the history of this node"));
247 putValue(SMALL_ICON, ImageProvider.get("dialogs", "history"));
248 }
249
250 public void actionPerformed(ActionEvent e) {
251 if (!isEnabled()) return;
252 run();
253 }
254
255 public void setPrimitiveId(PrimitiveId pid) {
256 this.primitiveId = pid;
257 updateEnabledState();
258 }
259
260 public void run() {
261 if (HistoryDataSet.getInstance().getHistory(primitiveId) == null) {
262 Main.worker.submit(new HistoryLoadTask().add(primitiveId));
263 }
264 Runnable r = new Runnable() {
265 public void run() {
266 final History h = HistoryDataSet.getInstance().getHistory(primitiveId);
267 if (h == null)
268 return;
269 GuiHelper.runInEDT(new Runnable() {
270 @Override public void run() {
271 HistoryBrowserDialogManager.getInstance().show(h);
272 }
273 });
274 }
275 };
276 Main.worker.submit(r);
277 }
278
279 public void updateEnabledState() {
280 setEnabled(primitiveId != null && primitiveId.getUniqueId() > 0);
281 }
282 }
283
284 static private PrimitiveId primitiveIdAtRow(TableModel model, int row) {
285 DiffTableModel castedModel = (DiffTableModel) model;
286 Long id = (Long)castedModel.getValueAt(row, 0).value;
287 if(id == null) return null;
288 return new SimplePrimitiveId(id, OsmPrimitiveType.NODE);
289 }
290
291 class InternalPopupMenuLauncher extends PopupMenuLauncher {
292 public InternalPopupMenuLauncher() {
293 super(popupMenu);
294 }
295
296 @Override protected int checkTableSelection(JTable table, Point p) {
297 int row = super.checkTableSelection(table, p);
298 popupMenu.prepare(primitiveIdAtRow(table.getModel(), row));
299 return row;
300 }
301 }
302
303 static class DoubleClickAdapter extends MouseAdapter {
304 private JTable table;
305 private ShowHistoryAction showHistoryAction;
306
307 public DoubleClickAdapter(JTable table) {
308 this.table = table;
309 showHistoryAction = new ShowHistoryAction();
310 }
311
312 @Override
313 public void mouseClicked(MouseEvent e) {
314 if (e.getClickCount() < 2) return;
315 int row = table.rowAtPoint(e.getPoint());
316 if(row <= 0) return;
317 PrimitiveId pid = primitiveIdAtRow(table.getModel(), row);
318 if (pid == null)
319 return;
320 showHistoryAction.setPrimitiveId(pid);
321 showHistoryAction.run();
322 }
323 }
324}
Note: See TracBrowser for help on using the repository browser.