/* * Project Sc2gears * * Copyright (c) 2010 Andras Belicza <[email protected]> * * This software is the property of Andras Belicza. * Copying, modifying, distributing, refactoring without the authors permission * is prohibited and protected by Law. */ package hu.belicza.andras.sc2gears.ui.dialogs; import hu.belicza.andras.sc2gears.Consts; import hu.belicza.andras.sc2gears.Sc2gears; import hu.belicza.andras.sc2gears.language.Language; import hu.belicza.andras.sc2gears.services.MousePrintRecorder; import hu.belicza.andras.sc2gears.services.MousePrintRecorder.DataCompression; import hu.belicza.andras.sc2gears.services.MousePrintRecorder.WhatToSave; import hu.belicza.andras.sc2gears.services.ReplayAutoSaver; import hu.belicza.andras.sc2gears.services.ReplayAutoSaver.NewFileDetectionMethod; import hu.belicza.andras.sc2gears.services.Sc2RegMonitor; import hu.belicza.andras.sc2gears.settings.Settings; import hu.belicza.andras.sc2gears.settings.Settings.PredefinedList; import hu.belicza.andras.sc2gears.sound.Sounds; import hu.belicza.andras.sc2gears.ui.GuiUtils; import hu.belicza.andras.sc2gears.ui.MainFrame; import hu.belicza.andras.sc2gears.ui.components.BaseLabelListCellRenderer; import hu.belicza.andras.sc2gears.ui.components.CustomComboBoxModel; import hu.belicza.andras.sc2gears.ui.components.StatusLabel; import hu.belicza.andras.sc2gears.ui.dialogs.ProxyConfigDialog.ProxyConfig; import hu.belicza.andras.sc2gears.ui.dialogs.ShareReplaysDialog.ReplayUploadSite; import hu.belicza.andras.sc2gears.ui.icons.Icons; import hu.belicza.andras.sc2gears.ui.moduls.replayanal.ReplayAnalyzer.ShowProfileInfo; import hu.belicza.andras.sc2gears.util.GeneralUtils; import hu.belicza.andras.sc2gears.util.Holder; import hu.belicza.andras.sc2gears.util.NormalThread; import hu.belicza.andras.sc2gears.util.ProfileCache; import hu.belicza.andras.sc2gears.util.ReplayCache; import hu.belicza.andras.sc2gears.util.Task; import hu.belicza.andras.sc2gearspluginapi.api.sc2replay.ReplayConsts.BnetLanguage; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Frame; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.EnumMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Vector; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSlider; import javax.swing.JSpinner; import javax.swing.JTabbedPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.SpinnerNumberModel; import javax.swing.SwingUtilities; /** * Miscellaneous settings dialog. * * @author Andras Belicza */ @SuppressWarnings("serial") public class MiscSettingsDialog extends BaseDialog { /** * Miscellaneous Settings dialog tab. * @author Andras Belicza */ public static enum SettingsTab { /** Replay auto-save settings tab. */ REPLAY_AUTO_SAVE ( "miscSettings.tab.replayAutoSave" , Icons.DATABASE_SAVE ), /** APM Alert settings tab. */ APM_ALERT ( "miscSettings.tab.apmAlert" , Icons.ALARM_CLOCK ), /** Mouse print settings tab. */ MOUSE_PRINT ( "miscSettings.tab.mousePrint" , Icons.FINGERPRINT ), /** User interface settings tab. */ USER_INTERFACE ( "miscSettings.tab.userInterface" , Icons.UI_LAYOUT_PANEL ), /** Replay parser settings tab. */ REPLAY_PARSER ( "miscSettings.tab.replayParser" , Icons.COMPILE ), /** Replay analyzer settings tab. */ REPLAY_ANALYZER ( "miscSettings.tab.replayAnalyzer" , Icons.CHART ), /** Multi-rep analysis settings tab. */ MULTI_REP_ANALYSIS ( "miscSettings.tab.multiRepAnalysis" , Icons.CHART_UP_COLOR ), /** Internal settings tab. */ INTERNAL ( "miscSettings.tab.internal" , Icons.WRENCH ), /** Mouse game rules settings tab. */ MOUSE_GAME_RULES ( "miscSettings.tab.mouseGameRules" , Icons.MOUSE ), /** Aliases settings tab. */ ALIASES ( "miscSettings.tab.aliases" , Icons.USERS ), /** Pre-defined lists settings tab. */ PREDEFINED_LISTS ( "miscSettings.tab.predefinedLists" , Icons.UI_COMBO_BOX_BLUE ), /** Folders settings tab. */ FOLDERS ( "miscSettings.tab.folders" , Icons.FOLDERS ), /** Sc2gears Database settings tab. */ SC2GEARS_DATABASE ( "miscSettings.tab.sc2gearsDatabase" , Icons.SERVER_NETWORK ), /** Custom replay sites settings tab. */ CUSTOM_REPLAY_SITES( "miscSettings.tab.customReplaySites", Icons.DOCUMENT_SHARE ); /** Text of the tab. */ public final String text; /** Icon associated with the tab. */ public final Icon icon; /** * Creates a new Tab. * @param tabTextKey text key of the tab * @param icon icon associated with the tab */ private SettingsTab( final String tabTextKey, final Icon icon ) { this.text = Language.getText( tabTextKey ); this.icon = icon; } } /** * A folder row in the Folders tab in the Miscellaneous settings dialog. * * @author Andras Belicza */ private static class FolderRow { private final String settingKeyForDefault; // This is different if multiplicationIndex is provided private final Integer multiplicationIndex; private final String checkBoxSettingKey; private final String settingKey; public final JComponent infoComponent; private final JTextField textField; private final boolean isUserHomeRelative; public FolderRow( final String textKey, final String settingKey, final boolean isUserHomeRelative, final Integer multiplicationIndex, final String checkBoxSettingKey ) { settingKeyForDefault = settingKey; this.multiplicationIndex = multiplicationIndex; this.checkBoxSettingKey = checkBoxSettingKey; this.settingKey = multiplicationIndex == null ? settingKey : settingKey + multiplicationIndex; if ( multiplicationIndex == null ) infoComponent = new JLabel( Language.getText( textKey ) ); else infoComponent = new JCheckBox( Language.getText( textKey ) + " #" + multiplicationIndex, Settings.getBoolean( checkBoxSettingKey + multiplicationIndex ) ); textField = new JTextField( Settings.getString( this.settingKey ), 25 ); this.isUserHomeRelative = isUserHomeRelative; } public JComponent getComponent() { final Box box = Box.createHorizontalBox(); box.add( infoComponent ); box.add( textField ); final JButton chooseFolderButton = new JButton( Language.getText( "folderSettings.chooseFolder" ), Icons.FOLDER ); chooseFolderButton.addActionListener( new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { final String startFolder; if ( isUserHomeRelative ) { final File folder = new File( textField.getText() ); if ( folder.exists() ) startFolder = folder.getAbsolutePath(); else startFolder = new File( Consts.FOLDER_USER_HOME, textField.getText() ).getAbsolutePath(); } else startFolder = textField.getText(); final JFileChooser fileChooser = new JFileChooser( startFolder ); fileChooser.setDialogTitle( Language.getText( "folderSettings.chooseFolder" ) ); fileChooser.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY ); if ( fileChooser.showOpenDialog( MainFrame.INSTANCE ) == JFileChooser.APPROVE_OPTION ) { String selectedFilePath = fileChooser.getSelectedFile().getAbsolutePath(); if ( isUserHomeRelative && selectedFilePath.toLowerCase().startsWith( Consts.FOLDER_USER_HOME.toLowerCase() ) ) { // Make it relative to user home selectedFilePath = selectedFilePath.substring( Consts.FOLDER_USER_HOME.length() ); } textField.setText( selectedFilePath ); } } } ); box.add( chooseFolderButton ); final JButton restoreDefaultFolderButton = new JButton( Language.getText( "folderSettings.restoreDefaultFolder" ), Icons.FOLDER_MINUS ); restoreDefaultFolderButton.addActionListener( new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { textField.setText( Settings.getDefaultString( settingKeyForDefault ) ); } } ); box.add( restoreDefaultFolderButton ); if ( infoComponent instanceof JCheckBox ) { final ActionListener enablerActionListener = new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { final boolean enabled = ( (JCheckBox) infoComponent ).isSelected(); textField .setEnabled( enabled ); chooseFolderButton .setEnabled( enabled ); restoreDefaultFolderButton.setEnabled( enabled ); // Required due to the Napkin LAF textField.updateUI(); SwingUtilities.invokeLater( new Runnable() { @Override public void run() { chooseFolderButton .updateUI(); restoreDefaultFolderButton.updateUI(); } } ); } }; enablerActionListener.actionPerformed( null ); ( (JCheckBox) infoComponent ).addActionListener( enablerActionListener ); } return box; } public void storeSetting() { Settings.set( settingKey, textField.getText() ); if ( infoComponent instanceof JCheckBox ) Settings.set( checkBoxSettingKey + multiplicationIndex, ( (JCheckBox) infoComponent ).isSelected() ); } } /** * A setting row in the miscellaneous settings dialog. * * @author Andras Belicza */ private static class SettingRow { private final String settingKey; public final JComponent component; public final Box box = Box.createHorizontalBox(); public SettingRow( final String textKey, final String settingKey, final JComponent component, final JComponent extra ) { this.settingKey = settingKey; this.component = component; // Build GUI if ( component instanceof JSpinner && ( (JSpinner) component ).getModel() instanceof SpinnerNumberModel ) { final SpinnerNumberModel model = (SpinnerNumberModel) ( (JSpinner) component ).getModel(); component.setToolTipText( Language.getText( "miscSettings.validRangeAndDefaultToolTip", model.getMinimum(), model.getMaximum(), Settings.getDefaultInt( settingKey ) ) ); } if ( component instanceof JComboBox ) { final JComboBox< ? > comboBox = (JComboBox< ? >) component; if ( comboBox.isEditable() ) { // It's a pre-defined list combo box comboBox.setSelectedItem( Settings.getString( settingKey ) ); } else { // It's a normal combo box comboBox.setMaximumRowCount( comboBox.getModel().getSize() ); // Display all values try { comboBox.setSelectedIndex( Settings.getInt( settingKey ) ); } catch ( final IllegalArgumentException iae ) { comboBox.setSelectedIndex( Settings.getDefaultInt( settingKey ) ); } } } box.add( new JLabel( Language.getText( textKey ) ) ); box.add( component instanceof JCheckBox ? GuiUtils.wrapInPanelLeftAligned( component ) : component ); box.add( extra ); final JButton restoreDefaultButton = new JButton(); GuiUtils.updateButtonText( restoreDefaultButton, "miscSettings.restoreDefault" ); restoreDefaultButton.addActionListener( new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { if ( component instanceof JSpinner ) ( ( JSpinner) component ).setValue( Settings.getDefaultInt( settingKey ) ); else if ( component instanceof JSlider ) ( ( JSlider) component ).setValue( Settings.getDefaultInt( settingKey ) ); else if ( component instanceof JTextField ) ( ( JTextField) component ).setText( Settings.getDefaultString( settingKey ) ); else if ( component instanceof JCheckBox ) ( ( JCheckBox) component ).setSelected( Settings.getDefaultBoolean( settingKey ) ); else if ( component instanceof JComboBox ) { final JComboBox< ? > comboBox = (JComboBox< ? >) component; if ( comboBox.isEditable() ) // It's a pre-defined list combo box comboBox.setSelectedItem( Settings.getDefaultString( settingKey ) ); else // Normal combo box comboBox.setSelectedIndex( Settings.getDefaultInt( settingKey ) ); } } } ); box.add( restoreDefaultButton ); } public void storeSetting() { if ( component instanceof JSpinner ) Settings.set( settingKey, ( (JSpinner) component ).getValue() ); else if ( component instanceof JSlider ) Settings.set( settingKey, ( (JSlider) component ).getValue() ); else if ( component instanceof JTextField ) Settings.set( settingKey, ( (JTextField) component ).getText() ); else if ( component instanceof JCheckBox ) Settings.set( settingKey, ( (JCheckBox) component ).isSelected() ); else if ( component instanceof JComboBox ) { Settings.set( settingKey, ( (JComboBox< ? >) component ).getSelectedIndex() ); final JComboBox< ? > comboBox = (JComboBox< ? >) component; if ( comboBox.isEditable() ) // It's a pre-defined list combo box Settings.set( settingKey, comboBox.getSelectedItem() ); else // Normal combo box Settings.set( settingKey, comboBox.getSelectedIndex() ); } } } /** * Creates a new MiscSettingsDialog.<br> * The MainFrame instance will be the owner of the dialog. * @param tabToSelect optional tab to select */ public MiscSettingsDialog( final SettingsTab tabToSelect ) { this( MainFrame.INSTANCE, tabToSelect, null ); } /** * Creates a new MiscSettingsDialog. * @param owner the Frame from which the misc settings dialog is displayed * @param tabToSelect optional tab to select * @param initialPredefinedList optional initial pre-defined list to select */ public MiscSettingsDialog( final Frame owner, final SettingsTab tabToSelect, final PredefinedList initialPredefinedList ) { super( owner, "miscSettings.title", Icons.EQUALIZER ); final JTabbedPane tabbedPane = new JTabbedPane( JTabbedPane.LEFT ); final JSlider soundVolumenSlider = new JSlider ( 0, 100, Settings.getInt( Settings.KEY_SETTINGS_MISC_SOUND_VOLUME ) ); soundVolumenSlider.setMajorTickSpacing( 20 ); soundVolumenSlider.setMinorTickSpacing( 10 ); soundVolumenSlider.setPaintTicks( true ); soundVolumenSlider.setPaintLabels( true ); final JButton testSoundButton = new JButton( Icons.CONTROL ); GuiUtils.updateButtonText( testSoundButton, "miscSettings.testSoundButton" ); testSoundButton.addActionListener( new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { Sounds.playSoundSample( Sounds.SAMPLE_SC2GEARS, false, soundVolumenSlider.getValue() ); } } ); final JComboBox< String > repAutoSaveNameTemplateComboBox = GuiUtils.createPredefinedListComboBox( PredefinedList.REP_AUTO_SAVE_TEMPLATE, false ); repAutoSaveNameTemplateComboBox.setToolTipText( Language.getText( "miscSettings.repAutoSaveNameTemplateToolTip" ) ); final JButton editTemplateButton = new JButton( Icons.UI_SCROLL_PANE_LIST ); GuiUtils.updateButtonText( editTemplateButton, "miscSettings.editTemplateButton" ); editTemplateButton.addActionListener( new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { new AutoSaveNameTemplateEditorDialog( MiscSettingsDialog.this, repAutoSaveNameTemplateComboBox ); } } ); final JTextField favoredPlayerListTextField = new JTextField( Settings.getString( Settings.KEY_SETTINGS_MISC_FAVORED_PLAYER_LIST ) ); favoredPlayerListTextField.setToolTipText( Language.getText( "miscSettings.favoredPlayerListToolTip" ) ); final JTextField mousePrintBackgroundColorTextField = new JTextField( Settings.getString( Settings.KEY_SETTINGS_MISC_MOUSE_PRINT_BACKGROUND_COLOR ) ); mousePrintBackgroundColorTextField.setToolTipText( Language.getText( "miscSettings.colorFieldToolTip" ) ); final JButton chooseBackgroundColorButton = new JButton( Icons.COLOR ); GuiUtils.updateButtonText( chooseBackgroundColorButton, "miscSettings.chooseColor" ); chooseBackgroundColorButton.addActionListener( new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { final Color color = new ColorChooserDialog( MiscSettingsDialog.this, GeneralUtils.getColorSetting( mousePrintBackgroundColorTextField.getText(), Settings.KEY_SETTINGS_MISC_MOUSE_PRINT_BACKGROUND_COLOR ) ).getColor(); if ( color != null ) mousePrintBackgroundColorTextField.setText( color.getRed() + "," + color.getGreen() + "," + color.getBlue() ); } } ); final JTextField mousePrintColorTextField = new JTextField( Settings.getString( Settings.KEY_SETTINGS_MISC_MOUSE_PRINT_COLOR ) ); mousePrintColorTextField.setToolTipText( Language.getText( "miscSettings.colorFieldToolTip" ) ); final JButton chooseColorButton = new JButton( Icons.COLOR ); GuiUtils.updateButtonText( chooseColorButton, "miscSettings.chooseColor" ); chooseColorButton.addActionListener( new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { final Color color = new ColorChooserDialog( MiscSettingsDialog.this, GeneralUtils.getColorSetting( mousePrintColorTextField.getText(), Settings.KEY_SETTINGS_MISC_MOUSE_PRINT_COLOR ) ).getColor(); if ( color != null ) mousePrintColorTextField.setText( color.getRed() + "," + color.getGreen() + "," + color.getBlue() ); } } ); final JComboBox< DataCompression > binaryDataCompressionAlgorithmComboBox = new JComboBox<>( DataCompression.values() ); binaryDataCompressionAlgorithmComboBox.setMaximumRowCount( binaryDataCompressionAlgorithmComboBox.getModel().getSize() ); // Display all output formats try { binaryDataCompressionAlgorithmComboBox.setSelectedIndex( Settings.getInt( Settings.KEY_SETTINGS_MISC_MOUSE_PRINT_DATA_COMPRESSION ) ); } catch ( final IllegalArgumentException iae ) { binaryDataCompressionAlgorithmComboBox.setSelectedIndex( Settings.getDefaultInt( Settings.KEY_SETTINGS_MISC_MOUSE_PRINT_DATA_COMPRESSION ) ); } final JComboBox< BnetLanguage > bnetLanguagesComboBox = new JComboBox<>( BnetLanguage.values() ); bnetLanguagesComboBox.setMaximumRowCount( bnetLanguagesComboBox.getModel().getSize() ); // Display all bnet languages bnetLanguagesComboBox.setToolTipText( Language.getText( "miscSettings.preferredBnetLanguageToolTip" ) ); bnetLanguagesComboBox.setRenderer( new BaseLabelListCellRenderer< BnetLanguage >() { @Override public Icon getIcon( final BnetLanguage value ) { return Icons.getLanguageIcon( Language.getDefaultText( value.textKey ) ); } } ); final JButton emptyProfileCacheButton = new JButton( Icons.CROSS ); GuiUtils.updateButtonText( emptyProfileCacheButton, "miscSettings.emptyReplayCacheButton" ); emptyProfileCacheButton.addActionListener( new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { if ( GuiUtils.showConfirmDialog( Language.getText( "miscSettings.confirmEmptyProfileCache" ), true ) != 0 ) return; ProfileCache.emptyCache( MiscSettingsDialog.this ); } } ); final JButton emptyReplayCacheButton = new JButton( Icons.CROSS ); GuiUtils.updateButtonText( emptyReplayCacheButton, "miscSettings.emptyReplayCacheButton" ); emptyReplayCacheButton.addActionListener( new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { if ( GuiUtils.showConfirmDialog( Language.getText( "miscSettings.confirmEmptyReplayCache" ), true ) != 0 ) return; ReplayCache.emptyCache(); } } ); final String customDateTimeFormatToolTip = Language.getText( "miscSettings.customDateTimeFormatToolTip" ); final JComboBox< String > customDateFormatTextComboBox = GuiUtils.createPredefinedListComboBox( PredefinedList.CUSTOM_DATE_FORMAT, false ); customDateFormatTextComboBox.setToolTipText( customDateTimeFormatToolTip ); final JPanel customDateControlPanel = new JPanel( new BorderLayout() ); final JButton testCustomDateButton = new JButton( Language.getText( "miscSettings.testFormatButton" ) ); customDateControlPanel.add( testCustomDateButton, BorderLayout.CENTER ); customDateControlPanel.add( GuiUtils.createDateTimeFormatHelpLinkLabel(), BorderLayout.EAST ); final JComboBox< String > customTimeFormatTextComboBox = GuiUtils.createPredefinedListComboBox( PredefinedList.CUSTOM_TIME_FORMAT, false ); customTimeFormatTextComboBox.setToolTipText( customDateTimeFormatToolTip ); final JPanel customTimeControlPanel = new JPanel( new BorderLayout() ); final JButton testCustomTimeButton = new JButton( Language.getText( "miscSettings.testFormatButton" ) ); customTimeControlPanel.add( testCustomTimeButton, BorderLayout.CENTER ); customTimeControlPanel.add( GuiUtils.createDateTimeFormatHelpLinkLabel(), BorderLayout.EAST ); final JComboBox< String > customDateTimeFormatTextComboBox = GuiUtils.createPredefinedListComboBox( PredefinedList.CUSTOM_DATE_TIME_FORMAT, false ); customDateTimeFormatTextComboBox.setToolTipText( customDateTimeFormatToolTip ); final JPanel customDateTimeControlPanel = new JPanel( new BorderLayout() ); final JButton testCustomDateTimeButton = new JButton( Language.getText( "miscSettings.testFormatButton" ) ); customDateTimeControlPanel.add( testCustomDateTimeButton, BorderLayout.CENTER ); customDateTimeControlPanel.add( GuiUtils.createDateTimeFormatHelpLinkLabel(), BorderLayout.EAST ); final ActionListener testCustomDateTimeActionListener = new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { final String pattern = ( event.getSource() == testCustomDateButton ? customDateFormatTextComboBox : event.getSource() == testCustomTimeButton ? customTimeFormatTextComboBox : customDateTimeFormatTextComboBox ).getSelectedItem().toString(); try { final String currentTime = new SimpleDateFormat( pattern ).format( new Date() ); GuiUtils.showInfoDialog( new Object[] { Language.getText( "miscSettings.dateTimeFormatValid" ), " ", Language.getText( "miscSettings.currentDateTimeWithFormat" ), currentTime } ); } catch ( IllegalArgumentException iae ) { iae.printStackTrace(); GuiUtils.showErrorDialog( Language.getText( "miscSettings.dateTimeFormatInvalid" ) ); } } }; testCustomDateButton .addActionListener( testCustomDateTimeActionListener ); testCustomTimeButton .addActionListener( testCustomDateTimeActionListener ); testCustomDateTimeButton.addActionListener( testCustomDateTimeActionListener ); final Holder< ProxyConfig > proxyConfigHolder = new Holder< ProxyConfig >(); final JButton proxyConfigButton = new JButton( Icons.GLOBE_NETWORK ); GuiUtils.updateButtonText( proxyConfigButton, "miscSettings.proxyConfigButton" ); proxyConfigButton.addActionListener( new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { if ( proxyConfigHolder.value == null ) proxyConfigHolder.value = new ProxyConfig(); new ProxyConfigDialog( proxyConfigHolder.value ); } } ); final JCheckBox enableProxyConfigCheckBox = new JCheckBox( Language.getText( "miscSettings.enableProxyConfig" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_ENABLE_PROXY_CONFIG ) ); final ActionListener enableProxyConfigActionListener = new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { proxyConfigButton.setEnabled( enableProxyConfigCheckBox.isSelected() ); } }; enableProxyConfigActionListener.actionPerformed( null ); enableProxyConfigCheckBox.addActionListener( enableProxyConfigActionListener ); final JTextField mouseGameRandomSeedTextField = new JTextField( Settings.getString( Settings.KEY_SETTINGS_MOUSE_GAME_RANDOM_SEED ) ); mouseGameRandomSeedTextField.setToolTipText( Language.getText( "miscSettings.randomSeedToolTip" ) ); final SettingRow[][] settingGroups = { // Replay auto-save { new SettingRow( "miscSettings.repAutoSaveNameTemplate", Settings.KEY_SETTINGS_MISC_REP_AUTO_SAVE_NAME_TEMPLATE, repAutoSaveNameTemplateComboBox, editTemplateButton ), new SettingRow( "miscSettings.newReplayDetectionMethod", Settings.KEY_SETTINGS_MISC_NEW_REPLAY_DETECTION_METHOD, new JComboBox<>( ReplayAutoSaver.fileMonitorSupported ? NewFileDetectionMethod.values() : new NewFileDetectionMethod[] { NewFileDetectionMethod.POLLING } ), new JLabel() ), new SettingRow( "miscSettings.newRepCheckIntervalSec", Settings.KEY_SETTINGS_MISC_NEW_REP_CHECK_INTERVAL_SEC, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_NEW_REP_CHECK_INTERVAL_SEC ), 1, 100, 1 ) ), new JLabel( Language.getText( "miscSettings.seconds" ) ) ), new SettingRow( "miscSettings.playReplaySavedVoiceWhenReplaysAreSaved", Settings.KEY_SETTINGS_MISC_PLAY_REPLAY_SAVED_VOICE, new JCheckBox( Language.getText( "miscSettings.playReplaySavedVoice" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_PLAY_REPLAY_SAVED_VOICE ) ), new JLabel() ), new SettingRow( "miscSettings.deleteSuccessfullyAutoSavedReplays", Settings.KEY_SETTINGS_MISC_DELETE_AUTO_SAVED_REPLAYS, new JCheckBox( Language.getText( "miscSettings.deleteAutoSavedReplays" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_DELETE_AUTO_SAVED_REPLAYS ) ), new JLabel() ), new SettingRow( "miscSettings.autoOpenNewReplaysInAnalyzer", Settings.KEY_SETTINGS_MISC_AUTO_OPEN_NEW_REPLAYS, new JCheckBox( Language.getText( "miscSettings.autoOpenNewReplays" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_AUTO_OPEN_NEW_REPLAYS ) ), new JLabel() ), new SettingRow( "miscSettings.showGameInfoDialogWhenNewReplayDetected", Settings.KEY_SETTINGS_MISC_SHOW_GAME_INFO_FOR_NEW_REPLAYS, new JCheckBox( Language.getText( "miscSettings.showOnTopGameInfoDialogForNewReplays" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_SHOW_GAME_INFO_FOR_NEW_REPLAYS ) ), new JLabel() ), new SettingRow( "miscSettings.autoStoreNewReplaysInDatabase", Settings.KEY_SETTINGS_MISC_AUTO_STORE_NEW_REPLAYS, new JCheckBox( Language.getText( "miscSettings.autoStoreNewReplays" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_AUTO_STORE_NEW_REPLAYS ) ), new JLabel() ) }, // APM alert { new SettingRow( "miscSettings.apmAlertLevel", Settings.KEY_SETTINGS_MISC_APM_ALERT_LEVEL, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_APM_ALERT_LEVEL ), 0, 1000, 1 ) ), new JLabel( Language.getText( "miscSettings.apm" ) ) ), new SettingRow( "miscSettings.apmWarmupTime", Settings.KEY_SETTINGS_MISC_APM_WARMUP_TIME, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_APM_WARMUP_TIME ), 0, 300, 1 ) ), new JLabel( Language.getText( "miscSettings.seconds" ) ) ), new SettingRow( "miscSettings.apmCheckIntervalSec", Settings.KEY_SETTINGS_MISC_APM_CHECK_INTERVAL_SEC, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_APM_CHECK_INTERVAL_SEC ), 1, 15, 1 ) ), new JLabel( Language.getText( "miscSettings.seconds" ) ) ), new SettingRow( "miscSettings.alertWhenApmIsAboveAlertLevelAgain", Settings.KEY_SETTINGS_MISC_ALERT_WHEN_APM_IS_BACK_TO_NORMAL, new JCheckBox( Language.getText( "miscSettings.alertWhenApmIsBackToNormal" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_ALERT_WHEN_APM_IS_BACK_TO_NORMAL ) ), new JLabel() ), new SettingRow( "miscSettings.alertRepetitionIntervalIfApmStaysLow", Settings.KEY_SETTINGS_MISC_APM_ALERT_REPETITION_INTERVAL_SEC, new JComboBox<>( Sc2RegMonitor.APM_ALERT_REPETITION_INTERVALS ), new JLabel( Language.getText( "miscSettings.seconds" ) ) ), new SettingRow( "miscSettings.alertOnGameStartEvents", Settings.KEY_SETTINGS_MISC_ALERT_ON_GAME_START, new JCheckBox( Language.getText( "miscSettings.alertWhenGamesStarts" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_ALERT_ON_GAME_START ) ), new JLabel() ), new SettingRow( "miscSettings.alertOnGameEndEvents", Settings.KEY_SETTINGS_MISC_ALERT_ON_GAME_END, new JCheckBox( Language.getText( "miscSettings.alertWhenGamesEnd" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_ALERT_ON_GAME_END ) ), new JLabel() ), new SettingRow( "miscSettings.autoShowHideApmDisplayDialog", Settings.KEY_SETTINGS_MISC_SHOW_HIDE_APM_DISPLAY_ON_START_END, new JCheckBox( Language.getText( "miscSettings.showHideOnTopApmDisplayDialog" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_SHOW_HIDE_APM_DISPLAY_ON_START_END ) ), new JLabel() ), }, // Mouse print { new SettingRow( "miscSettings.saveMousePrintsOfAllGames", Settings.KEY_SETTINGS_MISC_SAVE_MOUSE_PRINTS, new JCheckBox( Language.getText( "miscSettings.saveMousePrints#2" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_SAVE_MOUSE_PRINTS ) ), new JLabel() ), new SettingRow( "miscSettings.storeMousePrintsOfAllGames", Settings.KEY_SETTINGS_MISC_STORE_MOUSE_PRINTS, new JCheckBox( Language.getText( "miscSettings.storeMousePrints" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_STORE_MOUSE_PRINTS ) ), new JLabel() ), new SettingRow( "miscSettings.mousePrintSamplingTime", Settings.KEY_SETTINGS_MISC_MOUSE_PRINT_SAMPLING_TIME, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_MOUSE_PRINT_SAMPLING_TIME ), 1, 20, 1 ) ), new JLabel( Language.getText( "miscSettings.ms" ) ) ), new SettingRow( "miscSettings.mousePrintWhatToSave", Settings.KEY_SETTINGS_MISC_MOUSE_PRINT_WHAT_TO_SAVE, new JComboBox<>( WhatToSave.values() ), GeneralUtils.createLinkLabel( Language.getText( "miscSettings.smpdFormatSpec" ), Consts.URL_SMPD_FORMAT_SPECIFICATION ) ), new SettingRow( "miscSettings.binaryDataCompressionAlgorithm", Settings.KEY_SETTINGS_MISC_MOUSE_PRINT_DATA_COMPRESSION, new JComboBox<>( DataCompression.values() ), new JLabel() ), new SettingRow( "miscSettings.mousePrintImageOutputFormat", Settings.KEY_SETTINGS_MISC_MOUSE_PRINT_IMAGE_OUTPUT_FORMAT, new JComboBox<>( MousePrintRecorder.OUTPUT_FORMATS ), new JLabel() ), new SettingRow( "miscSettings.useAntialiasingEffect", Settings.KEY_SETTINGS_MISC_MOUSE_PRINT_USE_ANTIALIASING, new JCheckBox( Language.getText( "miscSettings.useAntialiasing" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_MOUSE_PRINT_USE_ANTIALIASING ) ), new JLabel() ), new SettingRow( "miscSettings.mousePrintBackgroundColorRGB", Settings.KEY_SETTINGS_MISC_MOUSE_PRINT_BACKGROUND_COLOR, mousePrintBackgroundColorTextField, chooseBackgroundColorButton ), new SettingRow( "miscSettings.mousePrintColorRGB", Settings.KEY_SETTINGS_MISC_MOUSE_PRINT_COLOR, mousePrintColorTextField, chooseColorButton ), new SettingRow( "miscSettings.pourInkWhenMouseIsIdleFor", Settings.KEY_SETTINGS_MISC_MOUSE_PRINT_POUR_INK_IDLE_TIME, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_MOUSE_PRINT_POUR_INK_IDLE_TIME ), 1, 30, 1 ) ), new JLabel( Language.getText( "miscSettings.seconds" ) ) ), new SettingRow( "miscSettings.idleInkFlowRate", Settings.KEY_SETTINGS_MISC_MOUSE_PRINT_IDLE_INK_FLOW_RATE, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_MOUSE_PRINT_IDLE_INK_FLOW_RATE ), 1, 1500, 1 ) ), new JLabel( Language.getText( "miscSettings.pixelPersec" ) ) ), new SettingRow( "miscSettings.mouseWarmupTime", Settings.KEY_SETTINGS_MISC_MOUSE_WARMUP_TIME, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_MOUSE_WARMUP_TIME ), 0, 300, 1 ) ), new JLabel( Language.getText( "miscSettings.seconds" ) ) ) }, // User interface { new SettingRow( "miscSettings.preferredBnetLanguage", Settings.KEY_SETTINGS_MISC_PREFERRED_BNET_LANGUAGE, bnetLanguagesComboBox, new JLabel() ), new SettingRow( "miscSettings.navBarInitialWidth", Settings.KEY_SETTINGS_MISC_NAV_BAR_INITIAL_WIDTH, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_NAV_BAR_INITIAL_WIDTH ), 0, 1000, 1 ) ), new JLabel( Language.getText( "miscSettings.pixels" ) ) ), new SettingRow( "miscSettings.chartsActionListPartition", Settings.KEY_SETTINGS_MISC_CHARTS_ACTION_LIST_PARTITIONING, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_CHARTS_ACTION_LIST_PARTITIONING ), 0, 100, 1 ) ), new JLabel( Language.getText( "miscSettings.percent" ) ) ), new SettingRow( "miscSettings.toolTipInitialDelay", Settings.KEY_SETTINGS_MISC_TOOL_TIP_INITIAL_DELAY, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_TOOL_TIP_INITIAL_DELAY ), 0, 10000, 1 ) ), new JLabel( Language.getText( "miscSettings.ms" ) ) ), new SettingRow( "miscSettings.toolTipDismissDelay", Settings.KEY_SETTINGS_MISC_TOOL_TIP_DISMISS_DELAY, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_TOOL_TIP_DISMISS_DELAY ), 0, 50000, 1 ) ), new JLabel( Language.getText( "miscSettings.ms" ) ) ), new SettingRow( "miscSettings.displayInfoBalloonWhenStartedMinimized", Settings.KEY_SETTINGS_MISC_DISPLAY_INFO_WHEN_STARTED_MINIMIZED, new JCheckBox( Language.getText( "miscSettings.displayInfoBalloonWhenStartedMinimized2" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_DISPLAY_INFO_WHEN_STARTED_MINIMIZED ) ), new JLabel() ), }, // Replay parser { new SettingRow( "miscSettings.useRealTimeMeasurement", Settings.KEY_SETTINGS_MISC_USE_REAL_TIME_MEASUREMENT, new JCheckBox( Language.getText( "miscSettings.convertGameTimeToRealTime" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_USE_REAL_TIME_MEASUREMENT ) ), new JLabel() ), new SettingRow( "miscSettings.initialTimeToExcludeFromApm", Settings.KEY_SETTINGS_MISC_INITIAL_TIME_TO_EXCLUDE_FROM_APM, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_INITIAL_TIME_TO_EXCLUDE_FROM_APM ), 0, 1000, 1 ) ), new JLabel( Language.getText( "miscSettings.seconds" ) ) ), new SettingRow( "miscSettings.favoredPlayerList", Settings.KEY_SETTINGS_MISC_FAVORED_PLAYER_LIST, favoredPlayerListTextField, new JLabel() ), new SettingRow( "miscSettings.declareLargestWinner", Settings.KEY_SETTINGS_MISC_DECLARE_LARGEST_AS_WINNER, new JCheckBox( Language.getText( "miscSettings.largestRemainingTeamWins" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_DECLARE_LARGEST_AS_WINNER ) ), new JLabel() ), new SettingRow( "miscSettings.overrideDetectedFormatBasedOnMatchup", Settings.KEY_SETTINGS_MISC_OVERRIDE_FORMAT_BASED_ON_MATCHUP, new JCheckBox( Language.getText( "miscSettings.overrideFormatBasedOnMatchup" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_OVERRIDE_FORMAT_BASED_ON_MATCHUP ) ), new JLabel() ), new SettingRow( "miscSettings.enableInternalPreprocessedReplayCache", Settings.KEY_SETTINGS_MISC_CACHE_PREPROCESSED_REPLAYS, new JCheckBox( Language.getText( "miscSettings.cachePreprocessedReplays" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_CACHE_PREPROCESSED_REPLAYS ) ), emptyReplayCacheButton ), new SettingRow( "miscSettings.useMd5HashFromFilename", Settings.KEY_SETTINGS_MISC_USE_MD5_HASH_FROM_FILE_NAME, new JCheckBox( Language.getText( "miscSettings.useMd5HashIfFoundInFileNames" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_USE_MD5_HASH_FROM_FILE_NAME ) ), new JLabel() ) }, // Replay analyzer { new SettingRow( "miscSettings.showProfileInfo", Settings.KEY_REP_MISC_ANALYZER_SHOW_PROFILE_INFO, new JComboBox<>( ShowProfileInfo.values() ), emptyProfileCacheButton ), new SettingRow( "miscSettings.autoRetrieveExtProfileInfo", Settings.KEY_REP_MISC_ANALYZER_AUTO_RETRIEVE_EXT_PROFILE_INFO, new JCheckBox( Language.getText( "miscSettings.autoRetrieveExtProfileInfo2" ), Settings.getBoolean( Settings.KEY_REP_MISC_ANALYZER_AUTO_RETRIEVE_EXT_PROFILE_INFO ) ), new JLabel() ), new SettingRow( "miscSettings.profileInfoValidityTime", Settings.KEY_SETTINGS_MISC_PROFILE_INFO_VALIDITY_TIME, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_PROFILE_INFO_VALIDITY_TIME ), 1, 30, 1 ) ), new JLabel( Language.getText( "miscSettings.days" ) ) ), new SettingRow( "miscSettings.maxTableSizeInProfileToolTip", Settings.KEY_REP_MISC_ANALYZER_MAX_ROWS_IN_PROFILE_TOOL_TIP, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_REP_MISC_ANALYZER_MAX_ROWS_IN_PROFILE_TOOL_TIP ), 0, 100, 1 ) ), new JLabel( Language.getText( "miscSettings.rows" ) ) ), new SettingRow( "miscSettings.rearrangePlayersInRepAnalyzer", Settings.KEY_SETTINGS_MISC_REARRANGE_PLAYERS_IN_REP_ANALYZER, new JCheckBox( Language.getText( "miscSettings.applyFavoredListInRepAnalyzer" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_REARRANGE_PLAYERS_IN_REP_ANALYZER ) ), new JLabel() ), new SettingRow( "miscSettings.showWinners", Settings.KEY_SETTINGS_MISC_SHOW_WINNERS, new JCheckBox( Language.getText( "miscSettings.showWinners2" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_SHOW_WINNERS ) ), new JLabel() ), new SettingRow( "miscSettings.animateRefreshRate", Settings.KEY_SETTINGS_MISC_ANIMATOR_FPS, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_ANIMATOR_FPS ), 1, 30, 1 ) ), new JLabel( Language.getText( "miscSettings.fps" ) ) ), new SettingRow( "miscSettings.animatorJumpTime", Settings.KEY_SETTINGS_MISC_ANIMATOR_JUMP_TIME, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_ANIMATOR_JUMP_TIME ), 1, 1200, 1 ) ), new JLabel( Language.getText( "miscSettings.seconds" ) ) ) }, // Multi-rep analysis { new SettingRow( "miscSettings.timeLimitForMultiRepAnalysis", Settings.KEY_SETTINGS_MISC_TIME_LIMIT_FOR_MULTI_REP_ANALYSIS, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_TIME_LIMIT_FOR_MULTI_REP_ANALYSIS ), 0, 1000, 1 ) ), new JLabel( Language.getText( "miscSettings.seconds" ) ) ), new SettingRow( "miscSettings.buildOrderLength", Settings.KEY_SETTINGS_MISC_BUILD_ORDER_LENGTH, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_BUILD_ORDER_LENGTH ), 1, 100, 1 ) ), new JLabel( Language.getText( "miscSettings.buildings" ) ) ), new SettingRow( "miscSettings.gameLengthRecordsGranularity", Settings.KEY_SETTINGS_MISC_GAME_LENGTH_RECORDS_GRANULARITY, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_GAME_LENGTH_RECORDS_GRANULARITY ), 1, 120, 1 ) ), new JLabel( Language.getText( "miscSettings.minutes" ) ) ), new SettingRow( "miscSettings.maxGamingSessionBreak", Settings.KEY_SETTINGS_MISC_MAX_GAMING_SESSION_BREAK, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_MAX_GAMING_SESSION_BREAK ), 1, 600, 1 ) ), new JLabel( Language.getText( "miscSettings.minutes" ) ) ) }, // Internal { new SettingRow( "miscSettings.soundVolume", Settings.KEY_SETTINGS_MISC_SOUND_VOLUME, soundVolumenSlider, testSoundButton ), new SettingRow( "miscSettings.timeToKeepLogFiles", Settings.KEY_SETTINGS_MISC_TIME_TO_KEEP_LOG_FILES, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_TIME_TO_KEEP_LOG_FILES ), 0, 10000, 1 ) ), new JLabel( Language.getText( "miscSettings.days" ) ) ), new SettingRow( "miscSettings.preloadSc2IconsOnStartup", Settings.KEY_SETTINGS_MISC_PRELOAD_SC2_ICONS_ON_STARTUP, new JCheckBox( Language.getText( "miscSettings.preloadSc2IconsOnStartup2" ), Settings.getBoolean( Settings.KEY_SETTINGS_MISC_PRELOAD_SC2_ICONS_ON_STARTUP ) ), new JLabel() ), new SettingRow( "miscSettings.allowOnlyOneInstance", Settings.KEY_SETTINGS_ALLOW_ONLY_ONE_INSTANCE, new JCheckBox( Language.getText( "miscSettings.enableInstanceMonitor" ), Settings.getBoolean( Settings.KEY_SETTINGS_ALLOW_ONLY_ONE_INSTANCE ) ), new JLabel() ), new SettingRow( "miscSettings.accessTheInternetThroughProxy", Settings.KEY_SETTINGS_MISC_ENABLE_PROXY_CONFIG, enableProxyConfigCheckBox, proxyConfigButton ), new SettingRow( "miscSettings.utilizedCpuCores", Settings.KEY_SETTINGS_MISC_UTILIZED_CPU_CORES, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MISC_UTILIZED_CPU_CORES ), 0, 32, 1 ) ), new JLabel( "(" + Language.getText( "miscSettings.detectedCpuCores", Runtime.getRuntime().availableProcessors() ) + ")" ) ), new SettingRow( "miscSettings.maxReplaysToOpenForOpenInAnalyzer", Settings.KEY_SETTINGS_MAX_REPLAYS_TO_OPEN_FOR_OPEN_IN_ANALYZER, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MAX_REPLAYS_TO_OPEN_FOR_OPEN_IN_ANALYZER ), 1, 15, 1 ) ), new JLabel() ), new SettingRow( "miscSettings.customDateFormat", Settings.KEY_SETTINGS_MISC_CUSTOM_DATE_FORMAT, customDateFormatTextComboBox, customDateControlPanel ), new SettingRow( "miscSettings.customTimeFormat", Settings.KEY_SETTINGS_MISC_CUSTOM_TIME_FORMAT, customTimeFormatTextComboBox, customTimeControlPanel ), new SettingRow( "miscSettings.customDateTimeFormat", Settings.KEY_SETTINGS_MISC_CUSTOM_DATE_TIME_FORMAT, customDateTimeFormatTextComboBox, customDateTimeControlPanel ) }, // Mouse game rules { new SettingRow( "miscSettings.gameSpeedRefreshRate", Settings.KEY_SETTINGS_MOUSE_GAME_FPS, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MOUSE_GAME_FPS ), 1, 50, 1 ) ), new JLabel( Language.getText( "miscSettings.fps" ) ) ), new SettingRow( "miscSettings.maxDiscRadius", Settings.KEY_SETTINGS_MOUSE_GAME_MAX_DISC_RADIUS, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MOUSE_GAME_MAX_DISC_RADIUS ), 1, 200, 1 ) ), new JLabel( Language.getText( "miscSettings.pixels" ) ) ), new SettingRow( "miscSettings.maxDiscAge", Settings.KEY_SETTINGS_MOUSE_GAME_MAX_DISC_AGE, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MOUSE_GAME_MAX_DISC_AGE ), 1, 10000, 1 ) ), new JLabel( Language.getText( "miscSettings.ms" ) ) ), new SettingRow( "miscSettings.maxDiscScore", Settings.KEY_SETTINGS_MOUSE_GAME_MAX_DISC_SCORE, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MOUSE_GAME_MAX_DISC_SCORE ), 1, 1000, 1 ) ), new JLabel( Language.getText( "miscSettings.points" ) ) ), new SettingRow( "miscSettings.maxDiscsMissed", Settings.KEY_SETTINGS_MOUSE_GAME_MAX_DISCS_MISSED, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MOUSE_GAME_MAX_DISCS_MISSED ), 1, 1000, 1 ) ), new JLabel() ), new SettingRow( "miscSettings.discMovementSpeed", Settings.KEY_SETTINGS_MOUSE_GAME_DISC_SPEED, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MOUSE_GAME_DISC_SPEED ), 0, 500, 1 ) ), new JLabel( Language.getText( "miscSettings.pixelPersec" ) ) ), new SettingRow( "miscSettings.greenDiscProbability", Settings.KEY_SETTINGS_MOUSE_GAME_FRIENDLY_DISC_PROBABILITY, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MOUSE_GAME_FRIENDLY_DISC_PROBABILITY ), 0, 100, 1 ) ), new JLabel( Language.getText( "miscSettings.percent" ) ) ), new SettingRow( "miscSettings.initialDelayForNewDisc", Settings.KEY_SETTINGS_MOUSE_GAME_INITIAL_DELAY_FOR_NEW_DISC, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MOUSE_GAME_INITIAL_DELAY_FOR_NEW_DISC ), 1, 10000, 1 ) ), new JLabel( Language.getText( "miscSettings.ms" ) ) ), new SettingRow( "miscSettings.newDiscDelayDecrement", Settings.KEY_SETTINGS_MOUSE_GAME_NEW_DISC_DELAY_DECREMENT, new JSpinner( new SpinnerNumberModel( Settings.getInt( Settings.KEY_SETTINGS_MOUSE_GAME_NEW_DISC_DELAY_DECREMENT ), 0, 100, 1 ) ), new JLabel( Language.getText( "miscSettings.msPerDisc" ) ) ), new SettingRow( "miscSettings.randomSeed", Settings.KEY_SETTINGS_MOUSE_GAME_RANDOM_SEED, mouseGameRandomSeedTextField, new JLabel() ), new SettingRow( "miscSettings.paintCrossAtCenterOfDiscs", Settings.KEY_SETTINGS_MOUSE_GAME_PAINT_DISC_CENTER_CROSS, new JCheckBox( Language.getText( "miscSettings.paintDiscCenterCross" ), Settings.getBoolean( Settings.KEY_SETTINGS_MOUSE_GAME_PAINT_DISC_CENTER_CROSS ) ), new JLabel() ), new SettingRow( "miscSettings.paintCircleAroundDiscs", Settings.KEY_SETTINGS_MOUSE_GAME_PAINT_MAX_DISC_OUTLINE, new JCheckBox( Language.getText( "miscSettings.paintMaxDiscOutline" ), Settings.getBoolean( Settings.KEY_SETTINGS_MOUSE_GAME_PAINT_MAX_DISC_OUTLINE ) ), new JLabel() ) } }; final SettingsTab[] settingsTabs = new SettingsTab[] { SettingsTab.REPLAY_AUTO_SAVE, SettingsTab.APM_ALERT, SettingsTab.MOUSE_PRINT, SettingsTab.USER_INTERFACE, SettingsTab.REPLAY_PARSER, SettingsTab.REPLAY_ANALYZER, SettingsTab.MULTI_REP_ANALYSIS, SettingsTab.INTERNAL, SettingsTab.MOUSE_GAME_RULES }; for ( int i = 0; i < settingGroups.length; i++ ) { final Box tabBox = Box.createVerticalBox(); tabBox.setBorder( BorderFactory.createEmptyBorder( 5, 5, 0, 5 ) ); GuiUtils.addNewTab( settingsTabs[ i ].text, settingsTabs[ i ].icon, false, tabbedPane, GuiUtils.wrapInPanel( tabBox ), null ); if ( tabToSelect == settingsTabs[ i ] ) tabbedPane.setSelectedIndex( tabbedPane.getTabCount() - 1 ); final SettingRow[] settingGroup = settingGroups[ i ]; for ( final SettingRow settingRow : settingGroup ) tabBox.add( settingRow.box ); } // Create a "form-style" (same width for all columns) for ( int column = 0; column < 3; column++ ) { // Find max column width int maxWidth = 0; for ( final SettingRow[] settingGroup : settingGroups ) for ( final SettingRow settingRow : settingGroup ) maxWidth = Math.max( settingRow.box.getComponent( column ).getPreferredSize().width, maxWidth ); // Set same width for all labels for ( final SettingRow[] settingGroup : settingGroups ) for ( final SettingRow settingRow : settingGroup ) settingRow.box.getComponent( column ).setPreferredSize( new Dimension( maxWidth, settingRow.box.getComponent( column ).getPreferredSize().height ) ); } // Aliases tab is unique final JTextArea playerAliasesTextArea = new JTextArea( Settings.getString( Settings.KEY_SETTINGS_MISC_PLAYER_ALIASES ), 1, 1 ); final JTextArea mapAliasesTextArea = new JTextArea( Settings.getString( Settings.KEY_SETTINGS_MISC_MAP_ALIASES ), 1, 1 ); { final JPanel panel = new JPanel( new BorderLayout() ); panel.setBorder( BorderFactory.createEmptyBorder( 5, 5, 0, 5 ) ); Box box = Box.createVerticalBox(); box.add( new JLabel( Language.getText( "miscSettings.aliasInfo" ) ) ); box.add( new JLabel( Language.getText( "miscSettings.aliasInfo2" ) ) ); box.add( new JLabel( Language.getText( "miscSettings.aliasInfo3" ) ) ); panel.add( GuiUtils.wrapInPanel( box ), BorderLayout.NORTH ); box = Box.createHorizontalBox(); final JScrollPane playerAliasesScrollPane = new JScrollPane( playerAliasesTextArea ); playerAliasesScrollPane.setBorder( BorderFactory.createTitledBorder( Language.getText( "miscSettings.playerAliases" ) ) ); box.add( playerAliasesScrollPane ); final JScrollPane mapAliasesScrollPane = new JScrollPane( mapAliasesTextArea ); mapAliasesScrollPane.setBorder( BorderFactory.createTitledBorder( Language.getText( "miscSettings.mapAliases" ) ) ); box.add( mapAliasesScrollPane ); panel.add( box, BorderLayout.CENTER ); GuiUtils.addNewTab( SettingsTab.ALIASES.text, SettingsTab.ALIASES.icon, false, tabbedPane, panel, null ); if ( tabToSelect == SettingsTab.ALIASES ) tabbedPane.setSelectedIndex( tabbedPane.getTabCount() - 1 ); } // Pre-defined lists tab is unique final Map< PredefinedList, String > predefinedListCacheMap = new EnumMap< PredefinedList, String >( PredefinedList.class ); final JComboBox< PredefinedList > predefinedListComboBox = new JComboBox<>( PredefinedList.values() ); if ( initialPredefinedList != null ) predefinedListComboBox.setSelectedItem( initialPredefinedList ); predefinedListComboBox.setMaximumRowCount( predefinedListComboBox.getItemCount() ); // Display all values predefinedListComboBox.setRenderer( new BaseLabelListCellRenderer< PredefinedList >( 2 ) { @Override public Icon getIcon( final PredefinedList value ) { return value.icon; } } ); final JTextArea predefinedListTextArea = new JTextArea( 18, 1 ); // I set the rows count to 18 because Easynth LAF has big tabs and it wouldn't fit in 1 column... final ActionListener predefinedListActionListener; { final JPanel panel = new JPanel( new BorderLayout() ); panel.setBorder( BorderFactory.createEmptyBorder( 5, 5, 0, 5 ) ); final Box northBox = Box.createVerticalBox(); final JPanel chooserPanel = new JPanel(); chooserPanel.add( new JLabel( Language.getText( "miscSettings.selectPredefinedList" ) ) ); predefinedListActionListener = new ActionListener() { private PredefinedList previousPredefinedList; @Override public void actionPerformed( final ActionEvent event ) { if ( previousPredefinedList != null ) predefinedListCacheMap.put( previousPredefinedList, predefinedListTextArea.getText() ); final PredefinedList predefinedList = (PredefinedList) predefinedListComboBox.getSelectedItem(); // If it has been just edited, load the edited value... String predefinedListValue = predefinedListCacheMap.get( predefinedList ); if ( predefinedListValue == null ) predefinedListValue = Settings.getString( predefinedList.settingsKey ); predefinedListTextArea.setText( predefinedListValue ); predefinedListTextArea.setCaretPosition( 0 ); previousPredefinedList = predefinedList; } }; predefinedListActionListener.actionPerformed( null ); // Load the value of the selected pre-defined list predefinedListComboBox.addActionListener( predefinedListActionListener ); chooserPanel.add( predefinedListComboBox ); northBox.add( chooserPanel ); final JLabel infoLabel = new JLabel( Language.getText( "miscSettings.predefinedList.info" ) ); northBox.add( GuiUtils.wrapInPanel( infoLabel ) ); panel.add( northBox, BorderLayout.NORTH ); panel.add( new JScrollPane( predefinedListTextArea ), BorderLayout.CENTER ); final JPanel buttonsPanel = new JPanel( new GridLayout( 2, 1 ) ); final JButton sortButton = new JButton( Icons.SORT_ALPHABET ); GuiUtils.updateButtonText( sortButton, "miscSettings.predefinedListSortButton" ); sortButton.addActionListener( new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { final List< String > lineVector = new ArrayList< String >(); Settings.breakIntoLines( predefinedListTextArea.getText(), lineVector ); Collections.sort( lineVector ); predefinedListTextArea.setText( "" ); for ( int i = 0; i < lineVector.size(); i++ ) { if ( i > 0 ) predefinedListTextArea.append( "\n" ); predefinedListTextArea.append( lineVector.get( i ) ); } predefinedListTextArea.setCaretPosition( 0 ); } } ); buttonsPanel.add( sortButton ); final JButton restoreDefaultButton = new JButton(); GuiUtils.updateButtonText( restoreDefaultButton, "miscSettings.restoreDefault" ); restoreDefaultButton.addActionListener( new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { predefinedListTextArea.setText( Settings.getDefaultString( ( (PredefinedList) predefinedListComboBox.getSelectedItem() ).settingsKey ) ); predefinedListTextArea.setCaretPosition( 0 ); } } ); buttonsPanel.add( restoreDefaultButton ); panel.add( GuiUtils.wrapInPanel( buttonsPanel ), BorderLayout.EAST ); GuiUtils.addNewTab( SettingsTab.PREDEFINED_LISTS.text, SettingsTab.PREDEFINED_LISTS.icon, false, tabbedPane, panel, null ); if ( tabToSelect == SettingsTab.PREDEFINED_LISTS ) tabbedPane.setSelectedIndex( tabbedPane.getTabCount() - 1 ); } // Folders tab is unique final List< FolderRow > folderRowList = new ArrayList< FolderRow >(); { final Box tabBox = Box.createVerticalBox(); tabBox.setBorder( BorderFactory.createEmptyBorder( 5, 5, 0, 5 ) ); folderRowList.add( new FolderRow( "folderSettings.sc2InstallationFolder" , Settings.KEY_SETTINGS_FOLDER_SC2_INSTALLATION , false, null, null ) ); folderRowList.add( new FolderRow( "folderSettings.sc2AutoReplay" , Settings.KEY_SETTINGS_FOLDER_SC2_AUTO_REPLAY , true , null, null ) ); for ( int i = 2; i <= Settings.MAX_SC2_AUTOREP_FOLDERS; i++ ) folderRowList.add( new FolderRow( "folderSettings.sc2AutoReplay" , Settings.KEY_SETTINGS_FOLDER_SC2_AUTO_REPLAY , true , i , Settings.KEY_SETTINGS_FOLDER_ENABLE_EXTRA_SC2_AUTO_REPLAY ) ); folderRowList.add( new FolderRow( "folderSettings.sc2Maps" , Settings.KEY_SETTINGS_FOLDER_SC2_MAPS , false, null, null ) ); folderRowList.add( new FolderRow( "folderSettings.defaultFolder" , Settings.KEY_SETTINGS_FOLDER_DEFAULT_REPLAY , false, null, null ) ); folderRowList.add( new FolderRow( "folderSettings.replayAutoSaveFolder" , Settings.KEY_SETTINGS_FOLDER_REPLAY_AUTO_SAVE , false, null, null ) ); folderRowList.add( new FolderRow( "folderSettings.mousePrintOutputFolder", Settings.KEY_SETTINGS_FOLDER_MOUSE_PRINT_OUTPUT, false, null, null ) ); // Create a "form-style" (same width for all columns) int maxWidth = 0; for ( final FolderRow folderRow : folderRowList ) { tabBox.add( folderRow.getComponent() ); maxWidth = Math.max( folderRow.infoComponent.getPreferredSize().width, maxWidth ); } // Set same width for all labels for ( final FolderRow folderRow : folderRowList ) folderRow.infoComponent.setPreferredSize( new Dimension( maxWidth, folderRow.infoComponent.getPreferredSize().height ) ); GuiUtils.addNewTab( SettingsTab.FOLDERS.text, SettingsTab.FOLDERS.icon, false, tabbedPane, GuiUtils.wrapInPanel( tabBox ), null ); if ( tabToSelect == SettingsTab.FOLDERS ) tabbedPane.setSelectedIndex( tabbedPane.getTabCount() - 1 ); } // Sc2gears Database tab is unique final Holder< String > authorizationKeyHolder = new Holder< String >(); { final Box tabBox = Box.createVerticalBox(); JPanel row = new JPanel( new FlowLayout( FlowLayout.LEFT ) ); row.add( new JLabel( Language.getText( "miscSettings.sc2gearsDatabaseInfo" ) ) ); row.add( GeneralUtils.createLinkLabel( Language.getText( "miscSettings.sc2gearsDatabaseReadMore" ), Consts.URL_SC2GEARS_DATABASE ) ); tabBox.add( row ); row = new JPanel( new FlowLayout( FlowLayout.LEFT ) ); row.add( new JLabel( Language.getText( "miscSettings.sc2gearsDatabaseInfo2" ) ) ); tabBox.add( row ); tabBox.add( Box.createVerticalStrut( 10 ) ); row = new JPanel( new FlowLayout( FlowLayout.LEFT ) ); row.add( new JLabel( Language.getText( "miscSettings.authorizationKey" ) ) ); final JLabel authKeyLabel = new JLabel(); GuiUtils.changeFontToBold( authKeyLabel ); row.add( authKeyLabel ); tabBox.add( row ); tabBox.add( Box.createVerticalStrut( 10 ) ); row = new JPanel( new FlowLayout( FlowLayout.LEFT ) ); final StatusLabel keyStatusLabel = new StatusLabel(); final JButton editKeyButton = new JButton( Icons.LICENSE_KEY ); GuiUtils.updateButtonText( editKeyButton, "miscSettings.editKeyButton" ); final JButton checkKeyButton = new JButton( Icons.SERVER_NETWORK ); final JButton deleteKeyButton = new JButton( Icons.CROSS ); final Task< String > setKeyTask = new Task< String >() { @Override public void execute( final String authorizationKey ) { authorizationKeyHolder.value = authorizationKey; final boolean keySet = authorizationKey.length() > 0; authKeyLabel.setText( keySet ? authorizationKey : "<" + Language.getText( "miscSettings.notSet" ) + ">" ); deleteKeyButton.setEnabled( keySet ); checkKeyButton .setEnabled( keySet ); } }; setKeyTask.execute( Settings.getString( Settings.KEY_SETTINGS_MISC_AUTHORIZATION_KEY ) ); editKeyButton.addActionListener( new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { final BaseDialog editKeyDialog = new BaseDialog( MiscSettingsDialog.this, "miscSettings.editKeyDialog.title" , Icons.LICENSE_KEY ); editKeyDialog.setModal( true ); final Box box = Box.createVerticalBox(); box.setBorder( BorderFactory.createEmptyBorder( 15, 15, 5, 15 ) ); Box drow = Box.createHorizontalBox(); drow.add( new JLabel( Language.getText( "miscSettings.editKeyDialog.info" ) ) ); drow.add( Box.createHorizontalStrut( 4 ) ); drow.add( GeneralUtils.createLinkLabel( Language.getText( "miscSettings.editKeyDialog.sc2gearsDatabaseUserPage" ), Consts.URL_SC2GEARS_DATABASE_USER_PAGE ) ); box.add( drow ); box.add( Box.createVerticalStrut( 10 ) ); drow = Box.createHorizontalBox(); drow.add( new JLabel( Language.getText( "miscSettings.authorizationKey" ) ) ); final JTextField keyTextField = new JTextField( authorizationKeyHolder.value ); drow.add( keyTextField ); box.add( drow ); box.add( Box.createVerticalStrut( 5 ) ); final JPanel buttonsPanel = new JPanel(); final StatusLabel newKeyStatusLabel = new StatusLabel(); final JButton cancelButton = editKeyDialog.createCloseButton( "button.cancel" ); final JButton okButton = new JButton(); GuiUtils.updateButtonText( okButton, "button.ok" ); okButton.addActionListener( new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { final String newAuthorizationKey = keyTextField.getText(); if ( newAuthorizationKey.length() == 0 ) { // If key is not provided/deleted, no need to check it (must not check it) setKeyTask.execute( "" ); keyStatusLabel.clearMessage(); editKeyDialog.dispose(); return; } editKeyDialog.setDefaultCloseOperation( JDialog.DO_NOTHING_ON_CLOSE ); keyTextField.setEnabled( false ); okButton .setEnabled( false ); cancelButton.setEnabled( false ); newKeyStatusLabel.setProgressMessageKey( "miscSettings.checkingKey" ); // Start a new thread to not block the UI new NormalThread( "Key checker" ) { @Override public void run() { final Boolean valid = GeneralUtils.checkAuthorizationKey( newAuthorizationKey ); final String keyStatusLabelTextKey = valid == null ? "miscSettings.checkingFailed" : valid.booleanValue() ? "miscSettings.checkingValid" : "miscSettings.checkingInvalid"; if ( valid == null || !valid ) newKeyStatusLabel.setErrorMessageKey( keyStatusLabelTextKey ); else newKeyStatusLabel.setInfoMessageKey( keyStatusLabelTextKey ); if ( valid != null && valid.booleanValue() ) { setKeyTask .execute( newAuthorizationKey ); if ( valid == null || !valid ) keyStatusLabel.setErrorMessageKey( keyStatusLabelTextKey ); else keyStatusLabel.setInfoMessageKey( keyStatusLabelTextKey ); editKeyDialog.dispose(); } else { cancelButton.setEnabled( true ); okButton .setEnabled( true ); keyTextField.setEnabled( true ); editKeyDialog.setDefaultCloseOperation( JDialog.DISPOSE_ON_CLOSE ); } } }.start(); } } ); buttonsPanel.add( okButton ); buttonsPanel.add( cancelButton ); box.add( buttonsPanel ); box.add( GuiUtils.wrapInPanel( newKeyStatusLabel ) ); editKeyDialog.add( box ); editKeyDialog.packAndShow( keyTextField, false ); } } ); row.add( editKeyButton ); deleteKeyButton.setEnabled( authorizationKeyHolder.value.length() > 0 ); GuiUtils.updateButtonText( deleteKeyButton, "miscSettings.deleteKeyButton" ); deleteKeyButton.addActionListener( new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { setKeyTask.execute( "" ); keyStatusLabel.clearMessage(); } } ); row.add( deleteKeyButton ); checkKeyButton.setEnabled( authorizationKeyHolder.value.length() > 0 ); GuiUtils.updateButtonText( checkKeyButton, "miscSettings.checkKeyButton" ); checkKeyButton.addActionListener( new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { editKeyButton .setEnabled( false ); deleteKeyButton.setEnabled( false ); checkKeyButton .setEnabled( false ); keyStatusLabel.setProgressMessageKey( "miscSettings.checkingKey" ); // Start a new thread to not block the UI new NormalThread( "Key checker" ) { @Override public void run() { final Boolean valid = GeneralUtils.checkAuthorizationKey( authorizationKeyHolder.value ); if ( valid == null || !valid ) keyStatusLabel.setErrorMessageKey( valid == null ? "miscSettings.checkingFailed" : "miscSettings.checkingInvalid" ); else keyStatusLabel.setInfoMessageKey( "miscSettings.checkingValid" ); editKeyButton .setEnabled( true ); deleteKeyButton.setEnabled( true ); checkKeyButton .setEnabled( true ); } }.start(); } } ); row.add( checkKeyButton ); row.add( keyStatusLabel ); tabBox.add( row ); GuiUtils.addNewTab( SettingsTab.SC2GEARS_DATABASE.text, SettingsTab.SC2GEARS_DATABASE.icon, false, tabbedPane, GuiUtils.wrapInPanel( tabBox ), null ); if ( tabToSelect == SettingsTab.SC2GEARS_DATABASE ) tabbedPane.setSelectedIndex( tabbedPane.getTabCount() - 1 ); } // Custom replay sites tab is unique final Vector< ReplayUploadSite > customReplayUploadSiteVector = new Vector< ReplayUploadSite >( Settings.getCustomReplayUploadSiteList() ); final ActionListener customReplaySiteActionListener; { final JPanel panel = new JPanel( new BorderLayout() ); final Box northBox = Box.createVerticalBox(); JLabel infoLabel = new JLabel( Language.getText( "miscSettings.customReplaySitesInfo" ) ); GuiUtils.changeFontToBold( infoLabel ); northBox.add( GuiUtils.wrapInPanel( infoLabel ) ); final JCheckBox acknowledgeCheckBox = GuiUtils.createCheckBox( "miscSettings.customReplaySitesAcknowledge", Settings.KEY_SETTINGS_MISC_CUSTOM_REPLAY_SITES_ACKNOWLEDGED ); northBox.add( GuiUtils.wrapInPanel( acknowledgeCheckBox ) ); panel.add( northBox, BorderLayout.NORTH ); final JPanel editPanel = new JPanel( new BorderLayout() ); editPanel.setBorder( BorderFactory.createTitledBorder( Language.getText( "miscSettings.customReplaySitesBorderTitle" ) ) ); final JComboBox< ReplayUploadSite > customReplaySiteComboBox = new JComboBox<>( new CustomComboBoxModel<>( customReplayUploadSiteVector ) ); final JTextField displayNameTextField = new JTextField( 30 ); final JTextField homePageTextField = new JTextField( 30 ); final JLabel testHomePageLinkLabel = GeneralUtils.createLinkStyledLabel( Language.getText( "miscSettings.testHomePageLink" ) ); testHomePageLinkLabel.setIcon( Icons.APPLICATION_BROWSER ); final JTextField uploadUrlTextField = new JTextField( 30 ); final JButton deleteButton = new JButton( Icons.CROSS ); final String testHomePageLinkActiveText = testHomePageLinkLabel.getText(); // HTML text final Runnable updateTestHomePageLink = new Runnable() { @Override public void run() { final boolean uploadReplaySiteSelected = customReplaySiteComboBox.getSelectedIndex() >= 0; testHomePageLinkLabel.setText( acknowledgeCheckBox.isSelected() && uploadReplaySiteSelected ? testHomePageLinkActiveText : Language.getText( "miscSettings.testHomePageLink" ) ); } }; final Runnable updateFieldsButtons = new Runnable() { @Override public void run() { final boolean uploadReplaySiteSelected = customReplaySiteComboBox.getSelectedIndex() >= 0; displayNameTextField.setEnabled( uploadReplaySiteSelected ); homePageTextField .setEnabled( uploadReplaySiteSelected ); uploadUrlTextField .setEnabled( uploadReplaySiteSelected ); deleteButton .setEnabled( uploadReplaySiteSelected ); updateTestHomePageLink.run(); } }; customReplaySiteActionListener = new ActionListener() { private ReplayUploadSite previousReplayUploadSite; @Override public void actionPerformed( final ActionEvent event ) { if ( previousReplayUploadSite != null ) { previousReplayUploadSite.displayName = displayNameTextField.getText(); previousReplayUploadSite.homePage = homePageTextField .getText(); previousReplayUploadSite.uploadUrl = uploadUrlTextField .getText(); // Refresh the combo box (display name might have changed) ( (CustomComboBoxModel< ? >) customReplaySiteComboBox.getModel() ).fireContentsChanged( customReplaySiteComboBox ); } previousReplayUploadSite = (ReplayUploadSite) customReplaySiteComboBox.getSelectedItem(); displayNameTextField.setText( previousReplayUploadSite == null ? null : previousReplayUploadSite.displayName ); homePageTextField .setText( previousReplayUploadSite == null ? null : previousReplayUploadSite.homePage ); uploadUrlTextField .setText( previousReplayUploadSite == null ? null : previousReplayUploadSite.uploadUrl ); updateFieldsButtons.run(); } }; customReplaySiteComboBox.addActionListener( customReplaySiteActionListener ); JPanel wrapper = new JPanel(); wrapper.add( new JLabel( Language.getText( "miscSettings.selectCustomReplaySite" ) ) ); wrapper.add( customReplaySiteComboBox ); editPanel.add( wrapper, BorderLayout.NORTH ); final Box fieldsBox = Box.createVerticalBox(); Box row = Box.createHorizontalBox(); row.add( new JLabel( Language.getText( "miscSettings.displayName" ) ) ); row.add( displayNameTextField ); fieldsBox.add( row ); row = Box.createHorizontalBox(); row.add( new JLabel( Language.getText( "miscSettings.homePage" ) ) ); row.add( homePageTextField ); fieldsBox.add( row ); testHomePageLinkLabel.addMouseListener( new MouseAdapter() { public void mouseClicked( final MouseEvent event ) { if ( homePageTextField.isEnabled() && homePageTextField.getText().length() > 0 ) GeneralUtils.showURLInBrowser( homePageTextField.getText() ); }; } ); fieldsBox.add( GuiUtils.createRightAlignedInfoWrapperPanel( testHomePageLinkLabel, 0 ) ); row = Box.createHorizontalBox(); row.add( new JLabel( Language.getText( "miscSettings.uploadUrl" ) ) ); row.add( uploadUrlTextField ); fieldsBox.add( row ); final JLabel uploadUrlInfoLabel = new JLabel( Language.getText( "miscSettings.uploadUrlInfo" ), JLabel.RIGHT ); fieldsBox.add( GuiUtils.createRightAlignedInfoWrapperPanel( uploadUrlInfoLabel, 0 ) ); editPanel.add( fieldsBox, BorderLayout.CENTER ); GuiUtils.alignBox( fieldsBox, 2 ); final JPanel buttonsPanel = new JPanel( new GridLayout( 2, 1 ) ); final JButton addNewButton = new JButton( Icons.DOCUMENT ); GuiUtils.updateButtonText( addNewButton, "miscSettings.addNewButton" ); addNewButton.addActionListener( new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { final ReplayUploadSite replayUploadSite = new ReplayUploadSite(); replayUploadSite.displayName = Language.getText( "miscSettings.customReplaySiteDefaultName", customReplaySiteComboBox.getItemCount() + 1 ); customReplaySiteComboBox.addItem( replayUploadSite ); customReplaySiteComboBox.setSelectedIndex( customReplaySiteComboBox.getItemCount() - 1 ); updateFieldsButtons.run(); } } ); buttonsPanel.add( addNewButton ); GuiUtils.updateButtonText( deleteButton, "miscSettings.deleteButton" ); deleteButton.addActionListener( new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { customReplaySiteComboBox.removeItemAt( customReplaySiteComboBox.getSelectedIndex() ); updateFieldsButtons.run(); } } ); buttonsPanel.add( deleteButton ); editPanel.add( GuiUtils.wrapInPanel( buttonsPanel ), BorderLayout.EAST ); // Load the selected replay upload site (if there's any) customReplaySiteActionListener.actionPerformed( null ); final ActionListener acknowledgeActionListener = new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { final boolean acknowledged = acknowledgeCheckBox.isSelected(); GuiUtils.setComponentTreeEnabled( editPanel, acknowledged ); if ( acknowledged ) updateFieldsButtons.run(); else updateTestHomePageLink.run(); } }; acknowledgeActionListener.actionPerformed( null ); acknowledgeCheckBox.addActionListener( acknowledgeActionListener ); panel.add( editPanel, BorderLayout.CENTER ); GuiUtils.addNewTab( SettingsTab.CUSTOM_REPLAY_SITES.text, SettingsTab.CUSTOM_REPLAY_SITES.icon, false, tabbedPane, GuiUtils.wrapInPanel( panel ), null ); if ( tabToSelect == SettingsTab.CUSTOM_REPLAY_SITES ) tabbedPane.setSelectedIndex( tabbedPane.getTabCount() - 1 ); } getContentPane().add( tabbedPane, BorderLayout.CENTER ); final JPanel buttonsPanel = new JPanel(); buttonsPanel.setBorder( BorderFactory.createCompoundBorder( BorderFactory.createMatteBorder( 1, 0, 0, 0, new JLabel().getForeground() ), BorderFactory.createEmptyBorder( 0, 0, 5, 0 ) ) ); final JButton okButton = new JButton(); GuiUtils.updateButtonText( okButton, "button.ok" ); buttonsPanel.add( okButton ); final JButton okAndRunDiagnosticTestButton = new JButton( Icons.SYSTEM_MONITOR ); GuiUtils.updateButtonText( okAndRunDiagnosticTestButton, "miscSettings.okAndRunDiagnosticTestButton" ); buttonsPanel.add( okAndRunDiagnosticTestButton ); final JButton okAndStoreSettingsButton = new JButton( Icons.SERVER_NETWORK ); GuiUtils.updateButtonText( okAndStoreSettingsButton, "miscSettings.okAndStoreSettingsButton" ); buttonsPanel.add( okAndStoreSettingsButton ); final JButton cancelButton = createCloseButton( "button.cancel" ); buttonsPanel.add( cancelButton ); getContentPane().add( buttonsPanel, BorderLayout.SOUTH ); final ActionListener okActionListener = new ActionListener() { @Override public void actionPerformed( final ActionEvent event ) { for ( final SettingRow[] settingGroup : settingGroups ) for ( final SettingRow settingRow : settingGroup ) settingRow.storeSetting(); GeneralUtils.setToolTipDelays(); Language.applyDateTimeFormats(); if ( proxyConfigHolder.value != null ) { proxyConfigHolder.value.storeSettings(); // Apply new proxy config Sc2gears.applyProxyConfig(); } Settings.set( Settings.KEY_SETTINGS_MISC_PLAYER_ALIASES, playerAliasesTextArea.getText() ); Settings.set( Settings.KEY_SETTINGS_MISC_MAP_ALIASES , mapAliasesTextArea .getText() ); Settings.rebuildAliases(); // Cache the currently displayed pre-defined list predefinedListActionListener.actionPerformed( null ); for ( final Entry< PredefinedList, String > entry : predefinedListCacheMap.entrySet() ) Settings.set( entry.getKey().settingsKey, entry.getValue() ); Settings.rebuildPredefinedLists(); for ( final FolderRow folderRow : folderRowList ) folderRow.storeSetting(); // Store settings from Sc2gears Database tab Settings.set( Settings.KEY_SETTINGS_MISC_AUTHORIZATION_KEY, authorizationKeyHolder.value ); // Store the currently displayed custom replay site customReplaySiteActionListener.actionPerformed( null ); Settings.setCustomReplayUploadSiteList( customReplayUploadSiteVector ); // Recommended to restart the replay auto-saver: if file monitor is used, new auto-save folders have to be watched, // also detection method might have changed. MainFrame.INSTANCE.restartReplayAutoSaver(); dispose(); if ( event.getSource() == okAndRunDiagnosticTestButton ) new DiagnosticToolDialog(); else if ( event.getSource() == okAndStoreSettingsButton ) { MainFrame.INSTANCE.saveSettingsNow(); GeneralUtils.storeOtherFile( Settings.SETTINGS_FILE, Language.getText( "miscSettings.settingsFileComment" ), "miscSettings.storingSettings" ); } } }; okButton .addActionListener( okActionListener ); okAndRunDiagnosticTestButton.addActionListener( okActionListener ); okAndStoreSettingsButton .addActionListener( okActionListener ); // I want tab titles to start exactly under each other (at one vertical line). By default they are center-aligned... int maxWidth = 0; for ( int i = tabbedPane.getTabCount() - 1; i >= 0; i-- ) maxWidth = Math.max( maxWidth, tabbedPane.getTabComponentAt( i ).getPreferredSize().width ); for ( int i = tabbedPane.getTabCount() - 1; i >= 0; i-- ) tabbedPane.getTabComponentAt( i ).setPreferredSize( new Dimension( maxWidth, tabbedPane.getTabComponentAt( i ).getPreferredSize().height ) ); packAndShow( cancelButton, true ); } /** * Creates and returns a link label which opens the miscellaneous settings dialog as a child of the main frame, * and selects the specified tab. * @param tabToSelect tab to select * @param owner optional owner frame; it not provided the Main frame will be used * @return a link label which opens the miscellaneous settings dialog and selects the specified tab */ public static JLabel createLinkLabelToSettings( final SettingsTab tabToSelect ) { return createLinkLabelToSettings( tabToSelect, MainFrame.INSTANCE, null ); } /** * Creates and returns a link label which opens the miscellaneous settings dialog as a child of the main frame, * selects the Pre-defined lists tab and selects the specified pre-defined list. * @param initialPredefinedList initial pre-definied list to select * @return a link label which opens the miscellaneous settings dialog and selects the Pre-defined lists tab */ public static JLabel createLinkLabelToPredefinedListsSettings( final PredefinedList initialPredefinedList ) { return createLinkLabelToSettings( SettingsTab.PREDEFINED_LISTS, MainFrame.INSTANCE, initialPredefinedList ); } /** * Creates and returns a link label which opens the miscellaneous settings dialog and selects the specified tab. * @param tabToSelect tab to select * @param owner optional owner frame; it not provided the Main frame will be used * @return a link label which opens the miscellaneous settings dialog and selects the specified tab */ public static JLabel createLinkLabelToSettings( final SettingsTab tabToSelect, final Frame owner ) { return createLinkLabelToSettings( tabToSelect, owner, null ); } /** * Creates and returns a link label which opens the miscellaneous settings dialog and selects the specified tab. * @param tabToSelect tab to select * @param owner optional owner frame; it not provided the Main frame will be used * @param initialPredefinedList optional initial pre-definied list to select * @return a link label which opens the miscellaneous settings dialog and selects the specified tab */ public static JLabel createLinkLabelToSettings( final SettingsTab tabToSelect, final Frame owner, final PredefinedList initialPredefinedList ) { final JLabel settingsLabel = GeneralUtils.createLinkStyledLabel( Language.getText( "misc.settingsOf", tabToSelect.text ) ); settingsLabel.setIcon( tabToSelect.icon ); settingsLabel.addMouseListener( new MouseAdapter() { public void mousePressed( final MouseEvent event ) { new MiscSettingsDialog( owner == null ? MainFrame.INSTANCE : owner, tabToSelect, initialPredefinedList ); }; } ); return settingsLabel; } }