001package apps; 002 003import static jmri.util.gui.GuiLafPreferencesManager.MIN_FONT_SIZE; 004 005import java.awt.FlowLayout; 006import java.awt.event.ActionEvent; 007import java.awt.event.ItemEvent; 008import java.text.MessageFormat; 009import java.util.Arrays; 010import java.util.HashMap; 011import java.util.Locale; 012import javax.swing.BoxLayout; 013import javax.swing.ButtonGroup; 014import javax.swing.DefaultComboBoxModel; 015import javax.swing.JButton; 016import javax.swing.JCheckBox; 017import javax.swing.JComboBox; 018import javax.swing.JComponent; 019import javax.swing.JLabel; 020import javax.swing.JPanel; 021import javax.swing.JRadioButton; 022import javax.swing.JSpinner; 023import javax.swing.SpinnerNumberModel; 024import javax.swing.SwingUtilities; 025import javax.swing.UIManager; 026import javax.swing.event.ChangeEvent; 027import jmri.InstanceManager; 028import jmri.profile.Profile; 029import jmri.profile.ProfileManager; 030import jmri.swing.PreferencesPanel; 031import jmri.util.gui.GuiLafPreferencesManager; 032import jmri.util.swing.JComboBoxUtil; 033import org.openide.util.lookup.ServiceProvider; 034 035/** 036 * Provide GUI to configure Swing GUI LAF defaults 037 * <p> 038 * Provides GUI configuration for SWING LAF by displaying radio buttons for each 039 * LAF implementation available. This information is then persisted separately 040 * by the {@link jmri.util.gui.GuiLafPreferencesManager}. 041 * <p> 042 * Locale default language and country is also considered a GUI (and perhaps 043 * LAF) configuration item. 044 * 045 * @author Bob Jacobsen Copyright (C) 2001, 2003, 2010 046 * @since 2.9.5 (Previously in jmri package) 047 */ 048@ServiceProvider(service = PreferencesPanel.class) 049public final class GuiLafConfigPane extends JPanel implements PreferencesPanel { 050 051 public static final int MAX_TOOLTIP_TIME = 3600; 052 public static final int MIN_TOOLTIP_TIME = 1; 053 054 /** 055 * Smallest font size shown to a user ({@value}). 056 * 057 * @see GuiLafPreferencesManager#MIN_FONT_SIZE 058 */ 059 public static final int MIN_DISPLAYED_FONT_SIZE = MIN_FONT_SIZE; 060 /** 061 * Largest font size shown to a user ({@value}). 062 * 063 * @see GuiLafPreferencesManager#MAX_FONT_SIZE 064 */ 065 public static final int MAX_DISPLAYED_FONT_SIZE = 20; 066 067 private final JComboBox<String> localeBox = new JComboBox<>(new String[]{ 068 Locale.getDefault().getDisplayName(), 069 "(Please Wait)"}); 070 private final HashMap<String, Locale> locale = new HashMap<>(); 071 private final ButtonGroup LAFGroup = new ButtonGroup(); 072 public JCheckBox mouseEvent; 073 private JComboBox<Integer> fontSizeComboBox; 074 public JCheckBox graphicStateDisplay; 075 public JCheckBox tabbedOblockEditor; 076 public JCheckBox editorUseOldLocSizeDisplay; 077 public ButtonGroup fileChooserGroup= new ButtonGroup(); 078 public JCheckBox force100percentScaling; 079 080 public GuiLafConfigPane() { 081 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 082 JPanel p; 083 doLAF(p = new JPanel()); 084 add(p); 085 doFontSize(p = new JPanel()); 086 add(p); 087 doFileChooserLayoutType(p = new JPanel()); 088 add(p); 089 doClickSelection(p = new JPanel()); 090 add(p); 091 doGraphicState(p = new JPanel()); 092 add(p); 093 doTabbedOblockEditor(p = new JPanel()); 094 add(p); 095 doEditorUseOldLocSize(p = new JPanel()); 096 add(p); 097 doForce100percentScaling(p = new JPanel()); 098 add(p); 099 doMaxComboRows(p = new JPanel()); 100 add(p); 101 doToolTipDismissDelay(p = new JPanel()); 102 add(p); 103 } 104 105 void doClickSelection(JPanel panel) { 106 panel.setLayout(new FlowLayout()); 107 mouseEvent = new JCheckBox(ConfigBundle.getMessage("GUIButtonNonStandardRelease")); 108 mouseEvent.addItemListener((ItemEvent e) -> { 109 InstanceManager.getDefault(GuiLafPreferencesManager.class).setNonStandardMouseEvent(mouseEvent.isSelected()); 110 }); 111 panel.add(mouseEvent); 112 } 113 114 void doGraphicState(JPanel panel) { 115 panel.setLayout(new FlowLayout()); 116 graphicStateDisplay = new JCheckBox(ConfigBundle.getMessage("GUIGraphicTableState")); 117 graphicStateDisplay.setSelected(InstanceManager.getDefault(GuiLafPreferencesManager.class).isGraphicTableState()); 118 graphicStateDisplay.addItemListener((ItemEvent e) -> { 119 InstanceManager.getDefault(GuiLafPreferencesManager.class).setGraphicTableState(graphicStateDisplay.isSelected()); 120 }); 121 panel.add(graphicStateDisplay); 122 } 123 124 void doTabbedOblockEditor(JPanel panel) { 125 panel.setLayout(new FlowLayout()); 126 tabbedOblockEditor = new JCheckBox(ConfigBundle.getMessage("GUITabbedOblockEditor")); 127 tabbedOblockEditor.setSelected(InstanceManager.getDefault(GuiLafPreferencesManager.class).isOblockEditTabbed()); 128 tabbedOblockEditor.setToolTipText(ConfigBundle.getMessage("GUIToolTipTabbedEdit")); 129 tabbedOblockEditor.addItemListener((ItemEvent e) -> { 130 InstanceManager.getDefault(GuiLafPreferencesManager.class).setOblockEditTabbed(tabbedOblockEditor.isSelected()); 131 }); 132 panel.add(tabbedOblockEditor); 133 } 134 135 void doEditorUseOldLocSize(JPanel panel) { 136 panel.setLayout(new FlowLayout()); 137 editorUseOldLocSizeDisplay = new JCheckBox(ConfigBundle.getMessage("GUIUseOldLocSize")); 138 editorUseOldLocSizeDisplay.setSelected(InstanceManager.getDefault(GuiLafPreferencesManager.class).isEditorUseOldLocSize()); 139 editorUseOldLocSizeDisplay.addItemListener((ItemEvent e) -> { 140 InstanceManager.getDefault(GuiLafPreferencesManager.class).setEditorUseOldLocSize(editorUseOldLocSizeDisplay.isSelected()); 141 }); 142 panel.add(editorUseOldLocSizeDisplay); 143 } 144 145 void doFileChooserLayoutType(JPanel panel) { 146 panel.setLayout(new FlowLayout()); 147 JLabel fileChooserLabel = new JLabel(ConfigBundle.getMessage("GUIJChooserUseOption")); 148 panel.add(fileChooserLabel); 149 // make the radio buttons 150 JRadioButton jButDefault = new JRadioButton(ConfigBundle.getMessage("GUIJChooserUseDefault")); 151 panel.add(jButDefault); 152 fileChooserGroup.add(jButDefault); 153 jButDefault.addActionListener((ActionEvent e) -> { 154 if (((JRadioButton)e.getSource()).isSelected() ) { 155 InstanceManager.getDefault(GuiLafPreferencesManager.class).setJFileChooserFormat(0); 156 } 157 }); 158 JRadioButton jButList = new JRadioButton(ConfigBundle.getMessage("GUIJChooserUseList")); 159 panel.add(jButList); 160 fileChooserGroup.add(jButList); 161 jButList.addActionListener((ActionEvent e) -> { 162 if (((JRadioButton)e.getSource()).isSelected() ) { 163 InstanceManager.getDefault(GuiLafPreferencesManager.class).setJFileChooserFormat(1); 164 } 165 }); 166 JRadioButton jButDetail = new JRadioButton(ConfigBundle.getMessage("GUIJChooserUseDetail")); 167 panel.add(jButDetail); 168 fileChooserGroup.add(jButDetail); 169 jButDetail.addActionListener((ActionEvent e) -> { 170 if (((JRadioButton)e.getSource()).isSelected() ) { 171 InstanceManager.getDefault(GuiLafPreferencesManager.class).setJFileChooserFormat(2); 172 } 173 }); 174 switch (InstanceManager.getDefault(GuiLafPreferencesManager.class).getJFileChooserFormat()) { 175 case 0: 176 jButDefault.setSelected(true); 177 break; 178 case 1: 179 jButList.setSelected(true); 180 break; 181 case 2: 182 jButDetail.setSelected(true); 183 break; 184 default: 185 jButDefault.setSelected(true); 186 } 187 } 188 189 void doForce100percentScaling(JPanel panel) { 190 jmri.util.EarlyInitializationPreferences eip = 191 jmri.util.EarlyInitializationPreferences.getInstance(); 192 193 panel.setLayout(new FlowLayout()); 194 force100percentScaling = new JCheckBox(ConfigBundle.getMessage("GUIForce100percentScaling")); 195 force100percentScaling.setSelected(eip.getGUIForce100percentScaling()); 196 force100percentScaling.addItemListener((ItemEvent e) -> { 197 eip.setGUIForce100percentScaling(force100percentScaling.isSelected()); 198 }); 199 panel.add(force100percentScaling); 200 } 201 202 void doLAF(JPanel panel) { 203 // find L&F definitions 204 panel.setLayout(new FlowLayout()); 205 UIManager.LookAndFeelInfo[] plafs = UIManager.getInstalledLookAndFeels(); 206 HashMap<String, String> installedLAFs = new HashMap<>(plafs.length); 207 for (UIManager.LookAndFeelInfo plaf : plafs) { 208 installedLAFs.put(plaf.getName(), plaf.getClassName()); 209 } 210 // make the radio buttons 211 for (java.util.Map.Entry<String, String> entry : installedLAFs.entrySet()) { 212 String name = entry.getKey(); 213 JRadioButton jmi = new JRadioButton(name); 214 panel.add(jmi); 215 LAFGroup.add(jmi); 216 jmi.setActionCommand(name); 217 jmi.addActionListener((ActionEvent e) -> { 218 InstanceManager.getDefault(GuiLafPreferencesManager.class).setLookAndFeel(installedLAFs.get(name)); 219 }); 220 if ( entry.getValue().equals(UIManager.getLookAndFeel().getClass().getName())) { 221 jmi.setSelected(true); 222 } 223 } 224 } 225 226 /** 227 * Create and return a JPanel for configuring default local. 228 * <p> 229 * Most of the action is handled in a separate thread, which replaces the 230 * contents of a JComboBox when the list of Locales is available. 231 * 232 * @return the panel 233 */ 234 public JPanel doLocale() { 235 JPanel panel = new JPanel(); 236 // add JComboBoxen for language and country 237 panel.setLayout(new FlowLayout()); 238 panel.add(localeBox); 239 JComboBoxUtil.setupComboBoxMaxRows(localeBox); 240 241 // create object to find locales in new Thread 242 Runnable r = () -> { 243 Locale[] locales = Locale.getAvailableLocales(); 244 String[] localeNames = new String[locales.length]; 245 for (int i = 0; i < locales.length; i++) { 246 locale.put(locales[i].getDisplayName(), locales[i]); 247 localeNames[i] = locales[i].getDisplayName(); 248 } 249 Arrays.sort(localeNames); 250 Runnable update = () -> { 251 localeBox.setModel(new DefaultComboBoxModel<>(localeNames)); 252 //localeBox.setModel(new javax.swing.DefaultComboBoxModel(locale.keySet().toArray())); 253 localeBox.setSelectedItem(Locale.getDefault().getDisplayName()); 254 localeBox.addActionListener((ActionEvent e) -> { 255 InstanceManager.getDefault(GuiLafPreferencesManager.class).setLocale(locale.getOrDefault(localeBox.getSelectedItem(), Locale.getDefault())); 256 }); 257 }; 258 SwingUtilities.invokeLater(update); 259 }; 260 new Thread(r).start(); 261 return panel; 262 } 263 264 public void setLocale(String loc) { 265 localeBox.setSelectedItem(loc); 266 } 267 268 /** 269 * Get the currently configured Locale or Locale.getDefault if no 270 * configuration has been done. 271 * 272 * @return the in-use Locale 273 */ 274 @Override 275 public Locale getLocale() { 276 Locale desired = locale.get(localeBox.getSelectedItem().toString()); 277 return (desired != null) ? desired : Locale.getDefault(); 278 } 279 280 public void doFontSize(JPanel panel) { 281 GuiLafPreferencesManager manager = InstanceManager.getDefault(GuiLafPreferencesManager.class); 282 Integer[] sizes = new Integer[MAX_DISPLAYED_FONT_SIZE - MIN_DISPLAYED_FONT_SIZE + 1]; 283 for (int i = 0; i < sizes.length; i++) { 284 sizes[i] = i + MIN_DISPLAYED_FONT_SIZE; 285 } 286 fontSizeComboBox = new JComboBox<>(sizes); 287 fontSizeComboBox.setEditable(true); // allow users to set font sizes not listed 288 JLabel fontSizeLabel = new JLabel(ConfigBundle.getMessage("ConsoleFontSize")); 289 fontSizeComboBox.setSelectedItem(manager.getFontSize()); 290 JLabel fontSizeUoM = new JLabel(ConfigBundle.getMessage("ConsoleFontSizeUoM")); 291 JButton resetButton = new JButton(ConfigBundle.getMessage("ResetDefault")); 292 resetButton.setToolTipText(ConfigBundle.getMessage("GUIFontSizeReset")); 293 294 panel.add(fontSizeLabel); 295 panel.add(fontSizeComboBox); 296 panel.add(fontSizeUoM); 297 panel.add(resetButton); 298 299 JComboBoxUtil.setupComboBoxMaxRows(fontSizeComboBox); 300 301 fontSizeComboBox.addActionListener((ActionEvent e) -> { 302 manager.setFontSize((int) fontSizeComboBox.getSelectedItem()); 303 }); 304 resetButton.addActionListener((ActionEvent e) -> { 305 if ((int) fontSizeComboBox.getSelectedItem() != manager.getDefaultFontSize()) { 306 fontSizeComboBox.setSelectedItem(manager.getDefaultFontSize()); 307 } 308 }); 309 } 310 311 private JSpinner maxComboRowsSpinner; 312 313 public void doMaxComboRows(JPanel panel) { 314 GuiLafPreferencesManager manager = InstanceManager.getDefault(GuiLafPreferencesManager.class); 315 JLabel maxComboRowsLabel = new JLabel(ConfigBundle.getMessage("GUIMaxComboRows")); 316 maxComboRowsSpinner = new JSpinner(new SpinnerNumberModel(manager.getMaxComboRows(), 0, 999, 1)); 317 this.maxComboRowsSpinner.addChangeListener((ChangeEvent e) -> { 318 manager.setMaxComboRows((int) maxComboRowsSpinner.getValue()); 319 }); 320 this.maxComboRowsSpinner.setToolTipText(ConfigBundle.getMessage("GUIMaxComboRowsToolTip")); 321 maxComboRowsLabel.setToolTipText(this.maxComboRowsSpinner.getToolTipText()); 322 panel.add(maxComboRowsLabel); 323 panel.add(maxComboRowsSpinner); 324 } 325 326 private JSpinner toolTipDismissDelaySpinner; 327 328 public void doToolTipDismissDelay(JPanel panel) { 329 GuiLafPreferencesManager manager = InstanceManager.getDefault(GuiLafPreferencesManager.class); 330 JLabel toolTipDismissDelayLabel = new JLabel(ConfigBundle.getMessage("GUIToolTipDismissDelay")); 331 toolTipDismissDelaySpinner = new JSpinner(new SpinnerNumberModel(manager.getToolTipDismissDelay() / 1000, MIN_TOOLTIP_TIME, MAX_TOOLTIP_TIME, 1)); 332 this.toolTipDismissDelaySpinner.addChangeListener((ChangeEvent e) -> { 333 manager.setToolTipDismissDelay((int) toolTipDismissDelaySpinner.getValue() * 1000); // convert to milliseconds from seconds 334 }); 335 this.toolTipDismissDelaySpinner.setToolTipText(MessageFormat.format(ConfigBundle.getMessage("GUIToolTipDismissDelayToolTip"), MIN_TOOLTIP_TIME, MAX_TOOLTIP_TIME)); 336 toolTipDismissDelayLabel.setToolTipText(this.toolTipDismissDelaySpinner.getToolTipText()); 337 JLabel toolTipDismissDelayUoM = new JLabel(ConfigBundle.getMessage("GUIToolTipDismissDelayUoM")); 338 toolTipDismissDelayUoM.setToolTipText(this.toolTipDismissDelaySpinner.getToolTipText()); 339 panel.add(toolTipDismissDelayLabel); 340 panel.add(toolTipDismissDelaySpinner); 341 panel.add(toolTipDismissDelayUoM); 342 } 343 344 public String getClassName() { 345 return LAFGroup.getSelection().getActionCommand(); 346 347 } 348 349 @Override 350 public String getPreferencesItem() { 351 return "DISPLAY"; // NOI18N 352 } 353 354 @Override 355 public String getPreferencesItemText() { 356 return ConfigBundle.getMessage("MenuDisplay"); // NOI18N 357 } 358 359 @Override 360 public String getTabbedPreferencesTitle() { 361 return ConfigBundle.getMessage("TabbedLayoutGUI"); // NOI18N 362 } 363 364 @Override 365 public String getLabelKey() { 366 return ConfigBundle.getMessage("LabelTabbedLayoutGUI"); // NOI18N 367 } 368 369 @Override 370 public JComponent getPreferencesComponent() { 371 return this; 372 } 373 374 @Override 375 public boolean isPersistant() { 376 return true; 377 } 378 379 @Override 380 public String getPreferencesTooltip() { 381 return null; 382 } 383 384 @Override 385 public void savePreferences() { 386 Profile profile = ProfileManager.getDefault().getActiveProfile(); 387 if (profile != null) { 388 InstanceManager.getDefault(GuiLafPreferencesManager.class).savePreferences(profile); 389 } 390 } 391 392 @Override 393 public boolean isDirty() { 394 return InstanceManager.getDefault(GuiLafPreferencesManager.class).isDirty(); 395 } 396 397 @Override 398 public boolean isRestartRequired() { 399 return InstanceManager.getDefault(GuiLafPreferencesManager.class).isRestartRequired(); 400 } 401 402 @Override 403 public boolean isPreferencesValid() { 404 return true; // no validity checking performed 405 } 406}