source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetContentPanel.java@ 2689

Last change on this file since 2689 was 2689, checked in by Gubaer, 17 years ago

new: Changeset Cache Manager for querying, downloading, browsing, and managing changesets within JOSM. See also Changeset Manager and Changeset Query Dialog

File size: 18.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.dialogs.changeset;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5import static org.openstreetmap.josm.tools.I18n.trn;
6
7import java.awt.BorderLayout;
8import java.awt.FlowLayout;
9import java.awt.event.ActionEvent;
10import java.awt.event.ComponentAdapter;
11import java.awt.event.ComponentEvent;
12import java.awt.event.MouseAdapter;
13import java.awt.event.MouseEvent;
14import java.beans.PropertyChangeEvent;
15import java.beans.PropertyChangeListener;
16import java.util.ArrayList;
17import java.util.Collection;
18import java.util.HashSet;
19import java.util.List;
20import java.util.Set;
21
22import javax.swing.AbstractAction;
23import javax.swing.BorderFactory;
24import javax.swing.DefaultListSelectionModel;
25import javax.swing.JButton;
26import javax.swing.JOptionPane;
27import javax.swing.JPanel;
28import javax.swing.JPopupMenu;
29import javax.swing.JScrollPane;
30import javax.swing.JSeparator;
31import javax.swing.JTable;
32import javax.swing.JToolBar;
33import javax.swing.SwingUtilities;
34import javax.swing.event.ListSelectionEvent;
35import javax.swing.event.ListSelectionListener;
36
37import org.openstreetmap.josm.Main;
38import org.openstreetmap.josm.actions.AutoScaleAction;
39import org.openstreetmap.josm.data.osm.Changeset;
40import org.openstreetmap.josm.data.osm.OsmPrimitive;
41import org.openstreetmap.josm.data.osm.history.History;
42import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
43import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
44import org.openstreetmap.josm.gui.HelpAwareOptionPane;
45import org.openstreetmap.josm.gui.JMultilineLabel;
46import org.openstreetmap.josm.gui.MapView;
47import org.openstreetmap.josm.gui.MapView.EditLayerChangeListener;
48import org.openstreetmap.josm.gui.help.HelpUtil;
49import org.openstreetmap.josm.gui.history.HistoryBrowserDialogManager;
50import org.openstreetmap.josm.gui.history.HistoryLoadTask;
51import org.openstreetmap.josm.gui.layer.OsmDataLayer;
52import org.openstreetmap.josm.tools.BugReportExceptionHandler;
53import org.openstreetmap.josm.tools.ImageProvider;
54
55/**
56 * The panel which displays the content of a changeset in a scollable table.
57 *
58 * It listens to property change events for {@see ChangesetCacheManagerModel#CHANGESET_IN_DETAIL_VIEW_PROP}
59 * and updates its view accordingly.
60 *
61 */
62public class ChangesetContentPanel extends JPanel implements PropertyChangeListener{
63
64 private ChangesetContentTableModel model;
65 private Changeset currentChangeset;
66 private JTable tblContent;
67
68 private DonwloadChangesetContentAction actDownloadContentAction;
69 private ShowHistoryAction actShowHistory;
70 private SelectInCurrentLayerAction actSelectInCurrentLayerAction;
71 private ZoomInCurrentLayerAction actZoomInCurrentLayerAction;
72
73 private HeaderPanel pnlHeader;
74
75 protected void buildModels() {
76 DefaultListSelectionModel selectionModel =new DefaultListSelectionModel();
77 model = new ChangesetContentTableModel(selectionModel);
78 actDownloadContentAction = new DonwloadChangesetContentAction();
79 actDownloadContentAction.initProperties(currentChangeset);
80 actShowHistory = new ShowHistoryAction();
81 model.getSelectionModel().addListSelectionListener(actShowHistory);
82
83 actSelectInCurrentLayerAction = new SelectInCurrentLayerAction();
84 model.getSelectionModel().addListSelectionListener(actSelectInCurrentLayerAction);
85 MapView.addEditLayerChangeListener(actSelectInCurrentLayerAction);
86
87 actZoomInCurrentLayerAction = new ZoomInCurrentLayerAction();
88 model.getSelectionModel().addListSelectionListener(actZoomInCurrentLayerAction);
89 MapView.addEditLayerChangeListener(actZoomInCurrentLayerAction);
90
91 addComponentListener(
92 new ComponentAdapter() {
93 @Override
94 public void componentHidden(ComponentEvent e) {
95 // make sure the listener is unregistered when the panel becomes
96 // invisible
97 MapView.removeEditLayerChangeListener(actSelectInCurrentLayerAction);
98 MapView.removeEditLayerChangeListener(actZoomInCurrentLayerAction);
99 }
100 }
101 );
102 }
103
104 protected JPanel buildContentPanel() {
105 JPanel pnl = new JPanel(new BorderLayout());
106 tblContent = new JTable(
107 model,
108 new ChangesetContentTableColumnModel(),
109 model.getSelectionModel()
110 );
111 tblContent.addMouseListener(new ChangesetContentTablePopupMenuLauncher());
112 pnl.add(new JScrollPane(tblContent), BorderLayout.CENTER);
113 return pnl;
114 }
115
116 protected JPanel buildActionButtonPanel() {
117 JPanel pnl = new JPanel(new FlowLayout(FlowLayout.LEFT));
118 JToolBar tb = new JToolBar(JToolBar.VERTICAL);
119 tb.setFloatable(false);
120
121 tb.add(actDownloadContentAction);
122 tb.add(actShowHistory);
123 tb.add(actSelectInCurrentLayerAction);
124 tb.add(actZoomInCurrentLayerAction);
125
126 pnl.add(tb);
127 return pnl;
128 }
129
130 protected void build() {
131 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
132 setLayout(new BorderLayout());
133 buildModels();
134
135 add(pnlHeader = new HeaderPanel(), BorderLayout.NORTH);
136 add(buildActionButtonPanel(), BorderLayout.WEST);
137 add(buildContentPanel(), BorderLayout.CENTER);
138
139 }
140
141 public ChangesetContentPanel() {
142 build();
143 }
144
145 public ChangesetContentTableModel getModel() {
146 return model;
147 }
148
149 protected void setCurrentChangeset(Changeset cs) {
150 currentChangeset = cs;
151 if (cs == null) {
152 model.populate(null);
153 } else {
154 model.populate(cs.getContent());
155 }
156 actDownloadContentAction.initProperties(cs);
157 pnlHeader.setChangeset(cs);
158 }
159
160 /* ---------------------------------------------------------------------------- */
161 /* interface PropertyChangeListener */
162 /* ---------------------------------------------------------------------------- */
163 public void propertyChange(PropertyChangeEvent evt) {
164 if(!evt.getPropertyName().equals(ChangesetCacheManagerModel.CHANGESET_IN_DETAIL_VIEW_PROP))
165 return;
166 Changeset cs = (Changeset)evt.getNewValue();
167 setCurrentChangeset(cs);
168 }
169
170
171 /**
172 * Downloads/Updates the content of the changeset
173 *
174 */
175 class DonwloadChangesetContentAction extends AbstractAction{
176 public DonwloadChangesetContentAction() {
177 putValue(NAME, tr("Download content"));
178 putValue(SMALL_ICON, ImageProvider.get("dialogs/changeset","downloadchangesetcontent"));
179 putValue(SHORT_DESCRIPTION, tr("Download the changeset content from the OSM server"));
180 }
181
182 public void actionPerformed(ActionEvent evt) {
183 if (currentChangeset == null) return;
184 ChangesetContentDownloadTask task = new ChangesetContentDownloadTask(ChangesetContentPanel.this,currentChangeset.getId());
185 ChangesetCacheManager.getInstance().runDownloadTask(task);
186 }
187
188 public void initProperties(Changeset cs) {
189 if (cs == null) {
190 setEnabled(false);
191 return;
192 } else {
193 setEnabled(true);
194 }
195 if (cs.getContent() == null) {
196 putValue(NAME, tr("Download content"));
197 putValue(SMALL_ICON, ImageProvider.get("dialogs/changeset","downloadchangesetcontent"));
198 putValue(SHORT_DESCRIPTION, tr("Download the changeset content from the OSM server"));
199 } else {
200 putValue(NAME, tr("Update content"));
201 putValue(SMALL_ICON, ImageProvider.get("dialogs/changeset","updatechangesetcontent"));
202 putValue(SHORT_DESCRIPTION, tr("Update the changeset content from the OSM server"));
203 }
204 }
205 }
206
207 class ChangesetContentTablePopupMenuLauncher extends MouseAdapter {
208 ChangesetContentTablePopupMenu menu = new ChangesetContentTablePopupMenu();
209
210 protected void launch(MouseEvent evt) {
211 if (! evt.isPopupTrigger()) return;
212 if (! model.hasSelectedPrimitives()) {
213 int row = tblContent.rowAtPoint(evt.getPoint());
214 if (row >= 0) {
215 model.setSelectedByIdx(row);
216 }
217 }
218 menu.show(tblContent, evt.getPoint().x, evt.getPoint().y);
219 }
220
221 @Override
222 public void mouseClicked(MouseEvent evt) {
223 launch(evt);
224 }
225
226 @Override
227 public void mousePressed(MouseEvent evt) {
228 launch(evt);
229 }
230
231 @Override
232 public void mouseReleased(MouseEvent evt) {
233 launch(evt);
234 }
235 }
236
237 class ChangesetContentTablePopupMenu extends JPopupMenu {
238 public ChangesetContentTablePopupMenu() {
239 add(actDownloadContentAction);
240 add(actShowHistory);
241 add(new JSeparator());
242 add(actSelectInCurrentLayerAction);
243 add(actZoomInCurrentLayerAction);
244 }
245 }
246
247 class ShowHistoryAction extends AbstractAction implements ListSelectionListener{
248 public ShowHistoryAction() {
249 putValue(NAME, tr("Show history"));
250 putValue(SMALL_ICON, ImageProvider.get("dialogs", "history"));
251 putValue(SHORT_DESCRIPTION, tr("Download and show the history of the selected primitives"));
252 updateEnabledState();
253 }
254
255 protected List<HistoryOsmPrimitive> filterPrimitivesWithUnloadedHistory(Collection<HistoryOsmPrimitive> primitives) {
256 ArrayList<HistoryOsmPrimitive> ret = new ArrayList<HistoryOsmPrimitive>(primitives.size());
257 for (HistoryOsmPrimitive p: primitives) {
258 if (HistoryDataSet.getInstance().getHistory(p.getPrimitiveId()) == null) {
259 ret.add(p);
260 }
261 }
262 return ret;
263 }
264
265 public void showHistory(final Collection<HistoryOsmPrimitive> primitives) {
266 List<HistoryOsmPrimitive> toLoad = filterPrimitivesWithUnloadedHistory(primitives);
267 if (!toLoad.isEmpty()) {
268 HistoryLoadTask task = new HistoryLoadTask(ChangesetContentPanel.this);
269 for (HistoryOsmPrimitive p: toLoad) {
270 task.add(p);
271 }
272 Main.worker.submit(task);
273 }
274
275 Runnable r = new Runnable() {
276 public void run() {
277 try {
278 for (HistoryOsmPrimitive p : primitives) {
279 History h = HistoryDataSet.getInstance().getHistory(p.getPrimitiveId());
280 if (h == null) {
281 continue;
282 }
283 HistoryBrowserDialogManager.getInstance().show(h);
284 }
285 } catch (final Exception e) {
286 SwingUtilities.invokeLater(new Runnable() {
287 public void run() {
288 BugReportExceptionHandler.handleException(e);
289 }
290 });
291 }
292
293 }
294 };
295 Main.worker.submit(r);
296 }
297
298 protected void updateEnabledState() {
299 setEnabled(model.hasSelectedPrimitives());
300 }
301
302 public void actionPerformed(ActionEvent arg0) {
303 Set<HistoryOsmPrimitive> selected = model.getSelectedPrimitives();
304 if (selected.isEmpty()) return;
305 showHistory(selected);
306 }
307
308 public void valueChanged(ListSelectionEvent e) {
309 updateEnabledState();
310 }
311 }
312
313 class SelectInCurrentLayerAction extends AbstractAction implements ListSelectionListener, EditLayerChangeListener{
314
315 public SelectInCurrentLayerAction() {
316 putValue(NAME, tr("Select in layer"));
317 putValue(SMALL_ICON, ImageProvider.get("dialogs", "select"));
318 putValue(SHORT_DESCRIPTION, tr("Select the corresponding primitives in the current data layer"));
319 updateEnabledState();
320 }
321
322 protected void alertNoPrimitivesToSelect(Collection<HistoryOsmPrimitive> primitives) {
323 HelpAwareOptionPane.showOptionDialog(
324 ChangesetContentPanel.this,
325 trn("<html>The selected object isn''t available in the current<br>"
326 + "edit layer ''{0}''.</html>",
327 "<html>None of the selected objects is available in the current<br>"
328 + "edit layer ''{0}''.</html>",
329 primitives.size(),
330 Main.main.getEditLayer().getName()
331 ),
332 tr("Nothing to select"),
333 JOptionPane.WARNING_MESSAGE,
334 HelpUtil.ht("/Dialog/ChangesetCacheManager#NothingToSelectInLayer")
335 );
336 }
337
338 public void actionPerformed(ActionEvent arg0) {
339 if (!isEnabled())
340 return;
341 if (Main.main == null || Main.main.getEditLayer() == null) return;
342 OsmDataLayer layer = Main.main.getEditLayer();
343 Set<HistoryOsmPrimitive> selected = model.getSelectedPrimitives();
344 Set<OsmPrimitive> target = new HashSet<OsmPrimitive>();
345 for (HistoryOsmPrimitive p : model.getSelectedPrimitives()) {
346 OsmPrimitive op = layer.data.getPrimitiveById(p.getPrimitiveId());
347 if (op != null) {
348 target.add(op);
349 }
350 }
351 if (target.isEmpty()) {
352 alertNoPrimitivesToSelect(selected);
353 return;
354 }
355 layer.data.setSelected(target);
356 }
357
358 public void updateEnabledState() {
359 if (Main.main == null || Main.main.getEditLayer() == null){
360 setEnabled(false);
361 return;
362 }
363 setEnabled(model.hasSelectedPrimitives());
364 }
365
366 public void valueChanged(ListSelectionEvent e) {
367 updateEnabledState();
368 }
369
370 public void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) {
371 updateEnabledState();
372 }
373 }
374
375 class ZoomInCurrentLayerAction extends AbstractAction implements ListSelectionListener, EditLayerChangeListener{
376
377 public ZoomInCurrentLayerAction() {
378 putValue(NAME, tr("Zoom to in layer"));
379 putValue(SMALL_ICON, ImageProvider.get("dialogs/autoscale", "selection"));
380 putValue(SHORT_DESCRIPTION, tr("Zoom to the corresponding primitives in the current data layer"));
381 updateEnabledState();
382 }
383
384 protected void alertNoPrimitivesToZoomTo(Collection<HistoryOsmPrimitive> primitives) {
385 HelpAwareOptionPane.showOptionDialog(
386 ChangesetContentPanel.this,
387 trn("<html>The selected object isn''t available in the current<br>"
388 + "edit layer ''{0}''.</html>",
389 "<html>None of the selected objects is available in the current<br>"
390 + "edit layer ''{0}''.</html>",
391 primitives.size(),
392 Main.main.getEditLayer().getName()
393 ),
394 tr("Nothing to zoom to"),
395 JOptionPane.WARNING_MESSAGE,
396 HelpUtil.ht("/Dialog/ChangesetCacheManager#NothingToZoomTo")
397 );
398 }
399
400 public void actionPerformed(ActionEvent arg0) {
401 if (!isEnabled())
402 return;
403 if (Main.main == null || Main.main.getEditLayer() == null) return;
404 OsmDataLayer layer = Main.main.getEditLayer();
405 Set<HistoryOsmPrimitive> selected = model.getSelectedPrimitives();
406 Set<OsmPrimitive> target = new HashSet<OsmPrimitive>();
407 for (HistoryOsmPrimitive p : model.getSelectedPrimitives()) {
408 OsmPrimitive op = layer.data.getPrimitiveById(p.getPrimitiveId());
409 if (op != null) {
410 target.add(op);
411 }
412 }
413 if (target.isEmpty()) {
414 alertNoPrimitivesToZoomTo(selected);
415 return;
416 }
417 layer.data.setSelected(target);
418 AutoScaleAction.zoomToSelection();
419 }
420
421 public void updateEnabledState() {
422 if (Main.main == null || Main.main.getEditLayer() == null){
423 setEnabled(false);
424 return;
425 }
426 setEnabled(model.hasSelectedPrimitives());
427 }
428
429 public void valueChanged(ListSelectionEvent e) {
430 updateEnabledState();
431 }
432
433 public void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) {
434 updateEnabledState();
435 }
436 }
437
438 static private class HeaderPanel extends JPanel {
439
440 private JMultilineLabel lblMessage;
441 private Changeset current;
442 private DownloadAction actDownload;
443
444 protected void build() {
445 setLayout(new FlowLayout(FlowLayout.LEFT));
446 lblMessage = new JMultilineLabel(
447 tr("The content of this changeset is not downloaded yet.")
448 );
449 add(lblMessage);
450 add(new JButton(actDownload = new DownloadAction()));
451
452 }
453
454 public HeaderPanel() {
455 build();
456 }
457
458 public void setChangeset(Changeset cs) {
459 setVisible(cs != null && cs.getContent() == null);
460 this.current = cs;
461 }
462
463 private class DownloadAction extends AbstractAction {
464 public DownloadAction() {
465 putValue(NAME, tr("Download now"));
466 putValue(SHORT_DESCRIPTION, tr("Download the changeset content"));
467 putValue(SMALL_ICON, ImageProvider.get("dialogs/changeset", "downloadchangesetcontent"));
468 }
469
470 public void actionPerformed(ActionEvent evt) {
471 if (current == null) return;
472 ChangesetContentDownloadTask task = new ChangesetContentDownloadTask(HeaderPanel.this, current.getId());
473 ChangesetCacheManager.getInstance().runDownloadTask(task);
474 }
475 }
476 }
477}
Note: See TracBrowser for help on using the repository browser.