source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetCacheManager.java@ 10611

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

see #11390 - sonar - squid:S1604 - Java 8: Anonymous inner classes containing only one method should become lambdas

  • Property svn:eol-style set to native
File size: 25.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;
5
6import java.awt.BorderLayout;
7import java.awt.Component;
8import java.awt.Container;
9import java.awt.Dimension;
10import java.awt.FlowLayout;
11import java.awt.GraphicsEnvironment;
12import java.awt.Window;
13import java.awt.event.ActionEvent;
14import java.awt.event.KeyEvent;
15import java.awt.event.MouseEvent;
16import java.awt.event.WindowAdapter;
17import java.awt.event.WindowEvent;
18import java.util.Collection;
19import java.util.HashSet;
20import java.util.List;
21import java.util.Set;
22
23import javax.swing.AbstractAction;
24import javax.swing.DefaultListSelectionModel;
25import javax.swing.JButton;
26import javax.swing.JComponent;
27import javax.swing.JFrame;
28import javax.swing.JOptionPane;
29import javax.swing.JPanel;
30import javax.swing.JPopupMenu;
31import javax.swing.JScrollPane;
32import javax.swing.JSplitPane;
33import javax.swing.JTabbedPane;
34import javax.swing.JTable;
35import javax.swing.JToolBar;
36import javax.swing.KeyStroke;
37import javax.swing.ListSelectionModel;
38import javax.swing.event.ListSelectionEvent;
39import javax.swing.event.ListSelectionListener;
40
41import org.openstreetmap.josm.Main;
42import org.openstreetmap.josm.actions.downloadtasks.AbstractChangesetDownloadTask;
43import org.openstreetmap.josm.actions.downloadtasks.ChangesetContentDownloadTask;
44import org.openstreetmap.josm.actions.downloadtasks.ChangesetHeaderDownloadTask;
45import org.openstreetmap.josm.actions.downloadtasks.ChangesetQueryTask;
46import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler;
47import org.openstreetmap.josm.data.osm.Changeset;
48import org.openstreetmap.josm.data.osm.ChangesetCache;
49import org.openstreetmap.josm.gui.HelpAwareOptionPane;
50import org.openstreetmap.josm.gui.JosmUserIdentityManager;
51import org.openstreetmap.josm.gui.dialogs.changeset.query.ChangesetQueryDialog;
52import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
53import org.openstreetmap.josm.gui.help.HelpUtil;
54import org.openstreetmap.josm.gui.io.CloseChangesetTask;
55import org.openstreetmap.josm.gui.util.GuiHelper;
56import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
57import org.openstreetmap.josm.io.ChangesetQuery;
58import org.openstreetmap.josm.io.OnlineResource;
59import org.openstreetmap.josm.tools.ImageProvider;
60import org.openstreetmap.josm.tools.WindowGeometry;
61
62/**
63 * ChangesetCacheManager manages the local cache of changesets
64 * retrieved from the OSM API. It displays both a table of the locally cached changesets
65 * and detail information about an individual changeset. It also provides actions for
66 * downloading, querying, closing changesets, in addition to removing changesets from
67 * the local cache.
68 * @since 2689
69 */
70public class ChangesetCacheManager extends JFrame {
71
72 /** the unique instance of the cache manager */
73 private static volatile ChangesetCacheManager instance;
74 private JTabbedPane pnlChangesetDetailTabs;
75
76 /**
77 * Replies the unique instance of the changeset cache manager
78 *
79 * @return the unique instance of the changeset cache manager
80 */
81 public static ChangesetCacheManager getInstance() {
82 if (instance == null) {
83 instance = new ChangesetCacheManager();
84 }
85 return instance;
86 }
87
88 /**
89 * Hides and destroys the unique instance of the changeset cache manager.
90 *
91 */
92 public static void destroyInstance() {
93 if (instance != null) {
94 instance.setVisible(true);
95 instance.dispose();
96 instance = null;
97 }
98 }
99
100 private ChangesetCacheManagerModel model;
101 private JSplitPane spContent;
102 private boolean needsSplitPaneAdjustment;
103
104 private RemoveFromCacheAction actRemoveFromCacheAction;
105 private CloseSelectedChangesetsAction actCloseSelectedChangesetsAction;
106 private DownloadSelectedChangesetsAction actDownloadSelectedChangesets;
107 private DownloadSelectedChangesetContentAction actDownloadSelectedContent;
108 private JTable tblChangesets;
109
110 /**
111 * Creates the various models required.
112 * @return the changeset cache model
113 */
114 static ChangesetCacheManagerModel buildModel() {
115 DefaultListSelectionModel selectionModel = new DefaultListSelectionModel();
116 selectionModel.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
117 return new ChangesetCacheManagerModel(selectionModel);
118 }
119
120 /**
121 * builds the toolbar panel in the heading of the dialog
122 *
123 * @return the toolbar panel
124 */
125 static JPanel buildToolbarPanel() {
126 JPanel pnl = new JPanel(new FlowLayout(FlowLayout.LEFT));
127
128 JButton btn = new JButton(new QueryAction());
129 pnl.add(btn);
130 pnl.add(new SingleChangesetDownloadPanel());
131 pnl.add(new JButton(new DownloadMyChangesets()));
132
133 return pnl;
134 }
135
136 /**
137 * builds the button panel in the footer of the dialog
138 *
139 * @return the button row pane
140 */
141 static JPanel buildButtonPanel() {
142 JPanel pnl = new JPanel(new FlowLayout(FlowLayout.CENTER));
143
144 //-- cancel and close action
145 pnl.add(new JButton(new CancelAction()));
146
147 //-- help action
148 pnl.add(new JButton(new ContextSensitiveHelpAction(HelpUtil.ht("/Dialog/ChangesetManager"))));
149
150 return pnl;
151 }
152
153 /**
154 * Builds the panel with the changeset details
155 *
156 * @return the panel with the changeset details
157 */
158 protected JPanel buildChangesetDetailPanel() {
159 JPanel pnl = new JPanel(new BorderLayout());
160 JTabbedPane tp = new JTabbedPane();
161 pnlChangesetDetailTabs = tp;
162
163 // -- add the details panel
164 ChangesetDetailPanel pnlChangesetDetail = new ChangesetDetailPanel();
165 tp.add(pnlChangesetDetail);
166 model.addPropertyChangeListener(pnlChangesetDetail);
167
168 // -- add the tags panel
169 ChangesetTagsPanel pnlChangesetTags = new ChangesetTagsPanel();
170 tp.add(pnlChangesetTags);
171 model.addPropertyChangeListener(pnlChangesetTags);
172
173 // -- add the panel for the changeset content
174 ChangesetContentPanel pnlChangesetContent = new ChangesetContentPanel();
175 tp.add(pnlChangesetContent);
176 model.addPropertyChangeListener(pnlChangesetContent);
177
178 // -- add the panel for the changeset discussion
179 ChangesetDiscussionPanel pnlChangesetDiscussion = new ChangesetDiscussionPanel();
180 tp.add(pnlChangesetDiscussion);
181 model.addPropertyChangeListener(pnlChangesetDiscussion);
182
183 tp.setTitleAt(0, tr("Properties"));
184 tp.setToolTipTextAt(0, tr("Display the basic properties of the changeset"));
185 tp.setTitleAt(1, tr("Tags"));
186 tp.setToolTipTextAt(1, tr("Display the tags of the changeset"));
187 tp.setTitleAt(2, tr("Content"));
188 tp.setToolTipTextAt(2, tr("Display the objects created, updated, and deleted by the changeset"));
189 tp.setTitleAt(3, tr("Discussion"));
190 tp.setToolTipTextAt(3, tr("Display the public discussion around this changeset"));
191
192 pnl.add(tp, BorderLayout.CENTER);
193 return pnl;
194 }
195
196 /**
197 * builds the content panel of the dialog
198 *
199 * @return the content panel
200 */
201 protected JPanel buildContentPanel() {
202 JPanel pnl = new JPanel(new BorderLayout());
203
204 spContent = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
205 spContent.setLeftComponent(buildChangesetTablePanel());
206 spContent.setRightComponent(buildChangesetDetailPanel());
207 spContent.setOneTouchExpandable(true);
208 spContent.setDividerLocation(0.5);
209
210 pnl.add(spContent, BorderLayout.CENTER);
211 return pnl;
212 }
213
214 /**
215 * Builds the table with actions which can be applied to the currently visible changesets
216 * in the changeset table.
217 *
218 * @return changset actions panel
219 */
220 protected JPanel buildChangesetTableActionPanel() {
221 JPanel pnl = new JPanel(new BorderLayout());
222
223 JToolBar tb = new JToolBar(JToolBar.VERTICAL);
224 tb.setFloatable(false);
225
226 // -- remove from cache action
227 model.getSelectionModel().addListSelectionListener(actRemoveFromCacheAction);
228 tb.add(actRemoveFromCacheAction);
229
230 // -- close selected changesets action
231 model.getSelectionModel().addListSelectionListener(actCloseSelectedChangesetsAction);
232 tb.add(actCloseSelectedChangesetsAction);
233
234 // -- download selected changesets
235 model.getSelectionModel().addListSelectionListener(actDownloadSelectedChangesets);
236 tb.add(actDownloadSelectedChangesets);
237
238 // -- download the content of the selected changesets
239 model.getSelectionModel().addListSelectionListener(actDownloadSelectedContent);
240 tb.add(actDownloadSelectedContent);
241
242 pnl.add(tb, BorderLayout.CENTER);
243 return pnl;
244 }
245
246 /**
247 * Builds the panel with the table of changesets
248 *
249 * @return the panel with the table of changesets
250 */
251 protected JPanel buildChangesetTablePanel() {
252 JPanel pnl = new JPanel(new BorderLayout());
253 tblChangesets = new JTable(
254 model,
255 new ChangesetCacheTableColumnModel(),
256 model.getSelectionModel()
257 );
258 tblChangesets.addMouseListener(new MouseEventHandler());
259 tblChangesets.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "showDetails");
260 tblChangesets.getActionMap().put("showDetails", new ShowDetailAction(model));
261 model.getSelectionModel().addListSelectionListener(new ChangesetDetailViewSynchronizer(model));
262
263 // activate DEL on the table
264 tblChangesets.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "removeFromCache");
265 tblChangesets.getActionMap().put("removeFromCache", actRemoveFromCacheAction);
266
267 pnl.add(new JScrollPane(tblChangesets), BorderLayout.CENTER);
268 pnl.add(buildChangesetTableActionPanel(), BorderLayout.WEST);
269 return pnl;
270 }
271
272 protected void build() {
273 setTitle(tr("Changeset Management Dialog"));
274 setIconImage(ImageProvider.get("dialogs/changeset", "changesetmanager").getImage());
275 Container cp = getContentPane();
276
277 cp.setLayout(new BorderLayout());
278
279 model = buildModel();
280 actRemoveFromCacheAction = new RemoveFromCacheAction(model);
281 actCloseSelectedChangesetsAction = new CloseSelectedChangesetsAction(model);
282 actDownloadSelectedChangesets = new DownloadSelectedChangesetsAction(model);
283 actDownloadSelectedContent = new DownloadSelectedChangesetContentAction(model);
284
285 cp.add(buildToolbarPanel(), BorderLayout.NORTH);
286 cp.add(buildContentPanel(), BorderLayout.CENTER);
287 cp.add(buildButtonPanel(), BorderLayout.SOUTH);
288
289 // the help context
290 HelpUtil.setHelpContext(getRootPane(), HelpUtil.ht("/Dialog/ChangesetManager"));
291
292 // make the dialog respond to ESC
293 getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
294 KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancelAndClose");
295 getRootPane().getActionMap().put("cancelAndClose", new CancelAction());
296
297 // install a window event handler
298 addWindowListener(new WindowEventHandler());
299 }
300
301 /**
302 * Constructs a new {@code ChangesetCacheManager}.
303 */
304 public ChangesetCacheManager() {
305 build();
306 }
307
308 @Override
309 public void setVisible(boolean visible) {
310 if (visible) {
311 new WindowGeometry(
312 getClass().getName() + ".geometry",
313 WindowGeometry.centerInWindow(
314 getParent(),
315 new Dimension(1000, 600)
316 )
317 ).applySafe(this);
318 needsSplitPaneAdjustment = true;
319 model.init();
320
321 } else if (isShowing()) { // Avoid IllegalComponentStateException like in #8775
322 model.tearDown();
323 new WindowGeometry(this).remember(getClass().getName() + ".geometry");
324 }
325 super.setVisible(visible);
326 }
327
328 /**
329 * Handler for window events
330 *
331 */
332 class WindowEventHandler extends WindowAdapter {
333 @Override
334 public void windowClosing(WindowEvent e) {
335 new CancelAction().cancelAndClose();
336 }
337
338 @Override
339 public void windowActivated(WindowEvent e) {
340 if (needsSplitPaneAdjustment) {
341 spContent.setDividerLocation(0.5);
342 needsSplitPaneAdjustment = false;
343 }
344 }
345 }
346
347 /**
348 * the cancel / close action
349 */
350 static class CancelAction extends AbstractAction {
351 CancelAction() {
352 putValue(NAME, tr("Close"));
353 new ImageProvider("cancel").getResource().attachImageIcon(this);
354 putValue(SHORT_DESCRIPTION, tr("Close the dialog"));
355 }
356
357 public void cancelAndClose() {
358 destroyInstance();
359 }
360
361 @Override
362 public void actionPerformed(ActionEvent e) {
363 cancelAndClose();
364 }
365 }
366
367 /**
368 * The action to query and download changesets
369 */
370 static class QueryAction extends AbstractAction {
371
372 QueryAction() {
373 putValue(NAME, tr("Query"));
374 new ImageProvider("dialogs", "search").getResource().attachImageIcon(this);
375 putValue(SHORT_DESCRIPTION, tr("Launch the dialog for querying changesets"));
376 setEnabled(!Main.isOffline(OnlineResource.OSM_API));
377 }
378
379 @Override
380 public void actionPerformed(ActionEvent evt) {
381 Window parent = GuiHelper.getWindowAncestorFor(evt);
382 if (!GraphicsEnvironment.isHeadless()) {
383 ChangesetQueryDialog dialog = new ChangesetQueryDialog(parent);
384 dialog.initForUserInput();
385 dialog.setVisible(true);
386 if (dialog.isCanceled())
387 return;
388
389 try {
390 ChangesetQuery query = dialog.getChangesetQuery();
391 if (query != null) {
392 ChangesetCacheManager.getInstance().runDownloadTask(new ChangesetQueryTask(parent, query));
393 }
394 } catch (IllegalStateException e) {
395 JOptionPane.showMessageDialog(parent, e.getMessage(), tr("Error"), JOptionPane.ERROR_MESSAGE);
396 }
397 }
398 }
399 }
400
401 /**
402 * Removes the selected changesets from the local changeset cache
403 *
404 */
405 static class RemoveFromCacheAction extends AbstractAction implements ListSelectionListener {
406 private final ChangesetCacheManagerModel model;
407
408 RemoveFromCacheAction(ChangesetCacheManagerModel model) {
409 putValue(NAME, tr("Remove from cache"));
410 new ImageProvider("dialogs", "delete").getResource().attachImageIcon(this);
411 putValue(SHORT_DESCRIPTION, tr("Remove the selected changesets from the local cache"));
412 this.model = model;
413 updateEnabledState();
414 }
415
416 @Override
417 public void actionPerformed(ActionEvent e) {
418 ChangesetCache.getInstance().remove(model.getSelectedChangesets());
419 }
420
421 protected void updateEnabledState() {
422 setEnabled(model.hasSelectedChangesets());
423 }
424
425 @Override
426 public void valueChanged(ListSelectionEvent e) {
427 updateEnabledState();
428 }
429 }
430
431 /**
432 * Closes the selected changesets
433 *
434 */
435 static class CloseSelectedChangesetsAction extends AbstractAction implements ListSelectionListener {
436 private final ChangesetCacheManagerModel model;
437
438 CloseSelectedChangesetsAction(ChangesetCacheManagerModel model) {
439 putValue(NAME, tr("Close"));
440 new ImageProvider("closechangeset").getResource().attachImageIcon(this);
441 putValue(SHORT_DESCRIPTION, tr("Close the selected changesets"));
442 this.model = model;
443 updateEnabledState();
444 }
445
446 @Override
447 public void actionPerformed(ActionEvent e) {
448 Main.worker.submit(new CloseChangesetTask(model.getSelectedChangesets()));
449 }
450
451 protected void updateEnabledState() {
452 List<Changeset> selected = model.getSelectedChangesets();
453 JosmUserIdentityManager im = JosmUserIdentityManager.getInstance();
454 for (Changeset cs: selected) {
455 if (cs.isOpen()) {
456 if (im.isPartiallyIdentified() && cs.getUser() != null && cs.getUser().getName().equals(im.getUserName())) {
457 setEnabled(true);
458 return;
459 }
460 if (im.isFullyIdentified() && cs.getUser() != null && cs.getUser().getId() == im.getUserId()) {
461 setEnabled(true);
462 return;
463 }
464 }
465 }
466 setEnabled(false);
467 }
468
469 @Override
470 public void valueChanged(ListSelectionEvent e) {
471 updateEnabledState();
472 }
473 }
474
475 /**
476 * Downloads the selected changesets
477 *
478 */
479 static class DownloadSelectedChangesetsAction extends AbstractAction implements ListSelectionListener {
480 private final ChangesetCacheManagerModel model;
481
482 DownloadSelectedChangesetsAction(ChangesetCacheManagerModel model) {
483 putValue(NAME, tr("Update changeset"));
484 new ImageProvider("dialogs/changeset", "updatechangeset").getResource().attachImageIcon(this);
485 putValue(SHORT_DESCRIPTION, tr("Updates the selected changesets with current data from the OSM server"));
486 this.model = model;
487 updateEnabledState();
488 }
489
490 @Override
491 public void actionPerformed(ActionEvent e) {
492 if (!GraphicsEnvironment.isHeadless()) {
493 ChangesetCacheManager.getInstance().runDownloadTask(
494 ChangesetHeaderDownloadTask.buildTaskForChangesets(GuiHelper.getWindowAncestorFor(e), model.getSelectedChangesets()));
495 }
496 }
497
498 protected void updateEnabledState() {
499 setEnabled(model.hasSelectedChangesets() && !Main.isOffline(OnlineResource.OSM_API));
500 }
501
502 @Override
503 public void valueChanged(ListSelectionEvent e) {
504 updateEnabledState();
505 }
506 }
507
508 /**
509 * Downloads the content of selected changesets from the OSM server
510 *
511 */
512 static class DownloadSelectedChangesetContentAction extends AbstractAction implements ListSelectionListener {
513 private final ChangesetCacheManagerModel model;
514
515 DownloadSelectedChangesetContentAction(ChangesetCacheManagerModel model) {
516 putValue(NAME, tr("Download changeset content"));
517 new ImageProvider("dialogs/changeset", "downloadchangesetcontent").getResource().attachImageIcon(this);
518 putValue(SHORT_DESCRIPTION, tr("Download the content of the selected changesets from the server"));
519 this.model = model;
520 updateEnabledState();
521 }
522
523 @Override
524 public void actionPerformed(ActionEvent e) {
525 if (!GraphicsEnvironment.isHeadless()) {
526 ChangesetCacheManager.getInstance().runDownloadTask(
527 new ChangesetContentDownloadTask(GuiHelper.getWindowAncestorFor(e), model.getSelectedChangesetIds()));
528 }
529 }
530
531 protected void updateEnabledState() {
532 setEnabled(model.hasSelectedChangesets() && !Main.isOffline(OnlineResource.OSM_API));
533 }
534
535 @Override
536 public void valueChanged(ListSelectionEvent e) {
537 updateEnabledState();
538 }
539 }
540
541 static class ShowDetailAction extends AbstractAction {
542 private final ChangesetCacheManagerModel model;
543
544 ShowDetailAction(ChangesetCacheManagerModel model) {
545 this.model = model;
546 }
547
548 protected void showDetails() {
549 List<Changeset> selected = model.getSelectedChangesets();
550 if (selected.size() == 1) {
551 model.setChangesetInDetailView(selected.get(0));
552 }
553 }
554
555 @Override
556 public void actionPerformed(ActionEvent e) {
557 showDetails();
558 }
559 }
560
561 static class DownloadMyChangesets extends AbstractAction {
562 DownloadMyChangesets() {
563 putValue(NAME, tr("My changesets"));
564 new ImageProvider("dialogs/changeset", "downloadchangeset").getResource().attachImageIcon(this);
565 putValue(SHORT_DESCRIPTION, tr("Download my changesets from the OSM server (max. 100 changesets)"));
566 setEnabled(!Main.isOffline(OnlineResource.OSM_API));
567 }
568
569 protected void alertAnonymousUser(Component parent) {
570 HelpAwareOptionPane.showOptionDialog(
571 parent,
572 tr("<html>JOSM is currently running with an anonymous user. It cannot download<br>"
573 + "your changesets from the OSM server unless you enter your OSM user name<br>"
574 + "in the JOSM preferences.</html>"
575 ),
576 tr("Warning"),
577 JOptionPane.WARNING_MESSAGE,
578 HelpUtil.ht("/Dialog/ChangesetManager#CanDownloadMyChangesets")
579 );
580 }
581
582 @Override
583 public void actionPerformed(ActionEvent e) {
584 Window parent = GuiHelper.getWindowAncestorFor(e);
585 JosmUserIdentityManager im = JosmUserIdentityManager.getInstance();
586 if (im.isAnonymous()) {
587 alertAnonymousUser(parent);
588 return;
589 }
590 ChangesetQuery query = new ChangesetQuery();
591 if (im.isFullyIdentified()) {
592 query = query.forUser(im.getUserId());
593 } else {
594 query = query.forUser(im.getUserName());
595 }
596 if (!GraphicsEnvironment.isHeadless()) {
597 ChangesetCacheManager.getInstance().runDownloadTask(new ChangesetQueryTask(parent, query));
598 }
599 }
600 }
601
602 class MouseEventHandler extends PopupMenuLauncher {
603
604 MouseEventHandler() {
605 super(new ChangesetTablePopupMenu());
606 }
607
608 @Override
609 public void mouseClicked(MouseEvent evt) {
610 if (isDoubleClick(evt)) {
611 new ShowDetailAction(model).showDetails();
612 }
613 }
614 }
615
616 class ChangesetTablePopupMenu extends JPopupMenu {
617 ChangesetTablePopupMenu() {
618 add(actRemoveFromCacheAction);
619 add(actCloseSelectedChangesetsAction);
620 add(actDownloadSelectedChangesets);
621 add(actDownloadSelectedContent);
622 }
623 }
624
625 static class ChangesetDetailViewSynchronizer implements ListSelectionListener {
626 private final ChangesetCacheManagerModel model;
627
628 ChangesetDetailViewSynchronizer(ChangesetCacheManagerModel model) {
629 this.model = model;
630 }
631
632 @Override
633 public void valueChanged(ListSelectionEvent e) {
634 List<Changeset> selected = model.getSelectedChangesets();
635 if (selected.size() == 1) {
636 model.setChangesetInDetailView(selected.get(0));
637 } else {
638 model.setChangesetInDetailView(null);
639 }
640 }
641 }
642
643 /**
644 * Selects the changesets in <code>changests</code>, provided the
645 * respective changesets are already present in the local changeset cache.
646 *
647 * @param changesets the collection of changesets. If {@code null}, the
648 * selection is cleared.
649 */
650 public void setSelectedChangesets(Collection<Changeset> changesets) {
651 model.setSelectedChangesets(changesets);
652 final int idx = model.getSelectionModel().getMinSelectionIndex();
653 if (idx < 0)
654 return;
655 GuiHelper.runInEDTAndWait(() -> tblChangesets.scrollRectToVisible(tblChangesets.getCellRect(idx, 0, true)));
656 repaint();
657 }
658
659 /**
660 * Selects the changesets with the ids in <code>ids</code>, provided the
661 * respective changesets are already present in the local changeset cache.
662 *
663 * @param ids the collection of ids. If null, the selection is cleared.
664 */
665 public void setSelectedChangesetsById(Collection<Integer> ids) {
666 if (ids == null) {
667 setSelectedChangesets(null);
668 return;
669 }
670 Set<Changeset> toSelect = new HashSet<>();
671 ChangesetCache cc = ChangesetCache.getInstance();
672 for (int id: ids) {
673 if (cc.contains(id)) {
674 toSelect.add(cc.get(id));
675 }
676 }
677 setSelectedChangesets(toSelect);
678 }
679
680 /**
681 * Selects the given component in the detail tabbed panel
682 * @param clazz the class of the component to select
683 */
684 public void setSelectedComponentInDetailPanel(Class<? extends JComponent> clazz) {
685 for (Component component : pnlChangesetDetailTabs.getComponents()) {
686 if (component.getClass().equals(clazz)) {
687 pnlChangesetDetailTabs.setSelectedComponent(component);
688 break;
689 }
690 }
691 }
692
693 /**
694 * Runs the given changeset download task.
695 * @param task The changeset download task to run
696 */
697 public void runDownloadTask(final AbstractChangesetDownloadTask task) {
698 Main.worker.submit(new PostDownloadHandler(task, task.download()));
699 Main.worker.submit(() -> {
700 if (task.isCanceled() || task.isFailed())
701 return;
702 setSelectedChangesets(task.getDownloadedData());
703 });
704 }
705}
Note: See TracBrowser for help on using the repository browser.