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

Last change on this file since 9526 was 9493, checked in by Don-vip, 8 years ago

reduce code duplication

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