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

Last change on this file since 16469 was 16469, checked in by simon04, 4 years ago

Checkstyle

  • Property svn:eol-style set to native
File size: 15.0 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.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.beans.PropertyChangeEvent;
13import java.beans.PropertyChangeListener;
14import java.util.Collection;
15import java.util.Collections;
16import java.util.List;
17import java.util.Objects;
18import java.util.Set;
19import java.util.stream.Collectors;
20
21import javax.swing.AbstractAction;
22import javax.swing.BorderFactory;
23import javax.swing.DefaultListSelectionModel;
24import javax.swing.JButton;
25import javax.swing.JComponent;
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.SwingConstants;
34import javax.swing.event.ListSelectionEvent;
35import javax.swing.event.ListSelectionListener;
36
37import org.openstreetmap.josm.actions.AutoScaleAction;
38import org.openstreetmap.josm.actions.HistoryInfoAction;
39import org.openstreetmap.josm.actions.downloadtasks.ChangesetContentDownloadTask;
40import org.openstreetmap.josm.data.osm.Changeset;
41import org.openstreetmap.josm.data.osm.DataSet;
42import org.openstreetmap.josm.data.osm.OsmPrimitive;
43import org.openstreetmap.josm.data.osm.PrimitiveId;
44import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
45import org.openstreetmap.josm.gui.HelpAwareOptionPane;
46import org.openstreetmap.josm.gui.MainApplication;
47import org.openstreetmap.josm.gui.help.HelpUtil;
48import org.openstreetmap.josm.gui.history.HistoryBrowserDialogManager;
49import org.openstreetmap.josm.gui.io.DownloadPrimitivesWithReferrersTask;
50import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeEvent;
51import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener;
52import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
53import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
54import org.openstreetmap.josm.tools.ImageProvider;
55import org.openstreetmap.josm.tools.Utils;
56
57/**
58 * The panel which displays the content of a changeset in a scrollable table.
59 *
60 * It listens to property change events for {@link ChangesetCacheManagerModel#CHANGESET_IN_DETAIL_VIEW_PROP}
61 * and updates its view accordingly.
62 * @since 2689
63 */
64public class ChangesetContentPanel extends JPanel implements PropertyChangeListener, ChangesetAware {
65 private JTable tblContent;
66 private ChangesetContentTableModel model;
67 private transient Changeset currentChangeset;
68
69 private DownloadChangesetContentAction actDownloadContentAction;
70 private ShowHistoryAction actShowHistory;
71 private SelectInCurrentLayerAction actSelectInCurrentLayerAction;
72 private ZoomInCurrentLayerAction actZoomInCurrentLayerAction;
73
74 private final HeaderPanel pnlHeader = new HeaderPanel();
75 protected DownloadObjectAction actDownloadObjectAction;
76
77 protected void buildModels() {
78 DefaultListSelectionModel selectionModel = new DefaultListSelectionModel();
79 model = new ChangesetContentTableModel(selectionModel);
80 actDownloadContentAction = new DownloadChangesetContentAction(this);
81 actDownloadContentAction.initProperties();
82
83 actDownloadObjectAction = new DownloadObjectAction();
84 model.getSelectionModel().addListSelectionListener(actDownloadObjectAction);
85
86 actShowHistory = new ShowHistoryAction();
87 model.getSelectionModel().addListSelectionListener(actShowHistory);
88
89 actSelectInCurrentLayerAction = new SelectInCurrentLayerAction();
90 model.getSelectionModel().addListSelectionListener(actSelectInCurrentLayerAction);
91 MainApplication.getLayerManager().addActiveLayerChangeListener(actSelectInCurrentLayerAction);
92
93 actZoomInCurrentLayerAction = new ZoomInCurrentLayerAction();
94 model.getSelectionModel().addListSelectionListener(actZoomInCurrentLayerAction);
95 MainApplication.getLayerManager().addActiveLayerChangeListener(actZoomInCurrentLayerAction);
96
97 addComponentListener(
98 new ComponentAdapter() {
99 @Override
100 public void componentShown(ComponentEvent e) {
101 MainApplication.getLayerManager().addAndFireActiveLayerChangeListener(actSelectInCurrentLayerAction);
102 MainApplication.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 MainApplication.getLayerManager().removeActiveLayerChangeListener(actSelectInCurrentLayerAction);
109 MainApplication.getLayerManager().removeActiveLayerChangeListener(actZoomInCurrentLayerAction);
110 }
111 }
112 );
113 }
114
115 protected JPanel buildContentPanel() {
116 JPanel pnl = new JPanel(new BorderLayout());
117 tblContent = new JTable(
118 model,
119 new ChangesetContentTableColumnModel(),
120 model.getSelectionModel()
121 );
122 tblContent.setAutoCreateRowSorter(true);
123 tblContent.addMouseListener(new PopupMenuLauncher(new ChangesetContentTablePopupMenu()));
124 HistoryInfoAction historyAction = MainApplication.getMenu().historyinfo;
125 tblContent.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(historyAction.getShortcut().getKeyStroke(), "historyAction");
126 tblContent.getActionMap().put("historyAction", historyAction);
127 pnl.add(new JScrollPane(tblContent), BorderLayout.CENTER);
128 return pnl;
129 }
130
131 protected JPanel buildActionButtonPanel() {
132 JPanel pnl = new JPanel(new FlowLayout(FlowLayout.LEFT));
133 JToolBar tb = new JToolBar(SwingConstants.VERTICAL);
134 tb.setFloatable(false);
135
136 tb.add(actDownloadContentAction);
137 tb.addSeparator();
138 tb.add(actDownloadObjectAction);
139 tb.add(actShowHistory);
140 tb.addSeparator();
141 tb.add(actSelectInCurrentLayerAction);
142 tb.add(actZoomInCurrentLayerAction);
143
144 pnl.add(tb);
145 return pnl;
146 }
147
148 protected final void build() {
149 setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
150 setLayout(new BorderLayout());
151 buildModels();
152
153 add(pnlHeader, BorderLayout.NORTH);
154 add(buildActionButtonPanel(), BorderLayout.WEST);
155 add(buildContentPanel(), BorderLayout.CENTER);
156 }
157
158 /**
159 * Constructs a new {@code ChangesetContentPanel}.
160 */
161 public ChangesetContentPanel() {
162 build();
163 }
164
165 /**
166 * Replies the changeset content model
167 * @return The model
168 */
169 public ChangesetContentTableModel getModel() {
170 return model;
171 }
172
173 protected void setCurrentChangeset(Changeset cs) {
174 currentChangeset = cs;
175 if (cs == null) {
176 model.populate(null);
177 } else {
178 model.populate(cs.getContent());
179 }
180 actDownloadContentAction.initProperties();
181 pnlHeader.setChangeset(cs);
182 }
183
184 /* ---------------------------------------------------------------------------- */
185 /* interface PropertyChangeListener */
186 /* ---------------------------------------------------------------------------- */
187 @Override
188 public void propertyChange(PropertyChangeEvent evt) {
189 if (!evt.getPropertyName().equals(ChangesetCacheManagerModel.CHANGESET_IN_DETAIL_VIEW_PROP))
190 return;
191 Changeset cs = (Changeset) evt.getNewValue();
192 setCurrentChangeset(cs);
193 }
194
195 private void alertNoPrimitivesTo(Collection<HistoryOsmPrimitive> primitives, String title, String helpTopic) {
196 HelpAwareOptionPane.showOptionDialog(
197 this,
198 trn("<html>The selected object is not available in the current<br>"
199 + "edit layer ''{0}''.</html>",
200 "<html>None of the selected objects is available in the current<br>"
201 + "edit layer ''{0}''.</html>",
202 primitives.size(),
203 Utils.escapeReservedCharactersHTML(MainApplication.getLayerManager().getEditLayer().getName())
204 ),
205 title, JOptionPane.WARNING_MESSAGE, helpTopic
206 );
207 }
208
209 private Set<HistoryOsmPrimitive> getSelectedPrimitives() {
210 return model.getSelectedPrimitives(tblContent);
211 }
212
213 class ChangesetContentTablePopupMenu extends JPopupMenu {
214 ChangesetContentTablePopupMenu() {
215 add(actDownloadContentAction);
216 add(new JSeparator());
217 add(actDownloadObjectAction);
218 add(actShowHistory);
219 add(new JSeparator());
220 add(actSelectInCurrentLayerAction);
221 add(actZoomInCurrentLayerAction);
222 }
223 }
224
225 class ShowHistoryAction extends AbstractAction implements ListSelectionListener {
226
227 ShowHistoryAction() {
228 putValue(NAME, tr("Show history"));
229 new ImageProvider("dialogs", "history").getResource().attachImageIcon(this);
230 putValue(SHORT_DESCRIPTION, tr("Download and show the history of the selected objects"));
231 updateEnabledState();
232 }
233
234 protected final void updateEnabledState() {
235 setEnabled(model.hasSelectedPrimitives());
236 }
237
238 @Override
239 public void actionPerformed(ActionEvent e) {
240 Set<HistoryOsmPrimitive> selected = getSelectedPrimitives();
241 if (selected.isEmpty()) return;
242 HistoryBrowserDialogManager.getInstance().showHistory(selected);
243 }
244
245 @Override
246 public void valueChanged(ListSelectionEvent e) {
247 updateEnabledState();
248 }
249 }
250
251 class DownloadObjectAction extends AbstractAction implements ListSelectionListener {
252
253 DownloadObjectAction() {
254 putValue(NAME, tr("Download objects"));
255 new ImageProvider("downloadprimitive").getResource().attachImageIcon(this, true);
256 putValue(SHORT_DESCRIPTION, tr("Download the current version of the selected objects"));
257 updateEnabledState();
258 }
259
260 @Override
261 public void actionPerformed(ActionEvent e) {
262 final List<PrimitiveId> primitiveIds = getSelectedPrimitives().stream().map(HistoryOsmPrimitive::getPrimitiveId)
263 .collect(Collectors.toList());
264 MainApplication.worker.submit(new DownloadPrimitivesWithReferrersTask(false, primitiveIds, true, true, null, null));
265 }
266
267 protected final void updateEnabledState() {
268 setEnabled(model.hasSelectedPrimitives());
269 }
270
271 @Override
272 public void valueChanged(ListSelectionEvent e) {
273 updateEnabledState();
274 }
275 }
276
277 abstract class SelectionBasedAction extends AbstractAction implements ListSelectionListener, ActiveLayerChangeListener {
278
279 protected Set<OsmPrimitive> getTarget() {
280 DataSet ds = MainApplication.getLayerManager().getActiveDataSet();
281 if (isEnabled() && ds != null) {
282 return getSelectedPrimitives().stream()
283 .map(p -> ds.getPrimitiveById(p.getPrimitiveId())).filter(Objects::nonNull).collect(Collectors.toSet());
284 }
285 return Collections.emptySet();
286 }
287
288 public final void updateEnabledState() {
289 setEnabled(MainApplication.getLayerManager().getActiveDataSet() != null && model.hasSelectedPrimitives());
290 }
291
292 @Override
293 public void valueChanged(ListSelectionEvent e) {
294 updateEnabledState();
295 }
296
297 @Override
298 public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) {
299 updateEnabledState();
300 }
301 }
302
303 class SelectInCurrentLayerAction extends SelectionBasedAction {
304
305 SelectInCurrentLayerAction() {
306 putValue(NAME, tr("Select in layer"));
307 new ImageProvider("dialogs", "select").getResource().attachImageIcon(this);
308 putValue(SHORT_DESCRIPTION, tr("Select the corresponding primitives in the current data layer"));
309 updateEnabledState();
310 }
311
312 @Override
313 public void actionPerformed(ActionEvent e) {
314 final Set<OsmPrimitive> target = getTarget();
315 if (target.isEmpty()) {
316 alertNoPrimitivesTo(getSelectedPrimitives(), tr("Nothing to select"),
317 HelpUtil.ht("/Dialog/ChangesetCacheManager#NothingToSelectInLayer"));
318 return;
319 }
320 MainApplication.getLayerManager().getActiveDataSet().setSelected(target);
321 }
322 }
323
324 class ZoomInCurrentLayerAction extends SelectionBasedAction {
325
326 ZoomInCurrentLayerAction() {
327 putValue(NAME, tr("Zoom to in layer"));
328 new ImageProvider("dialogs/autoscale", "selection").getResource().attachImageIcon(this);
329 putValue(SHORT_DESCRIPTION, tr("Zoom to the corresponding objects in the current data layer"));
330 updateEnabledState();
331 }
332
333 @Override
334 public void actionPerformed(ActionEvent e) {
335 final Set<OsmPrimitive> target = getTarget();
336 if (target.isEmpty()) {
337 alertNoPrimitivesTo(getSelectedPrimitives(), tr("Nothing to zoom to"),
338 HelpUtil.ht("/Dialog/ChangesetCacheManager#NothingToZoomTo"));
339 return;
340 }
341 MainApplication.getLayerManager().getActiveDataSet().setSelected(target);
342 AutoScaleAction.zoomToSelection();
343 }
344 }
345
346 private static class HeaderPanel extends JPanel {
347
348 private transient Changeset current;
349
350 HeaderPanel() {
351 build();
352 }
353
354 protected final void build() {
355 setLayout(new FlowLayout(FlowLayout.LEFT));
356 add(new JMultilineLabel(tr("The content of this changeset is not downloaded yet.")));
357 add(new JButton(new DownloadAction()));
358
359 }
360
361 public void setChangeset(Changeset cs) {
362 setVisible(cs != null && cs.getContent() == null);
363 this.current = cs;
364 }
365
366 private class DownloadAction extends AbstractAction {
367 DownloadAction() {
368 putValue(NAME, tr("Download now"));
369 putValue(SHORT_DESCRIPTION, tr("Download the changeset content"));
370 new ImageProvider("dialogs/changeset", "downloadchangesetcontent").getResource().attachImageIcon(this);
371 }
372
373 @Override
374 public void actionPerformed(ActionEvent evt) {
375 if (current == null) return;
376 ChangesetContentDownloadTask task = new ChangesetContentDownloadTask(HeaderPanel.this, current.getId());
377 ChangesetCacheManager.getInstance().runDownloadTask(task);
378 }
379 }
380 }
381
382 @Override
383 public Changeset getCurrentChangeset() {
384 return currentChangeset;
385 }
386}
Note: See TracBrowser for help on using the repository browser.