001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.preferences; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.Component; 007import java.awt.Container; 008import java.awt.Font; 009import java.awt.GridBagLayout; 010import java.awt.event.MouseWheelEvent; 011import java.awt.event.MouseWheelListener; 012import java.util.ArrayList; 013import java.util.Collection; 014import java.util.HashSet; 015import java.util.Iterator; 016import java.util.LinkedList; 017import java.util.List; 018import java.util.Set; 019 020import javax.swing.BorderFactory; 021import javax.swing.Icon; 022import javax.swing.ImageIcon; 023import javax.swing.JLabel; 024import javax.swing.JOptionPane; 025import javax.swing.JPanel; 026import javax.swing.JScrollPane; 027import javax.swing.JTabbedPane; 028import javax.swing.SwingUtilities; 029import javax.swing.event.ChangeEvent; 030import javax.swing.event.ChangeListener; 031 032import org.openstreetmap.josm.Main; 033import org.openstreetmap.josm.actions.ExpertToggleAction; 034import org.openstreetmap.josm.actions.ExpertToggleAction.ExpertModeChangeListener; 035import org.openstreetmap.josm.actions.RestartAction; 036import org.openstreetmap.josm.gui.HelpAwareOptionPane; 037import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec; 038import org.openstreetmap.josm.gui.MainApplication; 039import org.openstreetmap.josm.gui.preferences.advanced.AdvancedPreference; 040import org.openstreetmap.josm.gui.preferences.audio.AudioPreference; 041import org.openstreetmap.josm.gui.preferences.display.ColorPreference; 042import org.openstreetmap.josm.gui.preferences.display.DisplayPreference; 043import org.openstreetmap.josm.gui.preferences.display.DrawingPreference; 044import org.openstreetmap.josm.gui.preferences.display.LafPreference; 045import org.openstreetmap.josm.gui.preferences.display.LanguagePreference; 046import org.openstreetmap.josm.gui.preferences.imagery.ImageryPreference; 047import org.openstreetmap.josm.gui.preferences.map.BackupPreference; 048import org.openstreetmap.josm.gui.preferences.map.MapPaintPreference; 049import org.openstreetmap.josm.gui.preferences.map.MapPreference; 050import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference; 051import org.openstreetmap.josm.gui.preferences.plugin.PluginPreference; 052import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference; 053import org.openstreetmap.josm.gui.preferences.remotecontrol.RemoteControlPreference; 054import org.openstreetmap.josm.gui.preferences.server.AuthenticationPreference; 055import org.openstreetmap.josm.gui.preferences.server.OverpassServerPreference; 056import org.openstreetmap.josm.gui.preferences.server.ProxyPreference; 057import org.openstreetmap.josm.gui.preferences.server.ServerAccessPreference; 058import org.openstreetmap.josm.gui.preferences.shortcut.ShortcutPreference; 059import org.openstreetmap.josm.gui.preferences.validator.ValidatorPreference; 060import org.openstreetmap.josm.gui.preferences.validator.ValidatorTagCheckerRulesPreference; 061import org.openstreetmap.josm.gui.preferences.validator.ValidatorTestsPreference; 062import org.openstreetmap.josm.plugins.PluginDownloadTask; 063import org.openstreetmap.josm.plugins.PluginHandler; 064import org.openstreetmap.josm.plugins.PluginInformation; 065import org.openstreetmap.josm.tools.CheckParameterUtil; 066import org.openstreetmap.josm.tools.GBC; 067import org.openstreetmap.josm.tools.ImageProvider; 068import org.openstreetmap.josm.tools.Logging; 069import org.openstreetmap.josm.tools.bugreport.BugReportExceptionHandler; 070 071/** 072 * The preference settings. 073 * 074 * @author imi 075 */ 076public final class PreferenceTabbedPane extends JTabbedPane implements MouseWheelListener, ExpertModeChangeListener, ChangeListener { 077 078 private final class PluginDownloadAfterTask implements Runnable { 079 private final PluginPreference preference; 080 private final PluginDownloadTask task; 081 private final Set<PluginInformation> toDownload; 082 083 private PluginDownloadAfterTask(PluginPreference preference, PluginDownloadTask task, 084 Set<PluginInformation> toDownload) { 085 this.preference = preference; 086 this.task = task; 087 this.toDownload = toDownload; 088 } 089 090 @Override 091 public void run() { 092 boolean requiresRestart = false; 093 094 for (PreferenceSetting setting : settingsInitialized) { 095 if (setting.ok()) { 096 requiresRestart = true; 097 } 098 } 099 100 // build the messages. We only display one message, including the status information from the plugin download task 101 // and - if necessary - a hint to restart JOSM 102 // 103 StringBuilder sb = new StringBuilder(); 104 sb.append("<html>"); 105 if (task != null && !task.isCanceled()) { 106 PluginHandler.refreshLocalUpdatedPluginInfo(task.getDownloadedPlugins()); 107 sb.append(PluginPreference.buildDownloadSummary(task)); 108 } 109 if (requiresRestart) { 110 sb.append(tr("You have to restart JOSM for some settings to take effect.")); 111 sb.append("<br/><br/>"); 112 sb.append(tr("Would you like to restart now?")); 113 } 114 sb.append("</html>"); 115 116 // display the message, if necessary 117 // 118 if (requiresRestart) { 119 final ButtonSpec[] options = RestartAction.getButtonSpecs(); 120 if (0 == HelpAwareOptionPane.showOptionDialog( 121 Main.parent, 122 sb.toString(), 123 tr("Restart"), 124 JOptionPane.INFORMATION_MESSAGE, 125 null, /* no special icon */ 126 options, 127 options[0], 128 null /* no special help */ 129 )) { 130 MainApplication.getMenu().restart.actionPerformed(null); 131 } 132 } else if (task != null && !task.isCanceled()) { 133 JOptionPane.showMessageDialog( 134 Main.parent, 135 sb.toString(), 136 tr("Warning"), 137 JOptionPane.WARNING_MESSAGE 138 ); 139 } 140 141 // load the plugins that can be loaded at runtime 142 List<PluginInformation> newPlugins = preference.getNewlyActivatedPlugins(); 143 if (newPlugins != null) { 144 Collection<PluginInformation> downloadedPlugins = null; 145 if (task != null && !task.isCanceled()) { 146 downloadedPlugins = task.getDownloadedPlugins(); 147 } 148 List<PluginInformation> toLoad = new ArrayList<>(); 149 for (PluginInformation pi : newPlugins) { 150 if (toDownload.contains(pi) && downloadedPlugins != null && !downloadedPlugins.contains(pi)) { 151 continue; // failed download 152 } 153 if (pi.canloadatruntime) { 154 toLoad.add(pi); 155 } 156 } 157 // check if plugin dependences can also be loaded 158 Collection<PluginInformation> allPlugins = new HashSet<>(toLoad); 159 allPlugins.addAll(PluginHandler.getPlugins()); 160 boolean removed; 161 do { 162 removed = false; 163 Iterator<PluginInformation> it = toLoad.iterator(); 164 while (it.hasNext()) { 165 if (!PluginHandler.checkRequiredPluginsPreconditions(null, allPlugins, it.next(), requiresRestart)) { 166 it.remove(); 167 removed = true; 168 } 169 } 170 } while (removed); 171 172 if (!toLoad.isEmpty()) { 173 PluginHandler.loadPlugins(PreferenceTabbedPane.this, toLoad, null); 174 } 175 } 176 177 Main.parent.repaint(); 178 } 179 } 180 181 /** 182 * Allows PreferenceSettings to do validation of entered values when ok was pressed. 183 * If data is invalid then event can return false to cancel closing of preferences dialog. 184 * @since 10600 (functional interface) 185 */ 186 @FunctionalInterface 187 public interface ValidationListener { 188 /** 189 * 190 * @return True if preferences can be saved 191 */ 192 boolean validatePreferences(); 193 } 194 195 private interface PreferenceTab { 196 TabPreferenceSetting getTabPreferenceSetting(); 197 198 Component getComponent(); 199 } 200 201 public static final class PreferencePanel extends JPanel implements PreferenceTab { 202 private final transient TabPreferenceSetting preferenceSetting; 203 204 private PreferencePanel(TabPreferenceSetting preferenceSetting) { 205 super(new GridBagLayout()); 206 CheckParameterUtil.ensureParameterNotNull(preferenceSetting); 207 this.preferenceSetting = preferenceSetting; 208 buildPanel(); 209 } 210 211 private void buildPanel() { 212 setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 213 add(new JLabel(preferenceSetting.getTitle()), GBC.eol().insets(0, 5, 0, 10).anchor(GBC.NORTHWEST)); 214 215 JLabel descLabel = new JLabel("<html>"+preferenceSetting.getDescription()+"</html>"); 216 descLabel.setFont(descLabel.getFont().deriveFont(Font.ITALIC)); 217 add(descLabel, GBC.eol().insets(5, 0, 5, 20).fill(GBC.HORIZONTAL)); 218 } 219 220 @Override 221 public TabPreferenceSetting getTabPreferenceSetting() { 222 return preferenceSetting; 223 } 224 225 @Override 226 public Component getComponent() { 227 return this; 228 } 229 } 230 231 public static final class PreferenceScrollPane extends JScrollPane implements PreferenceTab { 232 private final transient TabPreferenceSetting preferenceSetting; 233 234 private PreferenceScrollPane(Component view, TabPreferenceSetting preferenceSetting) { 235 super(view); 236 this.preferenceSetting = preferenceSetting; 237 } 238 239 private PreferenceScrollPane(PreferencePanel preferencePanel) { 240 this(preferencePanel.getComponent(), preferencePanel.getTabPreferenceSetting()); 241 } 242 243 @Override 244 public TabPreferenceSetting getTabPreferenceSetting() { 245 return preferenceSetting; 246 } 247 248 @Override 249 public Component getComponent() { 250 return this; 251 } 252 } 253 254 // all created tabs 255 private final transient List<PreferenceTab> tabs = new ArrayList<>(); 256 private static final Collection<PreferenceSettingFactory> SETTINGS_FACTORIES = new LinkedList<>(); 257 private static final PreferenceSettingFactory ADVANCED_PREFERENCE_FACTORY = new AdvancedPreference.Factory(); 258 private final transient List<PreferenceSetting> settings = new ArrayList<>(); 259 260 // distinct list of tabs that have been initialized (we do not initialize tabs until they are displayed to speed up dialog startup) 261 private final transient List<PreferenceSetting> settingsInitialized = new ArrayList<>(); 262 263 final transient List<ValidationListener> validationListeners = new ArrayList<>(); 264 265 /** 266 * Add validation listener to currently open preferences dialog. Calling to removeValidationListener is not necessary, all listeners will 267 * be automatically removed when dialog is closed 268 * @param validationListener validation listener to add 269 */ 270 public void addValidationListener(ValidationListener validationListener) { 271 validationListeners.add(validationListener); 272 } 273 274 /** 275 * Construct a PreferencePanel for the preference settings. Layout is GridBagLayout 276 * and a centered title label and the description are added. 277 * @param caller Preference settings, that display a top level tab 278 * @return The created panel ready to add other controls. 279 */ 280 public PreferencePanel createPreferenceTab(TabPreferenceSetting caller) { 281 return createPreferenceTab(caller, false); 282 } 283 284 /** 285 * Construct a PreferencePanel for the preference settings. Layout is GridBagLayout 286 * and a centered title label and the description are added. 287 * @param caller Preference settings, that display a top level tab 288 * @param inScrollPane if <code>true</code> the added tab will show scroll bars 289 * if the panel content is larger than the available space 290 * @return The created panel ready to add other controls. 291 */ 292 public PreferencePanel createPreferenceTab(TabPreferenceSetting caller, boolean inScrollPane) { 293 CheckParameterUtil.ensureParameterNotNull(caller, "caller"); 294 PreferencePanel p = new PreferencePanel(caller); 295 296 PreferenceTab tab = p; 297 if (inScrollPane) { 298 PreferenceScrollPane sp = new PreferenceScrollPane(p); 299 tab = sp; 300 } 301 tabs.add(tab); 302 return p; 303 } 304 305 @FunctionalInterface 306 private interface TabIdentifier { 307 boolean identify(TabPreferenceSetting tps, Object param); 308 } 309 310 private void selectTabBy(TabIdentifier method, Object param) { 311 for (int i = 0; i < getTabCount(); i++) { 312 Component c = getComponentAt(i); 313 if (c instanceof PreferenceTab) { 314 PreferenceTab tab = (PreferenceTab) c; 315 if (method.identify(tab.getTabPreferenceSetting(), param)) { 316 setSelectedIndex(i); 317 return; 318 } 319 } 320 } 321 } 322 323 public void selectTabByName(String name) { 324 selectTabBy((tps, name1) -> name1 != null && tps != null && tps.getIconName() != null && name1.equals(tps.getIconName()), name); 325 } 326 327 public void selectTabByPref(Class<? extends TabPreferenceSetting> clazz) { 328 selectTabBy((tps, clazz1) -> tps.getClass().isAssignableFrom((Class<?>) clazz1), clazz); 329 } 330 331 public boolean selectSubTabByPref(Class<? extends SubPreferenceSetting> clazz) { 332 for (PreferenceSetting setting : settings) { 333 if (clazz.isInstance(setting)) { 334 final SubPreferenceSetting sub = (SubPreferenceSetting) setting; 335 final TabPreferenceSetting tab = sub.getTabPreferenceSetting(this); 336 selectTabBy((tps, unused) -> tps.equals(tab), null); 337 return tab.selectSubTab(sub); 338 } 339 } 340 return false; 341 } 342 343 /** 344 * Returns the {@code DisplayPreference} object. 345 * @return the {@code DisplayPreference} object. 346 */ 347 public DisplayPreference getDisplayPreference() { 348 return getSetting(DisplayPreference.class); 349 } 350 351 /** 352 * Returns the {@code MapPreference} object. 353 * @return the {@code MapPreference} object. 354 */ 355 public MapPreference getMapPreference() { 356 return getSetting(MapPreference.class); 357 } 358 359 /** 360 * Returns the {@code PluginPreference} object. 361 * @return the {@code PluginPreference} object. 362 */ 363 public PluginPreference getPluginPreference() { 364 return getSetting(PluginPreference.class); 365 } 366 367 /** 368 * Returns the {@code ImageryPreference} object. 369 * @return the {@code ImageryPreference} object. 370 */ 371 public ImageryPreference getImageryPreference() { 372 return getSetting(ImageryPreference.class); 373 } 374 375 /** 376 * Returns the {@code ShortcutPreference} object. 377 * @return the {@code ShortcutPreference} object. 378 */ 379 public ShortcutPreference getShortcutPreference() { 380 return getSetting(ShortcutPreference.class); 381 } 382 383 /** 384 * Returns the {@code ServerAccessPreference} object. 385 * @return the {@code ServerAccessPreference} object. 386 * @since 6523 387 */ 388 public ServerAccessPreference getServerPreference() { 389 return getSetting(ServerAccessPreference.class); 390 } 391 392 /** 393 * Returns the {@code ValidatorPreference} object. 394 * @return the {@code ValidatorPreference} object. 395 * @since 6665 396 */ 397 public ValidatorPreference getValidatorPreference() { 398 return getSetting(ValidatorPreference.class); 399 } 400 401 /** 402 * Saves preferences. 403 */ 404 public void savePreferences() { 405 // create a task for downloading plugins if the user has activated, yet not downloaded, new plugins 406 final PluginPreference preference = getPluginPreference(); 407 if (preference != null) { 408 final Set<PluginInformation> toDownload = preference.getPluginsScheduledForUpdateOrDownload(); 409 final PluginDownloadTask task; 410 if (toDownload != null && !toDownload.isEmpty()) { 411 task = new PluginDownloadTask(this, toDownload, tr("Download plugins")); 412 } else { 413 task = null; 414 } 415 416 // this is the task which will run *after* the plugins are downloaded 417 final Runnable continuation = new PluginDownloadAfterTask(preference, task, toDownload); 418 419 if (task != null) { 420 // if we have to launch a plugin download task we do it asynchronously, followed 421 // by the remaining "save preferences" activites run on the Swing EDT. 422 MainApplication.worker.submit(task); 423 MainApplication.worker.submit(() -> SwingUtilities.invokeLater(continuation)); 424 } else { 425 // no need for asynchronous activities. Simply run the remaining "save preference" 426 // activities on this thread (we are already on the Swing EDT 427 continuation.run(); 428 } 429 } 430 } 431 432 /** 433 * If the dialog is closed with Ok, the preferences will be stored to the preferences- 434 * file, otherwise no change of the file happens. 435 */ 436 public PreferenceTabbedPane() { 437 super(JTabbedPane.LEFT, JTabbedPane.SCROLL_TAB_LAYOUT); 438 super.addMouseWheelListener(this); 439 super.getModel().addChangeListener(this); 440 ExpertToggleAction.addExpertModeChangeListener(this); 441 } 442 443 public void buildGui() { 444 Collection<PreferenceSettingFactory> factories = new ArrayList<>(SETTINGS_FACTORIES); 445 factories.addAll(PluginHandler.getPreferenceSetting()); 446 factories.add(ADVANCED_PREFERENCE_FACTORY); 447 448 for (PreferenceSettingFactory factory : factories) { 449 if (factory != null) { 450 PreferenceSetting setting = factory.createPreferenceSetting(); 451 if (setting != null) { 452 settings.add(setting); 453 } 454 } 455 } 456 addGUITabs(false); 457 } 458 459 private void addGUITabsForSetting(Icon icon, TabPreferenceSetting tps) { 460 for (PreferenceTab tab : tabs) { 461 if (tab.getTabPreferenceSetting().equals(tps)) { 462 insertGUITabsForSetting(icon, tps, getTabCount()); 463 } 464 } 465 } 466 467 private int insertGUITabsForSetting(Icon icon, TabPreferenceSetting tps, int index) { 468 int position = index; 469 for (PreferenceTab tab : tabs) { 470 if (tab.getTabPreferenceSetting().equals(tps)) { 471 insertTab(null, icon, tab.getComponent(), tps.getTooltip(), position++); 472 } 473 } 474 return position - 1; 475 } 476 477 private void addGUITabs(boolean clear) { 478 boolean expert = ExpertToggleAction.isExpert(); 479 Component sel = getSelectedComponent(); 480 if (clear) { 481 removeAll(); 482 } 483 // Inspect each tab setting 484 for (PreferenceSetting setting : settings) { 485 if (setting instanceof TabPreferenceSetting) { 486 TabPreferenceSetting tps = (TabPreferenceSetting) setting; 487 if (expert || !tps.isExpert()) { 488 // Get icon 489 String iconName = tps.getIconName(); 490 ImageIcon icon = null; 491 492 if (iconName != null && !iconName.isEmpty()) { 493 icon = ImageProvider.get("preferences", iconName, ImageProvider.ImageSizes.SETTINGS_TAB); 494 } 495 if (settingsInitialized.contains(tps)) { 496 // If it has been initialized, add corresponding tab(s) 497 addGUITabsForSetting(icon, tps); 498 } else { 499 // If it has not been initialized, create an empty tab with only icon and tooltip 500 addTab(null, icon, new PreferencePanel(tps), tps.getTooltip()); 501 } 502 } 503 } else if (!(setting instanceof SubPreferenceSetting)) { 504 Logging.warn("Ignoring preferences "+setting); 505 } 506 } 507 if (sel != null) { 508 int index = indexOfComponent(sel); 509 if (index > -1) { 510 setSelectedIndex(index); 511 } 512 } 513 } 514 515 @Override 516 public void expertChanged(boolean isExpert) { 517 addGUITabs(true); 518 } 519 520 public List<PreferenceSetting> getSettings() { 521 return settings; 522 } 523 524 @SuppressWarnings("unchecked") 525 public <T> T getSetting(Class<? extends T> clazz) { 526 for (PreferenceSetting setting:settings) { 527 if (clazz.isAssignableFrom(setting.getClass())) 528 return (T) setting; 529 } 530 return null; 531 } 532 533 static { 534 // order is important! 535 SETTINGS_FACTORIES.add(new DisplayPreference.Factory()); 536 SETTINGS_FACTORIES.add(new DrawingPreference.Factory()); 537 SETTINGS_FACTORIES.add(new ColorPreference.Factory()); 538 SETTINGS_FACTORIES.add(new LafPreference.Factory()); 539 SETTINGS_FACTORIES.add(new LanguagePreference.Factory()); 540 SETTINGS_FACTORIES.add(new ServerAccessPreference.Factory()); 541 SETTINGS_FACTORIES.add(new AuthenticationPreference.Factory()); 542 SETTINGS_FACTORIES.add(new ProxyPreference.Factory()); 543 SETTINGS_FACTORIES.add(new OverpassServerPreference.Factory()); 544 SETTINGS_FACTORIES.add(new MapPreference.Factory()); 545 SETTINGS_FACTORIES.add(new ProjectionPreference.Factory()); 546 SETTINGS_FACTORIES.add(new MapPaintPreference.Factory()); 547 SETTINGS_FACTORIES.add(new TaggingPresetPreference.Factory()); 548 SETTINGS_FACTORIES.add(new BackupPreference.Factory()); 549 SETTINGS_FACTORIES.add(new PluginPreference.Factory()); 550 SETTINGS_FACTORIES.add(MainApplication.getToolbar()); 551 SETTINGS_FACTORIES.add(new AudioPreference.Factory()); 552 SETTINGS_FACTORIES.add(new ShortcutPreference.Factory()); 553 SETTINGS_FACTORIES.add(new ValidatorPreference.Factory()); 554 SETTINGS_FACTORIES.add(new ValidatorTestsPreference.Factory()); 555 SETTINGS_FACTORIES.add(new ValidatorTagCheckerRulesPreference.Factory()); 556 SETTINGS_FACTORIES.add(new RemoteControlPreference.Factory()); 557 SETTINGS_FACTORIES.add(new ImageryPreference.Factory()); 558 } 559 560 /** 561 * This mouse wheel listener reacts when a scroll is carried out over the 562 * tab strip and scrolls one tab/down or up, selecting it immediately. 563 */ 564 @Override 565 public void mouseWheelMoved(MouseWheelEvent wev) { 566 // Ensure the cursor is over the tab strip 567 if (super.indexAtLocation(wev.getPoint().x, wev.getPoint().y) < 0) 568 return; 569 570 // Get currently selected tab 571 int newTab = super.getSelectedIndex() + wev.getWheelRotation(); 572 573 // Ensure the new tab index is sound 574 newTab = newTab < 0 ? 0 : newTab; 575 newTab = newTab >= super.getTabCount() ? super.getTabCount() - 1 : newTab; 576 577 // select new tab 578 super.setSelectedIndex(newTab); 579 } 580 581 @Override 582 public void stateChanged(ChangeEvent e) { 583 int index = getSelectedIndex(); 584 Component sel = getSelectedComponent(); 585 if (index > -1 && sel instanceof PreferenceTab) { 586 PreferenceTab tab = (PreferenceTab) sel; 587 TabPreferenceSetting preferenceSettings = tab.getTabPreferenceSetting(); 588 if (!settingsInitialized.contains(preferenceSettings)) { 589 try { 590 getModel().removeChangeListener(this); 591 preferenceSettings.addGui(this); 592 // Add GUI for sub preferences 593 for (PreferenceSetting setting : settings) { 594 if (setting instanceof SubPreferenceSetting) { 595 addSubPreferenceSetting(preferenceSettings, (SubPreferenceSetting) setting); 596 } 597 } 598 Icon icon = getIconAt(index); 599 remove(index); 600 if (index <= insertGUITabsForSetting(icon, preferenceSettings, index)) { 601 setSelectedIndex(index); 602 } 603 } catch (SecurityException ex) { 604 Logging.error(ex); 605 } catch (RuntimeException ex) { // NOPMD 606 // allow to change most settings even if e.g. a plugin fails 607 BugReportExceptionHandler.handleException(ex); 608 } finally { 609 settingsInitialized.add(preferenceSettings); 610 getModel().addChangeListener(this); 611 } 612 } 613 Container ancestor = getTopLevelAncestor(); 614 if (ancestor instanceof PreferenceDialog) { 615 ((PreferenceDialog) ancestor).setHelpContext(preferenceSettings.getHelpContext()); 616 } 617 } 618 } 619 620 private void addSubPreferenceSetting(TabPreferenceSetting preferenceSettings, SubPreferenceSetting sps) { 621 if (sps.getTabPreferenceSetting(this) == preferenceSettings) { 622 try { 623 sps.addGui(this); 624 } catch (SecurityException ex) { 625 Logging.error(ex); 626 } catch (RuntimeException ex) { // NOPMD 627 BugReportExceptionHandler.handleException(ex); 628 } finally { 629 settingsInitialized.add(sps); 630 } 631 } 632 } 633}