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

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

add Changeset.getComment()

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