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

Revision 4786, 18.3 KB checked in by simon04, 4 months ago (diff)

fix #7255 - CT status of users is not loaded in history view

  • 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.trn;
6
7import java.awt.BorderLayout;
8import java.awt.FlowLayout;
9import java.awt.event.ActionEvent;
10import java.awt.event.ComponentAdapter;
11import java.awt.event.ComponentEvent;
12import java.awt.event.MouseAdapter;
13import java.awt.event.MouseEvent;
14import java.beans.PropertyChangeEvent;
15import java.beans.PropertyChangeListener;
16import java.util.ArrayList;
17import java.util.Collection;
18import java.util.HashSet;
19import java.util.List;
20import java.util.Set;
21
22import javax.swing.AbstractAction;
23import javax.swing.BorderFactory;
24import javax.swing.DefaultListSelectionModel;
25import javax.swing.JButton;
26import javax.swing.JOptionPane;
27import javax.swing.JPanel;
28import javax.swing.JPopupMenu;
29import javax.swing.JScrollPane;
30import javax.swing.JSeparator;
31import javax.swing.JTable;
32import javax.swing.JToolBar;
33import javax.swing.SwingUtilities;
34import javax.swing.event.ListSelectionEvent;
35import javax.swing.event.ListSelectionListener;
36
37import org.openstreetmap.josm.Main;
38import org.openstreetmap.josm.actions.AutoScaleAction;
39import org.openstreetmap.josm.data.osm.Changeset;
40import org.openstreetmap.josm.data.osm.OsmPrimitive;
41import org.openstreetmap.josm.data.osm.history.History;
42import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
43import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
44import org.openstreetmap.josm.gui.HelpAwareOptionPane;
45import org.openstreetmap.josm.gui.JMultilineLabel;
46import org.openstreetmap.josm.gui.MapView;
47import org.openstreetmap.josm.gui.MapView.EditLayerChangeListener;
48import org.openstreetmap.josm.gui.help.HelpUtil;
49import org.openstreetmap.josm.gui.history.HistoryBrowserDialogManager;
50import org.openstreetmap.josm.gui.history.HistoryLoadTask;
51import org.openstreetmap.josm.gui.layer.OsmDataLayer;
52import org.openstreetmap.josm.gui.progress.ContributorTermsUpdateRunnable;
53import org.openstreetmap.josm.tools.BugReportExceptionHandler;
54import org.openstreetmap.josm.tools.ImageProvider;
55
56/**
57 * The panel which displays the content of a changeset in a scollable table.
58 *
59 * It listens to property change events for {@see ChangesetCacheManagerModel#CHANGESET_IN_DETAIL_VIEW_PROP}
60 * and updates its view accordingly.
61 *
62 */
63public class ChangesetContentPanel extends JPanel implements PropertyChangeListener{
64
65    private ChangesetContentTableModel model;
66    private Changeset currentChangeset;
67    private JTable tblContent;
68
69    private DonwloadChangesetContentAction actDownloadContentAction;
70    private ShowHistoryAction actShowHistory;
71    private SelectInCurrentLayerAction actSelectInCurrentLayerAction;
72    private ZoomInCurrentLayerAction actZoomInCurrentLayerAction;
73
74    private HeaderPanel pnlHeader;
75
76    protected void buildModels() {
77        DefaultListSelectionModel selectionModel =new DefaultListSelectionModel();
78        model = new ChangesetContentTableModel(selectionModel);
79        actDownloadContentAction = new DonwloadChangesetContentAction();
80        actDownloadContentAction.initProperties(currentChangeset);
81        actShowHistory = new ShowHistoryAction();
82        model.getSelectionModel().addListSelectionListener(actShowHistory);
83
84        actSelectInCurrentLayerAction = new SelectInCurrentLayerAction();
85        model.getSelectionModel().addListSelectionListener(actSelectInCurrentLayerAction);
86        MapView.addEditLayerChangeListener(actSelectInCurrentLayerAction);
87
88        actZoomInCurrentLayerAction = new ZoomInCurrentLayerAction();
89        model.getSelectionModel().addListSelectionListener(actZoomInCurrentLayerAction);
90        MapView.addEditLayerChangeListener(actZoomInCurrentLayerAction);
91
92        addComponentListener(
93                new ComponentAdapter() {
94                    @Override
95                    public void componentHidden(ComponentEvent e) {
96                        // make sure the listener is unregistered when the panel becomes
97                        // invisible
98                        MapView.removeEditLayerChangeListener(actSelectInCurrentLayerAction);
99                        MapView.removeEditLayerChangeListener(actZoomInCurrentLayerAction);
100                    }
101                }
102        );
103    }
104
105    protected JPanel buildContentPanel() {
106        JPanel pnl = new JPanel(new BorderLayout());
107        tblContent = new JTable(
108                model,
109                new ChangesetContentTableColumnModel(),
110                model.getSelectionModel()
111        );
112        tblContent.addMouseListener(new ChangesetContentTablePopupMenuLauncher());
113        pnl.add(new JScrollPane(tblContent), BorderLayout.CENTER);
114        return pnl;
115    }
116
117    protected JPanel buildActionButtonPanel() {
118        JPanel pnl = new JPanel(new FlowLayout(FlowLayout.LEFT));
119        JToolBar tb = new JToolBar(JToolBar.VERTICAL);
120        tb.setFloatable(false);
121
122        tb.add(actDownloadContentAction);
123        tb.add(actShowHistory);
124        tb.add(actSelectInCurrentLayerAction);
125        tb.add(actZoomInCurrentLayerAction);
126
127        pnl.add(tb);
128        return pnl;
129    }
130
131    protected void build() {
132        setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
133        setLayout(new BorderLayout());
134        buildModels();
135
136        add(pnlHeader = new HeaderPanel(), BorderLayout.NORTH);
137        add(buildActionButtonPanel(), BorderLayout.WEST);
138        add(buildContentPanel(), BorderLayout.CENTER);
139
140    }
141
142    public ChangesetContentPanel() {
143        build();
144    }
145
146    public ChangesetContentTableModel getModel() {
147        return model;
148    }
149
150    protected void setCurrentChangeset(Changeset cs) {
151        currentChangeset = cs;
152        if (cs == null) {
153            model.populate(null);
154        } else {
155            model.populate(cs.getContent());
156        }
157        actDownloadContentAction.initProperties(cs);
158        pnlHeader.setChangeset(cs);
159    }
160
161    /* ---------------------------------------------------------------------------- */
162    /* interface PropertyChangeListener                                             */
163    /* ---------------------------------------------------------------------------- */
164    public void propertyChange(PropertyChangeEvent evt) {
165        if(!evt.getPropertyName().equals(ChangesetCacheManagerModel.CHANGESET_IN_DETAIL_VIEW_PROP))
166            return;
167        Changeset cs = (Changeset)evt.getNewValue();
168        setCurrentChangeset(cs);
169    }
170
171    /**
172     * Downloads/Updates the content of the changeset
173     *
174     */
175    class DonwloadChangesetContentAction extends AbstractAction{
176        public DonwloadChangesetContentAction() {
177            putValue(NAME, tr("Download content"));
178            putValue(SMALL_ICON, ImageProvider.get("dialogs/changeset","downloadchangesetcontent"));
179            putValue(SHORT_DESCRIPTION, tr("Download the changeset content from the OSM server"));
180        }
181
182        public void actionPerformed(ActionEvent evt) {
183            if (currentChangeset == null) return;
184            ChangesetContentDownloadTask task = new ChangesetContentDownloadTask(ChangesetContentPanel.this,currentChangeset.getId());
185            ChangesetCacheManager.getInstance().runDownloadTask(task);
186        }
187
188        public void initProperties(Changeset cs) {
189            if (cs == null) {
190                setEnabled(false);
191                return;
192            } else {
193                setEnabled(true);
194            }
195            if (cs.getContent() == null) {
196                putValue(NAME, tr("Download content"));
197                putValue(SMALL_ICON, ImageProvider.get("dialogs/changeset","downloadchangesetcontent"));
198                putValue(SHORT_DESCRIPTION, tr("Download the changeset content from the OSM server"));
199            } else {
200                putValue(NAME, tr("Update content"));
201                putValue(SMALL_ICON, ImageProvider.get("dialogs/changeset","updatechangesetcontent"));
202                putValue(SHORT_DESCRIPTION, tr("Update the changeset content from the OSM server"));
203            }
204        }
205    }
206
207    class ChangesetContentTablePopupMenuLauncher extends MouseAdapter {
208        ChangesetContentTablePopupMenu menu = new ChangesetContentTablePopupMenu();
209
210        protected void launch(MouseEvent evt) {
211            if (! evt.isPopupTrigger()) return;
212            if (! model.hasSelectedPrimitives()) {
213                int row = tblContent.rowAtPoint(evt.getPoint());
214                if (row >= 0) {
215                    model.setSelectedByIdx(row);
216                }
217            }
218            menu.show(tblContent, evt.getPoint().x, evt.getPoint().y);
219        }
220
221        @Override
222        public void mouseClicked(MouseEvent evt) {
223            launch(evt);
224        }
225
226        @Override
227        public void mousePressed(MouseEvent evt) {
228            launch(evt);
229        }
230
231        @Override
232        public void mouseReleased(MouseEvent evt) {
233            launch(evt);
234        }
235    }
236
237    class ChangesetContentTablePopupMenu extends JPopupMenu {
238        public ChangesetContentTablePopupMenu() {
239            add(actDownloadContentAction);
240            add(actShowHistory);
241            add(new JSeparator());
242            add(actSelectInCurrentLayerAction);
243            add(actZoomInCurrentLayerAction);
244        }
245    }
246
247    class ShowHistoryAction extends AbstractAction implements ListSelectionListener{
248        public ShowHistoryAction() {
249            putValue(NAME, tr("Show history"));
250            putValue(SMALL_ICON, ImageProvider.get("dialogs", "history"));
251            putValue(SHORT_DESCRIPTION, tr("Download and show the history of the selected objects"));
252            updateEnabledState();
253        }
254
255        protected List<HistoryOsmPrimitive> filterPrimitivesWithUnloadedHistory(Collection<HistoryOsmPrimitive> primitives) {
256            ArrayList<HistoryOsmPrimitive> ret = new ArrayList<HistoryOsmPrimitive>(primitives.size());
257            for (HistoryOsmPrimitive p: primitives) {
258                if (HistoryDataSet.getInstance().getHistory(p.getPrimitiveId()) == null) {
259                    ret.add(p);
260                }
261            }
262            return ret;
263        }
264
265        public void showHistory(final Collection<HistoryOsmPrimitive> primitives) {
266            Main.worker.submit(new ContributorTermsUpdateRunnable());
267
268            List<HistoryOsmPrimitive> toLoad = filterPrimitivesWithUnloadedHistory(primitives);
269            if (!toLoad.isEmpty()) {
270                HistoryLoadTask task = new HistoryLoadTask(ChangesetContentPanel.this);
271                for (HistoryOsmPrimitive p: toLoad) {
272                    task.add(p);
273                }
274                Main.worker.submit(task);
275            }
276
277            Runnable r = new Runnable() {
278                public void run() {
279                    try {
280                        for (HistoryOsmPrimitive p : primitives) {
281                            History h = HistoryDataSet.getInstance().getHistory(p.getPrimitiveId());
282                            if (h == null) {
283                                continue;
284                            }
285                            HistoryBrowserDialogManager.getInstance().show(h);
286                        }
287                    } catch (final Exception e) {
288                        SwingUtilities.invokeLater(new Runnable() {
289                            public void run() {
290                                BugReportExceptionHandler.handleException(e);
291                            }
292                        });
293                    }
294
295                }
296            };
297            Main.worker.submit(r);
298        }
299
300        protected void updateEnabledState() {
301            setEnabled(model.hasSelectedPrimitives());
302        }
303
304        public void actionPerformed(ActionEvent arg0) {
305            Set<HistoryOsmPrimitive> selected = model.getSelectedPrimitives();
306            if (selected.isEmpty()) return;
307            showHistory(selected);
308        }
309
310        public void valueChanged(ListSelectionEvent e) {
311            updateEnabledState();
312        }
313    }
314
315    class SelectInCurrentLayerAction extends AbstractAction implements ListSelectionListener, EditLayerChangeListener{
316
317        public SelectInCurrentLayerAction() {
318            putValue(NAME, tr("Select in layer"));
319            putValue(SMALL_ICON, ImageProvider.get("dialogs", "select"));
320            putValue(SHORT_DESCRIPTION, tr("Select the corresponding primitives in the current data layer"));
321            updateEnabledState();
322        }
323
324        protected void alertNoPrimitivesToSelect(Collection<HistoryOsmPrimitive> primitives) {
325            HelpAwareOptionPane.showOptionDialog(
326                    ChangesetContentPanel.this,
327                    trn("<html>The selected object is not available in the current<br>"
328                            + "edit layer ''{0}''.</html>",
329                            "<html>None of the selected objects is available in the current<br>"
330                            + "edit layer ''{0}''.</html>",
331                            primitives.size(),
332                            Main.main.getEditLayer().getName()
333                    ),
334                    tr("Nothing to select"),
335                    JOptionPane.WARNING_MESSAGE,
336                    HelpUtil.ht("/Dialog/ChangesetCacheManager#NothingToSelectInLayer")
337            );
338        }
339
340        public void actionPerformed(ActionEvent arg0) {
341            if (!isEnabled())
342                return;
343            if (Main.main == null || Main.main.getEditLayer() == null) return;
344            OsmDataLayer layer = Main.main.getEditLayer();
345            Set<HistoryOsmPrimitive> selected = model.getSelectedPrimitives();
346            Set<OsmPrimitive> target = new HashSet<OsmPrimitive>();
347            for (HistoryOsmPrimitive p : model.getSelectedPrimitives()) {
348                OsmPrimitive op = layer.data.getPrimitiveById(p.getPrimitiveId());
349                if (op != null) {
350                    target.add(op);
351                }
352            }
353            if (target.isEmpty()) {
354                alertNoPrimitivesToSelect(selected);
355                return;
356            }
357            layer.data.setSelected(target);
358        }
359
360        public void updateEnabledState() {
361            if (Main.main == null || Main.main.getEditLayer() == null){
362                setEnabled(false);
363                return;
364            }
365            setEnabled(model.hasSelectedPrimitives());
366        }
367
368        public void valueChanged(ListSelectionEvent e) {
369            updateEnabledState();
370        }
371
372        public void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) {
373            updateEnabledState();
374        }
375    }
376
377    class ZoomInCurrentLayerAction extends AbstractAction implements ListSelectionListener, EditLayerChangeListener{
378
379        public ZoomInCurrentLayerAction() {
380            putValue(NAME, tr("Zoom to in layer"));
381            putValue(SMALL_ICON, ImageProvider.get("dialogs/autoscale", "selection"));
382            putValue(SHORT_DESCRIPTION, tr("Zoom to the corresponding objects in the current data layer"));
383            updateEnabledState();
384        }
385
386        protected void alertNoPrimitivesToZoomTo(Collection<HistoryOsmPrimitive> primitives) {
387            HelpAwareOptionPane.showOptionDialog(
388                    ChangesetContentPanel.this,
389                    trn("<html>The selected object is not available in the current<br>"
390                            + "edit layer ''{0}''.</html>",
391                            "<html>None of the selected objects is available in the current<br>"
392                            + "edit layer ''{0}''.</html>",
393                            primitives.size(),
394                            Main.main.getEditLayer().getName()
395                    ),
396                    tr("Nothing to zoom to"),
397                    JOptionPane.WARNING_MESSAGE,
398                    HelpUtil.ht("/Dialog/ChangesetCacheManager#NothingToZoomTo")
399            );
400        }
401
402        public void actionPerformed(ActionEvent arg0) {
403            if (!isEnabled())
404                return;
405            if (Main.main == null || Main.main.getEditLayer() == null) return;
406            OsmDataLayer layer = Main.main.getEditLayer();
407            Set<HistoryOsmPrimitive> selected = model.getSelectedPrimitives();
408            Set<OsmPrimitive> target = new HashSet<OsmPrimitive>();
409            for (HistoryOsmPrimitive p : model.getSelectedPrimitives()) {
410                OsmPrimitive op = layer.data.getPrimitiveById(p.getPrimitiveId());
411                if (op != null) {
412                    target.add(op);
413                }
414            }
415            if (target.isEmpty()) {
416                alertNoPrimitivesToZoomTo(selected);
417                return;
418            }
419            layer.data.setSelected(target);
420            AutoScaleAction.zoomToSelection();
421        }
422
423        public void updateEnabledState() {
424            if (Main.main == null || Main.main.getEditLayer() == null){
425                setEnabled(false);
426                return;
427            }
428            setEnabled(model.hasSelectedPrimitives());
429        }
430
431        public void valueChanged(ListSelectionEvent e) {
432            updateEnabledState();
433        }
434
435        public void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) {
436            updateEnabledState();
437        }
438    }
439
440    static private class HeaderPanel extends JPanel {
441
442        private JMultilineLabel lblMessage;
443        private Changeset current;
444
445        protected void build() {
446            setLayout(new FlowLayout(FlowLayout.LEFT));
447            lblMessage = new JMultilineLabel(
448                    tr("The content of this changeset is not downloaded yet.")
449            );
450            add(lblMessage);
451            add(new JButton(new DownloadAction()));
452
453        }
454
455        public HeaderPanel() {
456            build();
457        }
458
459        public void setChangeset(Changeset cs) {
460            setVisible(cs != null && cs.getContent() == null);
461            this.current = cs;
462        }
463
464        private class DownloadAction extends AbstractAction {
465            public DownloadAction() {
466                putValue(NAME, tr("Download now"));
467                putValue(SHORT_DESCRIPTION, tr("Download the changeset content"));
468                putValue(SMALL_ICON, ImageProvider.get("dialogs/changeset", "downloadchangesetcontent"));
469            }
470
471            public void actionPerformed(ActionEvent evt) {
472                if (current == null) return;
473                ChangesetContentDownloadTask task = new ChangesetContentDownloadTask(HeaderPanel.this, current.getId());
474                ChangesetCacheManager.getInstance().runDownloadTask(task);
475            }
476        }
477    }
478}
Note: See TracBrowser for help on using the repository browser.