Added Preferences dialog
This commit is contained in:
parent
e7c3276541
commit
0aa6cc434d
7 changed files with 691 additions and 2 deletions
|
@ -8,6 +8,7 @@ Changelog
|
||||||
- Added --global-panic commandline arg to show mod devs typoed find tags
|
- Added --global-panic commandline arg to show mod devs typoed find tags
|
||||||
- Added commandline tips in readme_modders.txt
|
- Added commandline tips in readme_modders.txt
|
||||||
- Fixed sloppy parser Validate error about things not allowed at root
|
- Fixed sloppy parser Validate error about things not allowed at root
|
||||||
|
- Added a Preferences dialog as an alternative to editing modman.cfg
|
||||||
|
|
||||||
1.2:
|
1.2:
|
||||||
- Added a commandline interface
|
- Added a commandline interface
|
||||||
|
|
|
@ -57,7 +57,7 @@ public class SlipstreamConfig {
|
||||||
configComments += " ftl_dats_path - The path to FTL's resources folder. If invalid, you'll be prompted.\n";
|
configComments += " ftl_dats_path - The path to FTL's resources folder. If invalid, you'll be prompted.\n";
|
||||||
configComments += " never_run_ftl - If true, there will be no offer to run FTL after patching. Default: false.\n";
|
configComments += " never_run_ftl - If true, there will be no offer to run FTL after patching. Default: false.\n";
|
||||||
configComments += " update_catalog - If a number greater than 0, check for new mod descriptions every N days.\n";
|
configComments += " update_catalog - If a number greater than 0, check for new mod descriptions every N days.\n";
|
||||||
configComments += " update_app - If a number greater than 0, check for new app version every N days.\n";
|
configComments += " update_app - If a number greater than 0, check for newer app versions every N days.\n";
|
||||||
configComments += " use_default_ui - If true, no attempt will be made to resemble a native GUI. Default: false.\n";
|
configComments += " use_default_ui - If true, no attempt will be made to resemble a native GUI. Default: false.\n";
|
||||||
configComments += " remember_geometry - If true, window geometry will be saved on exit and restored on startup.\n";
|
configComments += " remember_geometry - If true, window geometry will be saved on exit and restored on startup.\n";
|
||||||
configComments += "\n";
|
configComments += "\n";
|
||||||
|
|
432
src/main/java/net/vhati/modmanager/ui/FieldEditorPanel.java
Normal file
432
src/main/java/net/vhati/modmanager/ui/FieldEditorPanel.java
Normal file
|
@ -0,0 +1,432 @@
|
||||||
|
package net.vhati.modmanager.ui;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.GridBagConstraints;
|
||||||
|
import java.awt.GridBagLayout;
|
||||||
|
import java.awt.Insets;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import javax.swing.Box;
|
||||||
|
import javax.swing.BoxLayout;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JCheckBox;
|
||||||
|
import javax.swing.JComboBox;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JSeparator;
|
||||||
|
import javax.swing.JSlider;
|
||||||
|
import javax.swing.JTextArea;
|
||||||
|
import javax.swing.JTextField;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.event.ChangeEvent;
|
||||||
|
import javax.swing.event.ChangeListener;
|
||||||
|
|
||||||
|
import net.vhati.modmanager.ui.RegexDocument;
|
||||||
|
|
||||||
|
|
||||||
|
public class FieldEditorPanel extends JPanel {
|
||||||
|
public enum ContentType { WRAPPED_LABEL, LABEL, STRING, INTEGER, BOOLEAN, SLIDER, COMBO, CHOOSER };
|
||||||
|
|
||||||
|
private Map<String, JTextArea> wrappedLabelMap = new HashMap<String, JTextArea>();
|
||||||
|
private Map<String, JLabel> labelMap = new HashMap<String, JLabel>();
|
||||||
|
private Map<String, JTextField> stringMap = new HashMap<String, JTextField>();
|
||||||
|
private Map<String, JTextField> intMap = new HashMap<String, JTextField>();
|
||||||
|
private Map<String, JCheckBox> boolMap = new HashMap<String, JCheckBox>();
|
||||||
|
private Map<String, JSlider> sliderMap = new HashMap<String, JSlider>();
|
||||||
|
private Map<String, JComboBox> comboMap = new HashMap<String, JComboBox>();
|
||||||
|
private Map<String, Chooser> chooserMap = new HashMap<String, Chooser>();
|
||||||
|
private Map<String, JLabel> reminderMap = new HashMap<String, JLabel>();
|
||||||
|
|
||||||
|
private GridBagConstraints gridC = new GridBagConstraints();
|
||||||
|
|
||||||
|
private Component nameStrut = Box.createHorizontalStrut(1);
|
||||||
|
private Component valueStrut = Box.createHorizontalStrut(120);
|
||||||
|
private Component reminderStrut = Box.createHorizontalStrut(90);
|
||||||
|
|
||||||
|
private boolean remindersVisible;
|
||||||
|
|
||||||
|
|
||||||
|
public FieldEditorPanel( boolean remindersVisible ) {
|
||||||
|
super( new GridBagLayout() );
|
||||||
|
this.remindersVisible = remindersVisible;
|
||||||
|
|
||||||
|
gridC.anchor = GridBagConstraints.WEST;
|
||||||
|
gridC.fill = GridBagConstraints.HORIZONTAL;
|
||||||
|
gridC.weightx = 0.0;
|
||||||
|
gridC.weighty = 0.0;
|
||||||
|
gridC.gridwidth = 1;
|
||||||
|
gridC.gridx = 0;
|
||||||
|
gridC.gridy = 0;
|
||||||
|
|
||||||
|
// No default width for col 0.
|
||||||
|
gridC.gridx = 0;
|
||||||
|
this.add( nameStrut, gridC );
|
||||||
|
gridC.gridx++;
|
||||||
|
this.add( valueStrut, gridC );
|
||||||
|
gridC.gridx++;
|
||||||
|
if ( remindersVisible ) {
|
||||||
|
this.add( reminderStrut, gridC );
|
||||||
|
gridC.gridy++;
|
||||||
|
}
|
||||||
|
|
||||||
|
gridC.insets = new Insets(2, 4, 2, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setNameWidth( int width ) {
|
||||||
|
nameStrut.setMinimumSize( new Dimension(width, 0) );
|
||||||
|
nameStrut.setPreferredSize( new Dimension(width, 0) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValueWidth( int width ) {
|
||||||
|
valueStrut.setMinimumSize( new Dimension(width, 0) );
|
||||||
|
valueStrut.setPreferredSize( new Dimension(width, 0) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReminderWidth( int width ) {
|
||||||
|
reminderStrut.setMinimumSize( new Dimension(width, 0) );
|
||||||
|
reminderStrut.setPreferredSize( new Dimension(width, 0) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs JComponents for a given type of value.
|
||||||
|
* A row consists of a static label, some JComponent,
|
||||||
|
* and a reminder label.
|
||||||
|
*
|
||||||
|
* The component and reminder will be accessable later
|
||||||
|
* via getter methods.
|
||||||
|
*/
|
||||||
|
public void addRow( String valueName, ContentType contentType ) {
|
||||||
|
gridC.fill = GridBagConstraints.HORIZONTAL;
|
||||||
|
gridC.gridwidth = 1;
|
||||||
|
gridC.weighty = 0.0;
|
||||||
|
gridC.gridx = 0;
|
||||||
|
this.add( new JLabel( valueName +":" ), gridC );
|
||||||
|
|
||||||
|
gridC.gridx++;
|
||||||
|
if ( contentType == ContentType.WRAPPED_LABEL ) {
|
||||||
|
gridC.anchor = GridBagConstraints.WEST;
|
||||||
|
JTextArea valueArea = new JTextArea();
|
||||||
|
valueArea.setBackground(null);
|
||||||
|
valueArea.setEditable( false );
|
||||||
|
valueArea.setBorder(null);
|
||||||
|
valueArea.setLineWrap( true );
|
||||||
|
valueArea.setWrapStyleWord( true );
|
||||||
|
valueArea.setFocusable( false );
|
||||||
|
valueArea.setFont( UIManager.getFont("Label.font") );
|
||||||
|
|
||||||
|
wrappedLabelMap.put( valueName, valueArea );
|
||||||
|
this.add( valueArea, gridC );
|
||||||
|
}
|
||||||
|
else if ( contentType == ContentType.LABEL ) {
|
||||||
|
gridC.anchor = GridBagConstraints.WEST;
|
||||||
|
JLabel valueLbl = new JLabel();
|
||||||
|
valueLbl.setHorizontalAlignment( SwingConstants.CENTER );
|
||||||
|
labelMap.put( valueName, valueLbl );
|
||||||
|
this.add( valueLbl, gridC );
|
||||||
|
}
|
||||||
|
else if ( contentType == ContentType.STRING ) {
|
||||||
|
gridC.anchor = GridBagConstraints.WEST;
|
||||||
|
JTextField valueField = new JTextField();
|
||||||
|
stringMap.put( valueName, valueField );
|
||||||
|
this.add( valueField, gridC );
|
||||||
|
}
|
||||||
|
else if ( contentType == ContentType.INTEGER ) {
|
||||||
|
gridC.anchor = GridBagConstraints.WEST;
|
||||||
|
JTextField valueField = new JTextField();
|
||||||
|
valueField.setHorizontalAlignment( JTextField.RIGHT );
|
||||||
|
valueField.setDocument( new RegexDocument("[0-9]*") );
|
||||||
|
intMap.put( valueName, valueField );
|
||||||
|
this.add( valueField, gridC );
|
||||||
|
}
|
||||||
|
else if ( contentType == ContentType.BOOLEAN ) {
|
||||||
|
gridC.anchor = GridBagConstraints.CENTER;
|
||||||
|
JCheckBox valueCheck = new JCheckBox();
|
||||||
|
valueCheck.setHorizontalAlignment( SwingConstants.CENTER );
|
||||||
|
boolMap.put( valueName, valueCheck );
|
||||||
|
this.add( valueCheck, gridC );
|
||||||
|
}
|
||||||
|
else if ( contentType == ContentType.SLIDER ) {
|
||||||
|
gridC.anchor = GridBagConstraints.CENTER;
|
||||||
|
JPanel panel = new JPanel();
|
||||||
|
panel.setLayout( new BoxLayout(panel, BoxLayout.X_AXIS) );
|
||||||
|
final JSlider valueSlider = new JSlider( JSlider.HORIZONTAL );
|
||||||
|
valueSlider.setPreferredSize( new Dimension(50, valueSlider.getPreferredSize().height) );
|
||||||
|
sliderMap.put( valueName, valueSlider );
|
||||||
|
panel.add(valueSlider);
|
||||||
|
final JTextField valueField = new JTextField(3);
|
||||||
|
valueField.setMaximumSize( valueField.getPreferredSize() );
|
||||||
|
valueField.setHorizontalAlignment( JTextField.RIGHT );
|
||||||
|
valueField.setEditable( false );
|
||||||
|
panel.add(valueField);
|
||||||
|
this.add( panel, gridC );
|
||||||
|
|
||||||
|
valueSlider.addChangeListener(new ChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void stateChanged(ChangeEvent e) {
|
||||||
|
valueField.setText( ""+valueSlider.getValue() );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if ( contentType == ContentType.COMBO ) {
|
||||||
|
gridC.anchor = GridBagConstraints.CENTER;
|
||||||
|
JComboBox valueCombo = new JComboBox();
|
||||||
|
valueCombo.setEditable(false);
|
||||||
|
comboMap.put( valueName, valueCombo );
|
||||||
|
this.add( valueCombo, gridC );
|
||||||
|
}
|
||||||
|
else if ( contentType == ContentType.CHOOSER ) {
|
||||||
|
gridC.anchor = GridBagConstraints.WEST;
|
||||||
|
JPanel panel = new JPanel();
|
||||||
|
panel.setLayout( new BoxLayout(panel, BoxLayout.X_AXIS) );
|
||||||
|
|
||||||
|
JTextField chooserField = new JTextField();
|
||||||
|
panel.add( chooserField );
|
||||||
|
panel.add( Box.createHorizontalStrut( 5 ) );
|
||||||
|
JButton chooserBtn = new JButton( "..." );
|
||||||
|
chooserBtn.setMargin( new Insets(1,2,1,2) );
|
||||||
|
panel.add( chooserBtn );
|
||||||
|
Chooser valueChooser = new Chooser( chooserField, chooserBtn );
|
||||||
|
chooserMap.put( valueName, valueChooser );
|
||||||
|
|
||||||
|
this.add( panel, gridC );
|
||||||
|
}
|
||||||
|
gridC.gridx++;
|
||||||
|
|
||||||
|
if ( remindersVisible ) {
|
||||||
|
gridC.anchor = GridBagConstraints.WEST;
|
||||||
|
JLabel valueReminder = new JLabel();
|
||||||
|
reminderMap.put( valueName, valueReminder );
|
||||||
|
this.add( valueReminder, gridC );
|
||||||
|
}
|
||||||
|
|
||||||
|
gridC.gridy++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTextRow( String text ) {
|
||||||
|
gridC.fill = GridBagConstraints.HORIZONTAL;
|
||||||
|
gridC.weighty = 0.0;
|
||||||
|
gridC.gridwidth = GridBagConstraints.REMAINDER;
|
||||||
|
gridC.gridx = 0;
|
||||||
|
|
||||||
|
gridC.anchor = GridBagConstraints.WEST;
|
||||||
|
JTextArea textArea = new JTextArea( text );
|
||||||
|
textArea.setBackground(null);
|
||||||
|
textArea.setEditable( false );
|
||||||
|
textArea.setBorder(null);
|
||||||
|
textArea.setLineWrap( true );
|
||||||
|
textArea.setWrapStyleWord( true );
|
||||||
|
textArea.setFocusable( false );
|
||||||
|
textArea.setFont( UIManager.getFont("Label.font") );
|
||||||
|
|
||||||
|
this.add( textArea, gridC );
|
||||||
|
gridC.gridy++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSeparatorRow() {
|
||||||
|
gridC.fill = GridBagConstraints.HORIZONTAL;
|
||||||
|
gridC.weighty = 0.0;
|
||||||
|
gridC.gridwidth = GridBagConstraints.REMAINDER;
|
||||||
|
gridC.gridx = 0;
|
||||||
|
|
||||||
|
JPanel panel = new JPanel();
|
||||||
|
panel.setLayout( new BoxLayout( panel, BoxLayout.Y_AXIS ) );
|
||||||
|
panel.add( Box.createVerticalStrut(10) );
|
||||||
|
JSeparator sep = new JSeparator();
|
||||||
|
sep.setPreferredSize( new Dimension(1, sep.getPreferredSize().height) );
|
||||||
|
panel.add( sep );
|
||||||
|
panel.add( Box.createVerticalStrut(10) );
|
||||||
|
|
||||||
|
this.add( panel, gridC );
|
||||||
|
gridC.gridy++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addBlankRow() {
|
||||||
|
gridC.fill = GridBagConstraints.NONE;
|
||||||
|
gridC.weighty = 0.0;
|
||||||
|
gridC.gridwidth = GridBagConstraints.REMAINDER;
|
||||||
|
gridC.gridx = 0;
|
||||||
|
|
||||||
|
this.add( Box.createVerticalStrut(12), gridC );
|
||||||
|
gridC.gridy++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addFillRow() {
|
||||||
|
gridC.fill = GridBagConstraints.VERTICAL;
|
||||||
|
gridC.weighty = 1.0;
|
||||||
|
gridC.gridwidth = GridBagConstraints.REMAINDER;
|
||||||
|
gridC.gridx = 0;
|
||||||
|
|
||||||
|
this.add( Box.createVerticalGlue(), gridC );
|
||||||
|
gridC.gridy++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setStringAndReminder( String valueName, String s ) {
|
||||||
|
JTextField valueField = stringMap.get( valueName );
|
||||||
|
if ( valueField != null ) valueField.setText(s);
|
||||||
|
if ( remindersVisible ) setReminder( valueName, s );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIntAndReminder( String valueName, int n ) {
|
||||||
|
setIntAndReminder( valueName, n, ""+n );
|
||||||
|
}
|
||||||
|
public void setIntAndReminder( String valueName, int n, String s ) {
|
||||||
|
JTextField valueField = intMap.get( valueName );
|
||||||
|
if ( valueField != null ) valueField.setText( ""+n );
|
||||||
|
if ( remindersVisible ) setReminder( valueName, s );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBoolAndReminder( String valueName, boolean b ) {
|
||||||
|
setBoolAndReminder( valueName, b, ""+b );
|
||||||
|
}
|
||||||
|
public void setBoolAndReminder( String valueName, boolean b, String s ) {
|
||||||
|
JCheckBox valueCheck = boolMap.get( valueName );
|
||||||
|
if ( valueCheck != null ) valueCheck.setSelected(b);
|
||||||
|
if ( remindersVisible ) setReminder( valueName, s );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSliderAndReminder( String valueName, int n ) {
|
||||||
|
setSliderAndReminder( valueName, n, ""+n );
|
||||||
|
}
|
||||||
|
public void setSliderAndReminder( String valueName, int n, String s ) {
|
||||||
|
JSlider valueSlider = sliderMap.get( valueName );
|
||||||
|
if ( valueSlider != null ) valueSlider.setValue(n);
|
||||||
|
if ( remindersVisible ) setReminder( valueName, s );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setComboAndReminder( String valueName, Object o ) {
|
||||||
|
setComboAndReminder( valueName, o, o.toString() );
|
||||||
|
}
|
||||||
|
public void setComboAndReminder( String valueName, Object o, String s ) {
|
||||||
|
JComboBox valueCombo = comboMap.get( valueName );
|
||||||
|
if ( valueCombo != null ) valueCombo.setSelectedItem(o);
|
||||||
|
if ( remindersVisible ) setReminder( valueName, s );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChooserAndReminder( String valueName, String s ) {
|
||||||
|
Chooser valueChooser = chooserMap.get( valueName );
|
||||||
|
if ( valueChooser != null ) valueChooser.getTextField().setText(s);
|
||||||
|
if ( remindersVisible ) setReminder( valueName, s );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReminder( String valueName, String s ) {
|
||||||
|
JLabel valueReminder = reminderMap.get( valueName );
|
||||||
|
if ( valueReminder != null ) valueReminder.setText( "( "+ s +" )" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public JTextArea getWrappedLabel( String valueName ) {
|
||||||
|
return wrappedLabelMap.get( valueName );
|
||||||
|
}
|
||||||
|
|
||||||
|
public JLabel getLabel( String valueName ) {
|
||||||
|
return labelMap.get( valueName );
|
||||||
|
}
|
||||||
|
|
||||||
|
public JTextField getString( String valueName ) {
|
||||||
|
return stringMap.get( valueName );
|
||||||
|
}
|
||||||
|
|
||||||
|
public JTextField getInt( String valueName ) {
|
||||||
|
return intMap.get( valueName );
|
||||||
|
}
|
||||||
|
|
||||||
|
public JCheckBox getBoolean( String valueName ) {
|
||||||
|
return boolMap.get( valueName );
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSlider getSlider( String valueName ) {
|
||||||
|
return sliderMap.get( valueName );
|
||||||
|
}
|
||||||
|
|
||||||
|
public JComboBox getCombo( String valueName ) {
|
||||||
|
return comboMap.get( valueName );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Chooser getChooser( String valueName ) {
|
||||||
|
return chooserMap.get( valueName );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
for ( JTextArea valueArea : wrappedLabelMap.values() )
|
||||||
|
valueArea.setText("");
|
||||||
|
|
||||||
|
for ( JLabel valueLbl : labelMap.values() )
|
||||||
|
valueLbl.setText("");
|
||||||
|
|
||||||
|
for ( JTextField valueField : stringMap.values() )
|
||||||
|
valueField.setText("");
|
||||||
|
|
||||||
|
for ( JTextField valueField : intMap.values() )
|
||||||
|
valueField.setText("");
|
||||||
|
|
||||||
|
for ( JCheckBox valueCheck : boolMap.values() )
|
||||||
|
valueCheck.setSelected(false);
|
||||||
|
|
||||||
|
for ( JSlider valueSlider : sliderMap.values() )
|
||||||
|
valueSlider.setValue(0);
|
||||||
|
|
||||||
|
for ( JComboBox valueCombo : comboMap.values() )
|
||||||
|
valueCombo.removeAllItems();
|
||||||
|
|
||||||
|
for ( Chooser valueChooser : chooserMap.values() )
|
||||||
|
valueChooser.getTextField().setText("");
|
||||||
|
|
||||||
|
for ( JLabel valueReminder : reminderMap.values() )
|
||||||
|
valueReminder.setText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeAll() {
|
||||||
|
labelMap.clear();
|
||||||
|
stringMap.clear();
|
||||||
|
intMap.clear();
|
||||||
|
boolMap.clear();
|
||||||
|
sliderMap.clear();
|
||||||
|
comboMap.clear();
|
||||||
|
reminderMap.clear();
|
||||||
|
super.removeAll();
|
||||||
|
gridC = new GridBagConstraints();
|
||||||
|
|
||||||
|
gridC.anchor = GridBagConstraints.WEST;
|
||||||
|
gridC.fill = GridBagConstraints.HORIZONTAL;
|
||||||
|
gridC.weightx = 0.0;
|
||||||
|
gridC.weighty = 0.0;
|
||||||
|
gridC.gridwidth = 1;
|
||||||
|
gridC.gridx = 0;
|
||||||
|
gridC.gridy = 0;
|
||||||
|
|
||||||
|
// No default width for col 0.
|
||||||
|
gridC.gridx = 0;
|
||||||
|
this.add( Box.createVerticalStrut(1), gridC );
|
||||||
|
gridC.gridx++;
|
||||||
|
this.add( valueStrut, gridC );
|
||||||
|
gridC.gridx++;
|
||||||
|
if ( remindersVisible ) {
|
||||||
|
this.add( reminderStrut, gridC );
|
||||||
|
gridC.gridy++;
|
||||||
|
}
|
||||||
|
|
||||||
|
gridC.insets = new Insets(2, 4, 2, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static class Chooser {
|
||||||
|
private JTextField textField;
|
||||||
|
private JButton button;
|
||||||
|
|
||||||
|
public Chooser( JTextField textField, JButton button ) {
|
||||||
|
this.textField = textField;
|
||||||
|
this.button = button;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JTextField getTextField() { return textField; }
|
||||||
|
public JButton getButton() { return button; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -84,6 +84,7 @@ import net.vhati.modmanager.ui.InertPanel;
|
||||||
import net.vhati.modmanager.ui.ModInfoArea;
|
import net.vhati.modmanager.ui.ModInfoArea;
|
||||||
import net.vhati.modmanager.ui.ModPatchDialog;
|
import net.vhati.modmanager.ui.ModPatchDialog;
|
||||||
import net.vhati.modmanager.ui.ModXMLSandbox;
|
import net.vhati.modmanager.ui.ModXMLSandbox;
|
||||||
|
import net.vhati.modmanager.ui.SlipstreamConfigDialog;
|
||||||
import net.vhati.modmanager.ui.Statusbar;
|
import net.vhati.modmanager.ui.Statusbar;
|
||||||
import net.vhati.modmanager.ui.StatusbarMouseListener;
|
import net.vhati.modmanager.ui.StatusbarMouseListener;
|
||||||
import net.vhati.modmanager.ui.TableRowTransferHandler;
|
import net.vhati.modmanager.ui.TableRowTransferHandler;
|
||||||
|
@ -131,6 +132,7 @@ public class ManagerFrame extends JFrame implements ActionListener, HashObserver
|
||||||
private JMenuItem rescanMenuItem;
|
private JMenuItem rescanMenuItem;
|
||||||
private JMenuItem extractDatsMenuItem;
|
private JMenuItem extractDatsMenuItem;
|
||||||
private JMenuItem sandboxMenuItem;
|
private JMenuItem sandboxMenuItem;
|
||||||
|
private JMenuItem configMenuItem;
|
||||||
private JMenuItem exitMenuItem;
|
private JMenuItem exitMenuItem;
|
||||||
private JMenu helpMenu;
|
private JMenu helpMenu;
|
||||||
private JMenuItem aboutMenuItem;
|
private JMenuItem aboutMenuItem;
|
||||||
|
@ -296,6 +298,7 @@ public class ManagerFrame extends JFrame implements ActionListener, HashObserver
|
||||||
log.error( String.format( "Error writing config to \"%s\".", appConfig.getConfigFile() ), f );
|
log.error( String.format( "Error writing config to \"%s\".", appConfig.getConfigFile() ), f );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
System.gc(); // Ward off an intermittent InterruptedException from exit()?
|
||||||
System.exit( 0 );
|
System.exit( 0 );
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -367,6 +370,10 @@ public class ManagerFrame extends JFrame implements ActionListener, HashObserver
|
||||||
sandboxMenuItem.addMouseListener( new StatusbarMouseListener( this, "Experiment with advanced mod syntax." ) );
|
sandboxMenuItem.addMouseListener( new StatusbarMouseListener( this, "Experiment with advanced mod syntax." ) );
|
||||||
sandboxMenuItem.addActionListener(this);
|
sandboxMenuItem.addActionListener(this);
|
||||||
fileMenu.add( sandboxMenuItem );
|
fileMenu.add( sandboxMenuItem );
|
||||||
|
configMenuItem = new JMenuItem( "Preferences..." );
|
||||||
|
configMenuItem.addMouseListener( new StatusbarMouseListener( this, "Edit preferences." ) );
|
||||||
|
configMenuItem.addActionListener(this);
|
||||||
|
fileMenu.add( configMenuItem );
|
||||||
fileMenu.add( new JSeparator() );
|
fileMenu.add( new JSeparator() );
|
||||||
exitMenuItem = new JMenuItem( "Exit" );
|
exitMenuItem = new JMenuItem( "Exit" );
|
||||||
exitMenuItem.addMouseListener( new StatusbarMouseListener( this, "Exit this application." ) );
|
exitMenuItem.addMouseListener( new StatusbarMouseListener( this, "Exit this application." ) );
|
||||||
|
@ -915,6 +922,7 @@ public class ManagerFrame extends JFrame implements ActionListener, HashObserver
|
||||||
extractDlg.setVisible( true );
|
extractDlg.setVisible( true );
|
||||||
}
|
}
|
||||||
else if ( source == sandboxMenuItem ) {
|
else if ( source == sandboxMenuItem ) {
|
||||||
|
setStatusText( "" );
|
||||||
File datsDir = new File( appConfig.getProperty( "ftl_dats_path" ) );
|
File datsDir = new File( appConfig.getProperty( "ftl_dats_path" ) );
|
||||||
File dataDatFile = new File( datsDir, "data.dat" );
|
File dataDatFile = new File( datsDir, "data.dat" );
|
||||||
|
|
||||||
|
@ -924,6 +932,15 @@ public class ManagerFrame extends JFrame implements ActionListener, HashObserver
|
||||||
sandboxFrame.setLocationRelativeTo( null );
|
sandboxFrame.setLocationRelativeTo( null );
|
||||||
sandboxFrame.setVisible( true );
|
sandboxFrame.setVisible( true );
|
||||||
}
|
}
|
||||||
|
else if ( source == configMenuItem ) {
|
||||||
|
setStatusText( "" );
|
||||||
|
|
||||||
|
SlipstreamConfigDialog configFrame = new SlipstreamConfigDialog( appConfig );
|
||||||
|
configFrame.addWindowListener( nerfListener );
|
||||||
|
//configFrame.setSize( 300, 400 );
|
||||||
|
configFrame.setLocationRelativeTo( null );
|
||||||
|
configFrame.setVisible( true );
|
||||||
|
}
|
||||||
else if ( source == exitMenuItem ) {
|
else if ( source == exitMenuItem ) {
|
||||||
setStatusText( "" );
|
setStatusText( "" );
|
||||||
exitApp();
|
exitApp();
|
||||||
|
@ -995,6 +1012,11 @@ public class ManagerFrame extends JFrame implements ActionListener, HashObserver
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles a main window's nerfed state as popups are opened/disposed.
|
||||||
|
*
|
||||||
|
* Requires: setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE ).
|
||||||
|
*/
|
||||||
private static class NerfListener extends WindowAdapter {
|
private static class NerfListener extends WindowAdapter {
|
||||||
private Nerfable nerfObj;
|
private Nerfable nerfObj;
|
||||||
|
|
||||||
|
@ -1007,7 +1029,7 @@ public class ManagerFrame extends JFrame implements ActionListener, HashObserver
|
||||||
nerfObj.setNerfed( true );
|
nerfObj.setNerfed( true );
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void windowClosing( WindowEvent e ) {
|
public void windowClosed( WindowEvent e ) {
|
||||||
nerfObj.setNerfed( false );
|
nerfObj.setNerfed( false );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,7 @@ public class ModXMLSandbox extends JFrame implements ActionListener {
|
||||||
|
|
||||||
public ModXMLSandbox( File dataDatFile ) {
|
public ModXMLSandbox( File dataDatFile ) {
|
||||||
super( "Mod XML Sandbox" );
|
super( "Mod XML Sandbox" );
|
||||||
|
this.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
|
||||||
|
|
||||||
this.dataDatFile = dataDatFile;
|
this.dataDatFile = dataDatFile;
|
||||||
|
|
||||||
|
|
62
src/main/java/net/vhati/modmanager/ui/RegexDocument.java
Normal file
62
src/main/java/net/vhati/modmanager/ui/RegexDocument.java
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
package net.vhati.modmanager.ui;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.regex.PatternSyntaxException;
|
||||||
|
import javax.swing.text.AttributeSet;
|
||||||
|
import javax.swing.text.BadLocationException;
|
||||||
|
import javax.swing.text.PlainDocument;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When applied to a JTextField via setDocument(), you can only enter a limited set of characters.
|
||||||
|
*/
|
||||||
|
public class RegexDocument extends PlainDocument {
|
||||||
|
private boolean dontCheck = false;
|
||||||
|
private Pattern p = null;
|
||||||
|
|
||||||
|
|
||||||
|
public RegexDocument( String regex ) {
|
||||||
|
if ( regex == null || regex.length()==0 ) dontCheck = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
p = Pattern.compile(regex);
|
||||||
|
} catch (PatternSyntaxException e) {dontCheck = true;}
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegexDocument() {
|
||||||
|
dontCheck = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insertString( int offs, String str, AttributeSet a ) throws BadLocationException {
|
||||||
|
if ( str == null ) return;
|
||||||
|
|
||||||
|
boolean proceed = true;
|
||||||
|
|
||||||
|
if ( dontCheck == false ) {
|
||||||
|
String tmp = super.getText(0, offs) + str + (super.getLength()>offs ? super.getText(offs,super.getLength()-offs) : "");
|
||||||
|
Matcher m = p.matcher(tmp);
|
||||||
|
proceed = m.matches();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( proceed == true ) super.insertString( offs, str, a );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove( int offs, int len ) throws BadLocationException {
|
||||||
|
boolean proceed = true;
|
||||||
|
|
||||||
|
if ( dontCheck == false ) {
|
||||||
|
try {
|
||||||
|
String tmp = super.getText(0, offs) + (super.getLength()>(offs+len) ? super.getText(offs+len, super.getLength()-(offs+len)) : "");
|
||||||
|
Matcher m = p.matcher(tmp);
|
||||||
|
proceed = m.matches();
|
||||||
|
} catch (BadLocationException f) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( proceed == true ) super.remove( offs, len );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,171 @@
|
||||||
|
package net.vhati.modmanager.ui;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.io.File;
|
||||||
|
import javax.swing.BorderFactory;
|
||||||
|
import javax.swing.Box;
|
||||||
|
import javax.swing.BoxLayout;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JCheckBox;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.JTextField;
|
||||||
|
import javax.swing.ScrollPaneConstants;
|
||||||
|
import javax.swing.event.AncestorEvent;
|
||||||
|
import javax.swing.event.AncestorListener;
|
||||||
|
|
||||||
|
import net.vhati.modmanager.core.FTLUtilities;
|
||||||
|
import net.vhati.modmanager.core.SlipstreamConfig;
|
||||||
|
import net.vhati.modmanager.ui.FieldEditorPanel;
|
||||||
|
import net.vhati.modmanager.ui.FieldEditorPanel.ContentType;
|
||||||
|
|
||||||
|
|
||||||
|
public class SlipstreamConfigDialog extends JFrame implements ActionListener {
|
||||||
|
protected static final String ALLOW_ZIP = "allow_zip";
|
||||||
|
protected static final String NEVER_RUN_FTL = "never_run_ftl";
|
||||||
|
protected static final String USE_DEFAULT_UI = "use_default_ui";
|
||||||
|
protected static final String REMEMBER_GEOMETRY = "remember_geometry";
|
||||||
|
protected static final String UPDATE_CATALOG = "update_catalog";
|
||||||
|
protected static final String UPDATE_APP = "update_app";
|
||||||
|
protected static final String FTL_DATS_PATH = "ftl_dats_path";
|
||||||
|
|
||||||
|
protected SlipstreamConfig appConfig;
|
||||||
|
|
||||||
|
protected FieldEditorPanel editorPanel;
|
||||||
|
protected JButton applyBtn;
|
||||||
|
|
||||||
|
|
||||||
|
public SlipstreamConfigDialog( SlipstreamConfig appConfig ) {
|
||||||
|
super( "Preferences..." );
|
||||||
|
this.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
|
||||||
|
|
||||||
|
this.appConfig = appConfig;
|
||||||
|
|
||||||
|
editorPanel = new FieldEditorPanel( false );
|
||||||
|
editorPanel.setBorder( BorderFactory.createEmptyBorder( 10, 10, 0, 10 ) );
|
||||||
|
editorPanel.setNameWidth( 250 );
|
||||||
|
editorPanel.addRow( ALLOW_ZIP, ContentType.BOOLEAN );
|
||||||
|
editorPanel.addTextRow( "Treat .zip files as .ftl files." );
|
||||||
|
editorPanel.addSeparatorRow();
|
||||||
|
editorPanel.addRow( NEVER_RUN_FTL, ContentType.BOOLEAN );
|
||||||
|
editorPanel.addTextRow( "Don't offer to run FTL after patching." );
|
||||||
|
editorPanel.addSeparatorRow();
|
||||||
|
editorPanel.addRow( USE_DEFAULT_UI, ContentType.BOOLEAN );
|
||||||
|
editorPanel.addTextRow( "Don't attempt to resemble a native GUI." );
|
||||||
|
editorPanel.addSeparatorRow();
|
||||||
|
editorPanel.addRow( REMEMBER_GEOMETRY, ContentType.BOOLEAN );
|
||||||
|
editorPanel.addTextRow( "Save window geometry on exit." );
|
||||||
|
editorPanel.addSeparatorRow();
|
||||||
|
editorPanel.addRow( UPDATE_CATALOG, ContentType.INTEGER );
|
||||||
|
editorPanel.addTextRow( "Check for new mod descriptions every N days. (0 to disable)" );
|
||||||
|
editorPanel.addSeparatorRow();
|
||||||
|
editorPanel.addRow( UPDATE_APP, ContentType.INTEGER );
|
||||||
|
editorPanel.addTextRow( "Check for newer app versions every N days. (0 to disable)" );
|
||||||
|
editorPanel.addSeparatorRow();
|
||||||
|
editorPanel.addRow( FTL_DATS_PATH, ContentType.CHOOSER );
|
||||||
|
editorPanel.addTextRow( "Path to FTL's resources folder." );
|
||||||
|
editorPanel.addSeparatorRow();
|
||||||
|
editorPanel.addBlankRow();
|
||||||
|
editorPanel.addTextRow( "Note: Some changes may have no immediate effect." );
|
||||||
|
editorPanel.addBlankRow();
|
||||||
|
editorPanel.addFillRow();
|
||||||
|
|
||||||
|
editorPanel.getBoolean( ALLOW_ZIP ).setSelected( appConfig.getProperty( ALLOW_ZIP, "false" ).equals( "true" ) );
|
||||||
|
editorPanel.getBoolean( NEVER_RUN_FTL ).setSelected( appConfig.getProperty( NEVER_RUN_FTL, "false" ).equals( "true" ) );
|
||||||
|
editorPanel.getBoolean( USE_DEFAULT_UI ).setSelected( appConfig.getProperty( USE_DEFAULT_UI, "false" ).equals( "true" ) );
|
||||||
|
editorPanel.getBoolean( REMEMBER_GEOMETRY ).setSelected( appConfig.getProperty( REMEMBER_GEOMETRY, "true" ).equals( "true" ) );
|
||||||
|
editorPanel.getInt( UPDATE_CATALOG ).setText( Integer.toString(appConfig.getPropertyAsInt( UPDATE_CATALOG, 0 )) );
|
||||||
|
editorPanel.getInt( UPDATE_APP ).setText( Integer.toString(appConfig.getPropertyAsInt( UPDATE_APP, 0 )) );
|
||||||
|
|
||||||
|
JTextField ftlDatsPathField = editorPanel.getChooser( FTL_DATS_PATH ).getTextField();
|
||||||
|
ftlDatsPathField.setText( appConfig.getProperty( FTL_DATS_PATH, "" ) );
|
||||||
|
ftlDatsPathField.setPreferredSize( new Dimension(150, ftlDatsPathField.getPreferredSize().height) );
|
||||||
|
editorPanel.getChooser( FTL_DATS_PATH ).getButton().addActionListener(this);
|
||||||
|
|
||||||
|
JPanel ctrlPanel = new JPanel();
|
||||||
|
ctrlPanel.setLayout( new BoxLayout( ctrlPanel, BoxLayout.X_AXIS ) );
|
||||||
|
ctrlPanel.setBorder( BorderFactory.createEmptyBorder( 10, 0, 10, 0 ) );
|
||||||
|
ctrlPanel.add( Box.createHorizontalGlue() );
|
||||||
|
applyBtn = new JButton( "Apply" );
|
||||||
|
applyBtn.addActionListener(this);
|
||||||
|
ctrlPanel.add( applyBtn );
|
||||||
|
ctrlPanel.add( Box.createHorizontalGlue() );
|
||||||
|
|
||||||
|
final JScrollPane editorScroll = new JScrollPane( editorPanel );
|
||||||
|
editorScroll.setVerticalScrollBarPolicy( ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS );
|
||||||
|
editorScroll.getVerticalScrollBar().setUnitIncrement( 10 );
|
||||||
|
int vbarWidth = editorScroll.getVerticalScrollBar().getPreferredSize().width;
|
||||||
|
editorScroll.setPreferredSize( new Dimension(editorPanel.getPreferredSize().width+vbarWidth+5, 400) );
|
||||||
|
|
||||||
|
JPanel contentPane = new JPanel( new BorderLayout() );
|
||||||
|
contentPane.add( editorScroll, BorderLayout.CENTER );
|
||||||
|
contentPane.add( ctrlPanel, BorderLayout.SOUTH );
|
||||||
|
this.setContentPane( contentPane );
|
||||||
|
this.pack();
|
||||||
|
this.setMinimumSize( new Dimension(250, 250) );
|
||||||
|
|
||||||
|
|
||||||
|
editorScroll.addAncestorListener(new AncestorListener() {
|
||||||
|
@Override
|
||||||
|
public void ancestorAdded( AncestorEvent e ) {
|
||||||
|
editorScroll.getViewport().setViewPosition( new Point(0, 0) );
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void ancestorMoved( AncestorEvent e ) {
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void ancestorRemoved( AncestorEvent e ) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed( ActionEvent e ) {
|
||||||
|
Object source = e.getSource();
|
||||||
|
|
||||||
|
if ( source == applyBtn ) {
|
||||||
|
String tmp;
|
||||||
|
appConfig.setProperty( ALLOW_ZIP, editorPanel.getBoolean( ALLOW_ZIP ).isSelected() ? "true" : "false" );
|
||||||
|
appConfig.setProperty( NEVER_RUN_FTL, editorPanel.getBoolean( NEVER_RUN_FTL ).isSelected() ? "true" : "false" );
|
||||||
|
appConfig.setProperty( USE_DEFAULT_UI, editorPanel.getBoolean( USE_DEFAULT_UI ).isSelected() ? "true" : "false" );
|
||||||
|
appConfig.setProperty( REMEMBER_GEOMETRY, editorPanel.getBoolean( REMEMBER_GEOMETRY ).isSelected() ? "true" : "false" );
|
||||||
|
|
||||||
|
tmp = editorPanel.getInt( UPDATE_CATALOG ).getText();
|
||||||
|
try {
|
||||||
|
int n = Integer.parseInt( tmp );
|
||||||
|
n = Math.max( 0, n );
|
||||||
|
appConfig.setProperty( UPDATE_CATALOG, Integer.toString( n ) );
|
||||||
|
}
|
||||||
|
catch ( NumberFormatException f ) {}
|
||||||
|
|
||||||
|
tmp = editorPanel.getInt( UPDATE_APP ).getText();
|
||||||
|
try {
|
||||||
|
int n = Integer.parseInt( tmp );
|
||||||
|
n = Math.max( 0, n );
|
||||||
|
appConfig.setProperty( UPDATE_APP, Integer.toString( n ) );
|
||||||
|
}
|
||||||
|
catch ( NumberFormatException f ) {}
|
||||||
|
|
||||||
|
tmp = editorPanel.getChooser( FTL_DATS_PATH ).getTextField().getText();
|
||||||
|
if ( tmp.length() > 0 && FTLUtilities.isDatsDirValid( new File(tmp) ) ) {
|
||||||
|
appConfig.setProperty( FTL_DATS_PATH, tmp );
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setVisible( false );
|
||||||
|
this.dispose();
|
||||||
|
}
|
||||||
|
else if ( source == editorPanel.getChooser( FTL_DATS_PATH ).getButton() ) {
|
||||||
|
File datsDir = FTLUtilities.promptForDatsDir( this );
|
||||||
|
if ( datsDir != null ) {
|
||||||
|
editorPanel.getChooser( FTL_DATS_PATH ).getTextField().setText( datsDir.getAbsolutePath() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue