source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetDetailPanel.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: 17.6 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.trc;
6
7import java.awt.BorderLayout;
8import java.awt.FlowLayout;
9import java.awt.GridBagConstraints;
10import java.awt.GridBagLayout;
11import java.awt.Insets;
12import java.awt.event.ActionEvent;
13import java.awt.event.ComponentAdapter;
14import java.awt.event.ComponentEvent;
15import java.beans.PropertyChangeEvent;
16import java.beans.PropertyChangeListener;
17import java.text.SimpleDateFormat;
18import java.util.Collection;
19import java.util.Collections;
20import java.util.HashSet;
21import java.util.Set;
22
23import javax.swing.AbstractAction;
24import javax.swing.BorderFactory;
25import javax.swing.JLabel;
26import javax.swing.JOptionPane;
27import javax.swing.JPanel;
28import javax.swing.JTextArea;
29import javax.swing.JTextField;
30import javax.swing.JToolBar;
31
32import org.openstreetmap.josm.Main;
33import org.openstreetmap.josm.actions.AutoScaleAction;
34import org.openstreetmap.josm.data.osm.Changeset;
35import org.openstreetmap.josm.data.osm.ChangesetCache;
36import org.openstreetmap.josm.data.osm.OsmPrimitive;
37import org.openstreetmap.josm.gui.HelpAwareOptionPane;
38import org.openstreetmap.josm.gui.MapView;
39import org.openstreetmap.josm.gui.MapView.EditLayerChangeListener;
40import org.openstreetmap.josm.gui.help.HelpUtil;
41import org.openstreetmap.josm.gui.layer.OsmDataLayer;
42import org.openstreetmap.josm.tools.ImageProvider;
43
44/**
45 * This panel displays the properties of the currently selected changeset in the
46 * {@see ChangesetCacheManager}.
47 *
48 */
49public class ChangesetDetailPanel extends JPanel implements PropertyChangeListener{
50
51 private JTextField tfID;
52 private JTextArea taComment;
53 private JTextField tfOpen;
54 private JTextField tfUser;
55 private JTextField tfCreatedOn;
56 private JTextField tfClosedOn;
57 private DonwloadChangesetContentAction actDownloadChangesetContent;
58 private UpdateChangesetAction actUpdateChangesets;
59 private RemoveFromCacheAction actRemoveFromCache;
60 private SelectInCurrentLayerAction actSelectInCurrentLayer;
61 private ZoomInCurrentLayerAction actZoomInCurrentLayerAction;
62
63 private Changeset current = null;
64
65 protected JPanel buildActionButtonPanel() {
66 JPanel pnl = new JPanel(new FlowLayout(FlowLayout.LEFT));
67
68 JToolBar tb = new JToolBar(JToolBar.VERTICAL);
69 tb.setFloatable(false);
70
71 // -- remove from cache action
72 tb.add(actRemoveFromCache = new RemoveFromCacheAction());
73 actRemoveFromCache.initProperties(current);
74
75 // -- changeset update
76 tb.add(actUpdateChangesets = new UpdateChangesetAction());
77 actUpdateChangesets.initProperties(current);
78
79 // -- changeset content download
80 tb.add(actDownloadChangesetContent =new DonwloadChangesetContentAction());
81 actDownloadChangesetContent.initProperties(current);
82
83 tb.add(actSelectInCurrentLayer = new SelectInCurrentLayerAction());
84 MapView.addEditLayerChangeListener(actSelectInCurrentLayer);
85
86 tb.add(actZoomInCurrentLayerAction = new ZoomInCurrentLayerAction());
87 MapView.addEditLayerChangeListener(actZoomInCurrentLayerAction);
88
89 addComponentListener(
90 new ComponentAdapter() {
91 @Override
92 public void componentHidden(ComponentEvent e) {
93 // make sure the listener is unregistered when the panel becomes
94 // invisible
95 MapView.removeEditLayerChangeListener(actSelectInCurrentLayer);
96 MapView.removeEditLayerChangeListener(actZoomInCurrentLayerAction);
97 }
98 }
99 );
100
101 pnl.add(tb);
102 return pnl;
103 }
104
105 protected JPanel buildDetailViewPanel() {
106 JPanel pnl = new JPanel(new GridBagLayout());
107
108 GridBagConstraints gc = new GridBagConstraints();
109 gc.anchor = GridBagConstraints.FIRST_LINE_START;
110 gc.insets = new Insets(0,0,2,3);
111
112 //-- id
113 gc.fill = GridBagConstraints.HORIZONTAL;
114 gc.weightx = 0.0;
115 pnl.add(new JLabel(tr("ID:")), gc);
116
117 gc.fill = GridBagConstraints.HORIZONTAL;
118 gc.weightx = 0.0;
119 gc.gridx = 1;
120 pnl.add(tfID = new JTextField(10), gc);
121 tfID.setEditable(false);
122
123 //-- comment
124 gc.gridx = 0;
125 gc.gridy = 1;
126 gc.fill = GridBagConstraints.HORIZONTAL;
127 gc.weightx = 0.0;
128 pnl.add(new JLabel(tr("Comment:")), gc);
129
130 gc.fill = GridBagConstraints.BOTH;
131 gc.weightx = 1.0;
132 gc.weighty = 1.0;
133 gc.gridx = 1;
134 pnl.add(taComment= new JTextArea(5,40), gc);
135 taComment.setEditable(false);
136
137 //-- Open/Closed
138 gc.gridx = 0;
139 gc.gridy = 2;
140 gc.fill = GridBagConstraints.HORIZONTAL;
141 gc.weightx = 0.0;
142 gc.weighty = 0.0;
143 pnl.add(new JLabel(tr("Open/Closed:")), gc);
144
145 gc.fill = GridBagConstraints.HORIZONTAL;
146 gc.gridx = 1;
147 pnl.add(tfOpen= new JTextField(10), gc);
148 tfOpen.setEditable(false);
149
150 //-- Created by:
151 gc.gridx = 0;
152 gc.gridy = 3;
153 gc.fill = GridBagConstraints.HORIZONTAL;
154 gc.weightx = 0.0;
155 pnl.add(new JLabel(tr("Created by:")), gc);
156
157 gc.fill = GridBagConstraints.HORIZONTAL;
158 gc.weightx = 1.0;
159 gc.gridx = 1;
160 pnl.add(tfUser= new JTextField(""), gc);
161 tfUser.setEditable(false);
162
163 //-- Created On:
164 gc.gridx = 0;
165 gc.gridy = 4;
166 gc.fill = GridBagConstraints.HORIZONTAL;
167 gc.weightx = 0.0;
168 pnl.add(new JLabel(tr("Created on:")), gc);
169
170 gc.fill = GridBagConstraints.HORIZONTAL;
171 gc.gridx = 1;
172 pnl.add(tfCreatedOn= new JTextField(20), gc);
173 tfCreatedOn.setEditable(false);
174
175 //-- Closed On:
176 gc.gridx = 0;
177 gc.gridy = 5;
178 gc.fill = GridBagConstraints.HORIZONTAL;
179 gc.weightx = 0.0;
180 pnl.add(new JLabel(tr("Closed on:")), gc);
181
182 gc.fill = GridBagConstraints.HORIZONTAL;
183 gc.gridx = 1;
184 pnl.add(tfClosedOn= new JTextField(20), gc);
185 tfClosedOn.setEditable(false);
186
187 return pnl;
188 }
189
190 protected void build() {
191 setLayout(new BorderLayout());
192 setBorder(BorderFactory.createEmptyBorder(3,3,3,3));
193 add(buildDetailViewPanel(), BorderLayout.CENTER);
194 add(buildActionButtonPanel(), BorderLayout.WEST);
195 }
196
197 protected void clearView() {
198 tfID.setText("");
199 taComment.setText("");
200 tfOpen.setText("");
201 tfUser.setText("");
202 tfCreatedOn.setText("");
203 tfClosedOn.setText("");
204 }
205
206 protected void updateView(Changeset cs) {
207 String msg;
208 if (cs == null) return;
209 tfID.setText(Integer.toString(cs.getId()));
210 String comment = cs.get("comment");
211 taComment.setText(comment == null ? "" : comment);
212
213 if (cs.isOpen()) {
214 msg = trc("changeset.state", "Open");
215 } else {
216 msg = trc("changeset.state", "Closed");
217 }
218 tfOpen.setText(msg);
219
220 if (cs.getUser() == null) {
221 msg = tr("anonymous");
222 } else {
223 msg = cs.getUser().getName();
224 }
225 tfUser.setText(msg);
226 SimpleDateFormat sdf = new SimpleDateFormat();
227
228 tfCreatedOn.setText(cs.getCreatedAt() == null ? "" : sdf.format(cs.getCreatedAt()));
229 tfClosedOn.setText(cs.getClosedAt() == null ? "" : sdf.format(cs.getClosedAt()));
230 }
231
232 public ChangesetDetailPanel() {
233 build();
234 }
235
236 protected void setCurrentChangeset(Changeset cs) {
237 current = cs;
238 if (cs == null) {
239 clearView();
240 } else {
241 updateView(cs);
242 }
243 actDownloadChangesetContent.initProperties(current);
244 actUpdateChangesets.initProperties(current);
245 actRemoveFromCache.initProperties(current);
246 actSelectInCurrentLayer.updateEnabledState();
247 actZoomInCurrentLayerAction.updateEnabledState();
248 }
249
250 /* ---------------------------------------------------------------------------- */
251 /* interface PropertyChangeListener */
252 /* ---------------------------------------------------------------------------- */
253 public void propertyChange(PropertyChangeEvent evt) {
254 if (! evt.getPropertyName().equals(ChangesetCacheManagerModel.CHANGESET_IN_DETAIL_VIEW_PROP))
255 return;
256 Changeset cs = (Changeset)evt.getNewValue();
257 setCurrentChangeset(cs);
258 }
259
260 /**
261 * The action for removing the currently selected changeset from the changeset cache
262 */
263 class RemoveFromCacheAction extends AbstractAction {
264 public RemoveFromCacheAction() {
265 putValue(NAME, tr("Remove from cache"));
266 putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete"));
267 putValue(SHORT_DESCRIPTION, tr("Remove the changeset in the detail view panel from the local cache"));
268 }
269
270 public void actionPerformed(ActionEvent evt) {
271 if (current == null)
272 return;
273 ChangesetCache.getInstance().remove(current);
274 }
275
276 public void initProperties(Changeset cs) {
277 setEnabled(cs != null);
278 }
279 }
280
281 /**
282 * Removes the selected changesets from the local changeset cache
283 *
284 */
285 class DonwloadChangesetContentAction extends AbstractAction{
286 public DonwloadChangesetContentAction() {
287 putValue(NAME, tr("Download content"));
288 putValue(SMALL_ICON, ImageProvider.get("dialogs/changeset","downloadchangesetcontent"));
289 putValue(SHORT_DESCRIPTION, tr("Download the changeset content from the OSM server"));
290 }
291
292 public void actionPerformed(ActionEvent evt) {
293 if (current == null) return;
294 ChangesetContentDownloadTask task = new ChangesetContentDownloadTask(ChangesetDetailPanel.this,current.getId());
295 ChangesetCacheManager.getInstance().runDownloadTask(task);
296 }
297
298 public void initProperties(Changeset cs) {
299 if (cs == null) {
300 setEnabled(false);
301 return;
302 } else {
303 setEnabled(true);
304 }
305 if (cs.getContent() == null) {
306 putValue(NAME, tr("Download content"));
307 putValue(SMALL_ICON, ImageProvider.get("dialogs/changeset","downloadchangesetcontent"));
308 putValue(SHORT_DESCRIPTION, tr("Download the changeset content from the OSM server"));
309 } else {
310 putValue(NAME, tr("Update content"));
311 putValue(SMALL_ICON, ImageProvider.get("dialogs/changeset","updatechangesetcontent"));
312 putValue(SHORT_DESCRIPTION, tr("Update the changeset content from the OSM server"));
313 }
314 }
315 }
316
317
318 /**
319 * Updates the current changeset from the OSM server
320 *
321 */
322 class UpdateChangesetAction extends AbstractAction{
323 public UpdateChangesetAction() {
324 putValue(NAME, tr("Update changeset"));
325 putValue(SMALL_ICON,ImageProvider.get("dialogs/changeset","updatechangeset"));
326 putValue(SHORT_DESCRIPTION, tr("Update the changeset from the OSM server"));
327 }
328
329 public void actionPerformed(ActionEvent evt) {
330 if (current == null) return;
331 Main.worker.submit(
332 new ChangesetHeaderDownloadTask(
333 ChangesetDetailPanel.this,
334 Collections.singleton(current.getId())
335 )
336 );
337 }
338
339 public void initProperties(Changeset cs) {
340 if (cs == null) {
341 setEnabled(false);
342 return;
343 } else {
344 setEnabled(true);
345 }
346 }
347 }
348
349 /**
350 * Selects the primitives in the content of this changeset in the the current
351 * data layer.
352 *
353 */
354 class SelectInCurrentLayerAction extends AbstractAction implements EditLayerChangeListener{
355
356 public SelectInCurrentLayerAction() {
357 putValue(NAME, tr("Select in layer"));
358 putValue(SMALL_ICON, ImageProvider.get("dialogs", "select"));
359 putValue(SHORT_DESCRIPTION, tr("Select the primitives in the content of this changeset in the current data layer"));
360 updateEnabledState();
361 }
362
363 protected void alertNoPrimitivesToSelect(Collection<OsmPrimitive> primitives) {
364 HelpAwareOptionPane.showOptionDialog(
365 ChangesetDetailPanel.this,
366 tr("<html>None of the objects in the content of changeset {0} is available in the current<br>"
367 + "edit layer ''{1}''.</html>",
368 current.getId(),
369 Main.main.getEditLayer().getName()
370 ),
371 tr("Nothing to select"),
372 JOptionPane.WARNING_MESSAGE,
373 HelpUtil.ht("/Dialog/ChangesetCacheManager#NothingToSelectInLayer")
374 );
375 }
376
377 public void actionPerformed(ActionEvent arg0) {
378 if (!isEnabled())
379 return;
380 if (Main.main == null || Main.main.getEditLayer() == null) return;
381 OsmDataLayer layer = Main.main.getEditLayer();
382 Set<OsmPrimitive> target = new HashSet<OsmPrimitive>();
383 for (OsmPrimitive p: layer.data.getNodes()) {
384 if (p.isUsable() && p.getChangesetId() == current.getId()) {
385 target.add(p);
386 }
387 }
388 for (OsmPrimitive p: layer.data.getWays()) {
389 if (p.isUsable() && p.getChangesetId() == current.getId()) {
390 target.add(p);
391 }
392 }
393 for (OsmPrimitive p: layer.data.getRelations()) {
394 if (p.isUsable() && p.getChangesetId() == current.getId()) {
395 target.add(p);
396 }
397 }
398 if (target.isEmpty()) {
399 alertNoPrimitivesToSelect(target);
400 return;
401 }
402 layer.data.setSelected(target);
403 }
404
405 public void updateEnabledState() {
406 if (Main.main == null || Main.main.getEditLayer() == null){
407 setEnabled(false);
408 return;
409 }
410 setEnabled(current != null);
411 }
412
413 public void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) {
414 updateEnabledState();
415 }
416 }
417
418 /**
419 * Zooms to the primitives in the content of this changeset in the the current
420 * data layer.
421 *
422 */
423 class ZoomInCurrentLayerAction extends AbstractAction implements EditLayerChangeListener{
424
425 public ZoomInCurrentLayerAction() {
426 putValue(NAME, tr("Zoom to in layer"));
427 putValue(SMALL_ICON, ImageProvider.get("dialogs/autoscale", "selection"));
428 putValue(SHORT_DESCRIPTION, tr("Zoom to the primitives in the content of this changeset in the current data layer"));
429 updateEnabledState();
430 }
431
432 protected void alertNoPrimitivesToZoomTo() {
433 HelpAwareOptionPane.showOptionDialog(
434 ChangesetDetailPanel.this,
435 tr("<html>None of the objects in the content of changeset {0} is available in the current<br>"
436 + "edit layer ''{1}''.</html>",
437 current.getId(),
438 Main.main.getEditLayer().getName()
439 ),
440 tr("Nothing to zoom to"),
441 JOptionPane.WARNING_MESSAGE,
442 HelpUtil.ht("/Dialog/ChangesetCacheManager#NothingToZoomTo")
443 );
444 }
445
446 public void actionPerformed(ActionEvent arg0) {
447 if (!isEnabled())
448 return;
449 if (Main.main == null || Main.main.getEditLayer() == null) return;
450 OsmDataLayer layer = Main.main.getEditLayer();
451 Set<OsmPrimitive> target = new HashSet<OsmPrimitive>();
452 for (OsmPrimitive p: layer.data.getNodes()) {
453 if (p.isUsable() && p.getChangesetId() == current.getId()) {
454 target.add(p);
455 }
456 }
457 for (OsmPrimitive p: layer.data.getWays()) {
458 if (p.isUsable() && p.getChangesetId() == current.getId()) {
459 target.add(p);
460 }
461 }
462 for (OsmPrimitive p: layer.data.getRelations()) {
463 if (p.isUsable() && p.getChangesetId() == current.getId()) {
464 target.add(p);
465 }
466 }
467 if (target.isEmpty()) {
468 alertNoPrimitivesToZoomTo();
469 return;
470 }
471 layer.data.setSelected(target);
472 AutoScaleAction.zoomToSelection();
473 }
474
475 public void updateEnabledState() {
476 if (Main.main == null || Main.main.getEditLayer() == null){
477 setEnabled(false);
478 return;
479 }
480 setEnabled(current != null);
481 }
482
483 public void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) {
484 updateEnabledState();
485 }
486 }
487}
Note: See TracBrowser for help on using the repository browser.