source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetDetailPanel.java@ 14555

Last change on this file since 14555 was 14555, checked in by GerdP, 5 years ago

see #17040 commit ChangesetDetail-v2.patch

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