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

Revision 3995, 16.3 KB checked in by mjulius, 14 months ago (diff)

fix #3590 - Primitives or objects: Pick one

  • Property svn:eol-style set to native
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     * Updates the current changeset from the OSM server
319     *
320     */
321    class UpdateChangesetAction extends AbstractAction{
322        public UpdateChangesetAction() {
323            putValue(NAME, tr("Update changeset"));
324            putValue(SMALL_ICON,ImageProvider.get("dialogs/changeset","updatechangeset"));
325            putValue(SHORT_DESCRIPTION, tr("Update the changeset from the OSM server"));
326        }
327
328        public void actionPerformed(ActionEvent evt) {
329            if (current == null) return;
330            Main.worker.submit(
331                    new ChangesetHeaderDownloadTask(
332                            ChangesetDetailPanel.this,
333                            Collections.singleton(current.getId())
334                    )
335            );
336        }
337
338        public void initProperties(Changeset cs) {
339            if (cs == null) {
340                setEnabled(false);
341                return;
342            } else {
343                setEnabled(true);
344            }
345        }
346    }
347
348    /**
349     * Selects the primitives in the content of this changeset in the current
350     * data layer.
351     *
352     */
353    class SelectInCurrentLayerAction extends AbstractAction implements EditLayerChangeListener{
354
355        public SelectInCurrentLayerAction() {
356            putValue(NAME, tr("Select in layer"));
357            putValue(SMALL_ICON, ImageProvider.get("dialogs", "select"));
358            putValue(SHORT_DESCRIPTION, tr("Select the primitives in the content of this changeset in the current data layer"));
359            updateEnabledState();
360        }
361
362        protected void alertNoPrimitivesToSelect(Collection<OsmPrimitive> primitives) {
363            HelpAwareOptionPane.showOptionDialog(
364                    ChangesetDetailPanel.this,
365                    tr("<html>None of the objects in the content of changeset {0} is available in the current<br>"
366                            + "edit layer ''{1}''.</html>",
367                            current.getId(),
368                            Main.main.getEditLayer().getName()
369                    ),
370                    tr("Nothing to select"),
371                    JOptionPane.WARNING_MESSAGE,
372                    HelpUtil.ht("/Dialog/ChangesetCacheManager#NothingToSelectInLayer")
373            );
374        }
375
376        public void actionPerformed(ActionEvent arg0) {
377            if (!isEnabled())
378                return;
379            if (Main.main == null || Main.main.getEditLayer() == null) return;
380            OsmDataLayer layer = Main.main.getEditLayer();
381            Set<OsmPrimitive> target = new HashSet<OsmPrimitive>();
382            for (OsmPrimitive p: layer.data.allPrimitives()) {
383                if (p.isUsable() && p.getChangesetId() == current.getId()) {
384                    target.add(p);
385                }
386            }
387            if (target.isEmpty()) {
388                alertNoPrimitivesToSelect(target);
389                return;
390            }
391            layer.data.setSelected(target);
392        }
393
394        public void updateEnabledState() {
395            if (Main.main == null || Main.main.getEditLayer() == null){
396                setEnabled(false);
397                return;
398            }
399            setEnabled(current != null);
400        }
401
402        public void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) {
403            updateEnabledState();
404        }
405    }
406
407    /**
408     * Zooms to the primitives in the content of this changeset in the current
409     * data layer.
410     *
411     */
412    class ZoomInCurrentLayerAction extends AbstractAction implements EditLayerChangeListener{
413
414        public ZoomInCurrentLayerAction() {
415            putValue(NAME, tr("Zoom to in layer"));
416            putValue(SMALL_ICON, ImageProvider.get("dialogs/autoscale", "selection"));
417            putValue(SHORT_DESCRIPTION, tr("Zoom to the objects in the content of this changeset in the current data layer"));
418            updateEnabledState();
419        }
420
421        protected void alertNoPrimitivesToZoomTo() {
422            HelpAwareOptionPane.showOptionDialog(
423                    ChangesetDetailPanel.this,
424                    tr("<html>None of the objects in the content of changeset {0} is available in the current<br>"
425                            + "edit layer ''{1}''.</html>",
426                            current.getId(),
427                            Main.main.getEditLayer().getName()
428                    ),
429                    tr("Nothing to zoom to"),
430                    JOptionPane.WARNING_MESSAGE,
431                    HelpUtil.ht("/Dialog/ChangesetCacheManager#NothingToZoomTo")
432            );
433        }
434
435        public void actionPerformed(ActionEvent arg0) {
436            if (!isEnabled())
437                return;
438            if (Main.main == null || Main.main.getEditLayer() == null) return;
439            OsmDataLayer layer = Main.main.getEditLayer();
440            Set<OsmPrimitive> target = new HashSet<OsmPrimitive>();
441            for (OsmPrimitive p: layer.data.allPrimitives()) {
442                if (p.isUsable() && p.getChangesetId() == current.getId()) {
443                    target.add(p);
444                }
445            }
446            if (target.isEmpty()) {
447                alertNoPrimitivesToZoomTo();
448                return;
449            }
450            layer.data.setSelected(target);
451            AutoScaleAction.zoomToSelection();
452        }
453
454        public void updateEnabledState() {
455            if (Main.main == null || Main.main.getEditLayer() == null){
456                setEnabled(false);
457                return;
458            }
459            setEnabled(current != null);
460        }
461
462        public void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) {
463            updateEnabledState();
464        }
465    }
466}
Note: See TracBrowser for help on using the repository browser.