/**
* Copyright (C) 2009-2014 Cars and Tracks Development Project (CTDP).
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package net.ctdp.rfdynhud.editor.util;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.text.JTextComponent;
import net.ctdp.rfdynhud.editor.RFDynHUDEditor;
import net.ctdp.rfdynhud.gamedata.GameFileSystem;
import net.ctdp.rfdynhud.gamedata.ModInfo;
import net.ctdp.rfdynhud.gamedata.SessionType;
public class SaveAsDialog extends JDialog implements ActionListener
{
private static final long serialVersionUID = 4097644328704959279L;
private static enum MainGroupItem
{
CONSTRUCT,
DIRECT,
;
}
private static enum Actions
{
CONSTRUCT,
DIRECT,
MOD,
SITUATION,
VEHICLE,
SESSION,
BROWSE,
CANCEL,
SAVE,
;
}
private static enum _Situation
{
All( null ),
SmallSessionMonitorView( "monitor_small" ),
FullscreenSessionMonitorView( "monitor_big" ),
Garage( "garage" ),
;
private static final int numItems = _Situation.values().length;
private final String string;
private _Situation( String string )
{
this.string = string;
}
}
private static enum _SessionType
{
Any( null ),
TestDay( SessionType.TEST_DAY.name() ),
Practice( SessionType.PRACTICE_WILDCARD ),
Practice1( SessionType.PRACTICE1.name() ),
Practice2( SessionType.PRACTICE2.name() ),
Practice3( SessionType.PRACTICE3.name() ),
Practice4( SessionType.PRACTICE4.name() ),
Qualifying( SessionType.QUALIFYING_WILDCARD ),
Qualifying1( SessionType.QUALIFYING1.name() ),
Qualifying2( SessionType.QUALIFYING2.name() ),
Qualifying3( SessionType.QUALIFYING3.name() ),
Qualifying4( SessionType.QUALIFYING4.name() ),
Warmup( SessionType.WARMUP.name() ),
Race( SessionType.RACE_WILDCARD ),
Race1( SessionType.RACE1.name() ),
Race2( SessionType.RACE2.name() ),
Race3( SessionType.RACE3.name() ),
Race4( SessionType.RACE4.name() ),
;
private static final int numItems = _SessionType.values().length;
private final String string;
private _SessionType( String string )
{
this.string = string;
}
}
private static final Color DISABLED_TEXT_COLOR = new JTextField().getDisabledTextColor();
private final RFDynHUDEditor editor;
private JRadioButton rdoConstruct = null;
private JRadioButton rdoDirect = null;
private JPanel constructFrame = null;
private JPanel directFrame = null;
private JLabel lblMod = null;
private JLabel lblSituation = null;
private JLabel lblVehicle = null;
private JLabel lblSession = null;
private JComboBox<String> cbxMod = null;
private ButtonGroup bgSituation = null;
private JRadioButton[] rdoSituation = null;
private JTextField tbxVehicle = null;
private ButtonGroup bgSession = null;
private JRadioButton[] rdoSession = null;
private JLabel lblFilename = null;
private JTextField tbxFilename = null;
private JButton btnBrowse = null;
private _Situation getSelectedSituation()
{
for ( int i = 0; i < rdoSituation.length; i++ )
{
if ( rdoSituation[i].isSelected() )
return ( _Situation.valueOf( rdoSituation[i].getText() ) );
}
return ( null );
}
private _SessionType getSelectedSession()
{
for ( int i = 0; i < rdoSession.length; i++ )
{
if ( rdoSession[i].isSelected() )
return ( _SessionType.valueOf( rdoSession[i].getText() ) );
}
return ( null );
}
private String constructFilename( boolean set )
{
String filename = "";
String mod = String.valueOf( cbxMod.getEditor().getItem() ).trim();
if ( !mod.equals( "" ) )
filename += mod + File.separator;
filename += "overlay";
_Situation situation = getSelectedSituation();
if ( situation != null )
{
if ( situation.string != null )
filename += "_" + situation.string;
}
String vehicle = tbxVehicle.getText().trim();
if ( !vehicle.equals( "" ) )
filename += "_" + vehicle;
_SessionType session = getSelectedSession();
if ( session != null )
{
if ( session.string != null )
filename += "_" + session.string;
}
filename += ".ini";
if ( set )
tbxFilename.setText( filename );
return ( filename );
}
private void onMainGroupSelectionChanged( MainGroupItem item )
{
boolean isConstruct = ( item == MainGroupItem.CONSTRUCT );
TitledBorder tbConstruct = new TitledBorder( "Construct" );
if ( !isConstruct )
tbConstruct.setTitleColor( DISABLED_TEXT_COLOR );
constructFrame.setBorder( tbConstruct );
lblMod.setEnabled( isConstruct );
lblSituation.setEnabled( isConstruct );
lblVehicle.setEnabled( isConstruct );
lblSession.setEnabled( isConstruct );
cbxMod.setEnabled( isConstruct );
for ( int i = 0; i < rdoSituation.length; i++ )
rdoSituation[i].setEnabled( isConstruct );
tbxVehicle.setEnabled( isConstruct );
for ( int i = 0; i < rdoSession.length; i++ )
rdoSession[i].setEnabled( isConstruct );
TitledBorder tbDirect = new TitledBorder( "Filename" );
if ( isConstruct )
tbDirect.setTitleColor( tbxFilename.getDisabledTextColor() );
directFrame.setBorder( tbDirect );
lblFilename.setEnabled( !isConstruct );
tbxFilename.setEnabled( !isConstruct );
btnBrowse.setEnabled( !isConstruct );
if ( isConstruct )
{
constructFilename( true );
}
}
private File parseSelectedFile( GameFileSystem fileSystem, boolean useFallback )
{
String filename = tbxFilename.getText().trim();
File file = null;
if ( !filename.equals( "" ) )
{
file = new File( filename );
if ( !file.isAbsolute() )
{
if ( !filename.startsWith( "/" ) && !filename.startsWith( "\\" ) )
filename = File.separator + filename;
file = new File( fileSystem.getConfigPath() + filename );
}
File path = file.getParentFile();
if ( path == null )
{
if ( useFallback )
{
path = fileSystem.getConfigFolder();
file = new File( path, file.getName() );
}
}
else if ( !path.exists() )
{
if ( useFallback )
{
path = fileSystem.getConfigFolder();
file = new File( path, file.getName() );
}
else
{
File path2 = path.getParentFile();
if ( ( path2 == null ) || !path2.exists() )
{
file = null;
}
}
}
}
else if ( useFallback )
{
file = new File( fileSystem.getConfigFolder(), "overlay.ini" );
}
if ( file != null )
{
if ( !file.getName().toLowerCase().endsWith( ".ini" ) )
file = new File( file.getAbsolutePath() + ".ini" );
try
{
file = file.getCanonicalFile();
}
catch ( IOException e )
{
file = file.getAbsoluteFile();
}
}
return ( file );
}
private boolean unparseFilename( GameFileSystem fileSystem, File file )
{
if ( file == null )
{
tbxFilename.setText( "" );
onMainGroupSelectionChanged( MainGroupItem.CONSTRUCT );
return ( false );
}
File folder = file.getParentFile();
if ( folder != null )
{
String path = folder.getAbsolutePath();
if ( path.toLowerCase().equals( fileSystem.getConfigPath().toLowerCase() ) )
path = "";
else if ( path.toLowerCase().startsWith( fileSystem.getConfigPath().toLowerCase() ) )
path = path.substring( fileSystem.getConfigPath().length() + 1 );
int p = path.lastIndexOf( File.separatorChar );
if ( p >= 0 )
path = path.substring( p + 1 );
String mod = path;
boolean found = false;
for ( int i = 0; !found && i < cbxMod.getItemCount(); i++ )
{
if ( cbxMod.getItemAt( i ).equalsIgnoreCase( mod ) )
{
cbxMod.setSelectedIndex( i );
found = true;
}
}
if ( !found )
cbxMod.getEditor().setItem( mod );
if ( !folder.exists() )
{
folder = null;
}
}
String filename = file.getName();
if ( !filename.toLowerCase().endsWith( ".ini" ) )
return ( false );
if ( !filename.startsWith( "overlay" ) )
return ( false );
if ( filename.length() != "overlay".length() + ".ini".length() )
{
filename = filename.substring( "overlay".length(), filename.length() - ".ini".length() );
int i = 0;
for ( _Situation situation : _Situation.values() )
{
if ( ( situation.string != null ) && filename.startsWith( "_" + situation.string ) )
{
rdoSituation[i].setSelected( true );
filename = filename.substring( 1 + situation.string.length() );
break;
}
i++;
}
i = 0;
for ( _SessionType session : _SessionType.values() )
{
if ( ( session.string != null ) && filename.endsWith( "_" + session.string ) )
{
rdoSession[i].setSelected( true );
filename = filename.substring( 0, filename.length() - 1 - session.string.length() );
break;
}
i++;
}
if ( filename.startsWith( "_" ) )
tbxVehicle.setText( filename.substring( 1 ) );
else
tbxVehicle.setText( filename );
}
if ( folder == null )
tbxFilename.setText( file.getName() );
else
tbxFilename.setText( folder + File.separator + file.getName() );
return ( true );
}
public void setSelectedFile( GameFileSystem fileSystem, File file )
{
if ( file == null )
{
rdoConstruct.setSelected( true );
onMainGroupSelectionChanged( MainGroupItem.CONSTRUCT );
tbxFilename.setText( "" );
}
else
{
File path = file.getParentFile();
if ( ( path == null ) || !path.exists() )
{
path = fileSystem.getConfigFolder();
file = new File( path, file.getName() );
}
if ( file.getAbsolutePath().toLowerCase().equals( fileSystem.getConfigPath().toLowerCase() ) )
tbxFilename.setText( "" );
else if ( file.getAbsolutePath().toLowerCase().startsWith( fileSystem.getConfigPath().toLowerCase() ) )
tbxFilename.setText( file.getAbsolutePath().substring( fileSystem.getConfigPath().length() + 1 ) );
else
tbxFilename.setText( file.getAbsolutePath() );
if ( unparseFilename( fileSystem, file ) )
{
rdoConstruct.setSelected( true );
onMainGroupSelectionChanged( MainGroupItem.CONSTRUCT );
}
else
{
rdoDirect.setSelected( true );
onMainGroupSelectionChanged( MainGroupItem.DIRECT );
}
}
}
public final File getSelectedFile( GameFileSystem fileSystem )
{
return ( parseSelectedFile( fileSystem, false ) );
}
private void browse( GameFileSystem fileSystem )
{
JFileChooser fc = new JFileChooser();
File file = parseSelectedFile( fileSystem, true );
if ( file != null )
{
fc.setCurrentDirectory( file.getParentFile() );
fc.setSelectedFile( file );
}
fc.setMultiSelectionEnabled( false );
fc.setFileSelectionMode( JFileChooser.FILES_ONLY );
fc.setFileFilter( new FileNameExtensionFilter( "ini files", "ini" ) );
if ( fc.showSaveDialog( this ) != JFileChooser.APPROVE_OPTION )
return;
if ( !fc.getSelectedFile().getName().toLowerCase().endsWith( ".ini" ) )
fc.setSelectedFile( new File( fc.getSelectedFile().getAbsolutePath() + ".ini" ) );
file = fc.getSelectedFile();
if ( file.getAbsolutePath().toLowerCase().equals( fileSystem.getConfigPath().toLowerCase() ) )
tbxFilename.setText( "" );
else if ( file.getAbsolutePath().toLowerCase().startsWith( fileSystem.getConfigPath().toLowerCase() ) )
tbxFilename.setText( file.getAbsolutePath().substring( fileSystem.getConfigPath().length() + 1 ) );
else
tbxFilename.setText( file.getAbsolutePath() );
}
private void cancel()
{
tbxFilename.setText( "" );
this.setVisible( false );
}
private void save( GameFileSystem fileSystem )
{
if ( tbxFilename.getText().trim().equals( "" ) )
return;
File file = getSelectedFile( fileSystem );
boolean doIt = true;
if ( file == null )
{
doIt = false;
}
else if ( file.exists() )
{
int result = JOptionPane.showConfirmDialog( this, "Do you want to overwrite the existing file \"" + file.getAbsolutePath() + "\"?", editor.getMainWindow().getTitle(), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE );
if ( result == JOptionPane.CANCEL_OPTION )
return;
if ( result == JOptionPane.NO_OPTION )
return;
}
if ( doIt )
{
//System.out.println( file );
this.setVisible( false );
}
}
private void onActionPerformed( Actions action )
{
switch ( action )
{
case CONSTRUCT:
if ( !lblMod.isEnabled() )
{
if ( !tbxFilename.getText().trim().equals( "" ) )
unparseFilename( RFDynHUDEditor.FILESYSTEM, new File( tbxFilename.getText().trim() ) );
onMainGroupSelectionChanged( MainGroupItem.CONSTRUCT );
}
break;
case DIRECT:
if ( !lblFilename.isEnabled() )
{
onMainGroupSelectionChanged( MainGroupItem.DIRECT );
}
break;
case MOD:
case SITUATION:
case VEHICLE:
case SESSION:
constructFilename( true );
break;
case BROWSE:
browse( RFDynHUDEditor.FILESYSTEM );
break;
case CANCEL:
cancel();
break;
case SAVE:
save( RFDynHUDEditor.FILESYSTEM );
break;
}
}
@Override
public void actionPerformed( ActionEvent e )
{
if ( e.getActionCommand() == null )
return;
onActionPerformed( Actions.valueOf( e.getActionCommand() ) );
}
private JPanel createConstructPanel( ModInfo modInfo )
{
int i = 0;
JPanel p0 = new JPanel( new BorderLayout() );
p0.setBorder( new TitledBorder( "Construct" ) );
JPanel p1 = new JPanel( new BorderLayout() );
p1.setBorder( new EmptyBorder( 0, 5, 5, 5 ) );
JPanel p2 = new JPanel( new BorderLayout( 5, 0 ) );
final int numRows = 1 + _Situation.numItems + 1 + _SessionType.numItems;
JPanel pl = new JPanel( new GridLayout( numRows, 1 ) );
lblMod = new JLabel( "Mod:" );
pl.add( lblMod );
lblSituation = new JLabel( "Situation:" );
pl.add( lblSituation );
for ( i = 0; i < _Situation.numItems - 1; i++ )
pl.add( Box.createVerticalGlue() );
lblVehicle = new JLabel( "Vehicle:" );
pl.add( lblVehicle );
lblSession = new JLabel( "Session:" );
pl.add( lblSession );
for ( i = 0; i < _SessionType.numItems - 1; i++ )
pl.add( Box.createVerticalGlue() );
p2.add( pl, BorderLayout.WEST );
JPanel pr = new JPanel( new GridLayout( numRows, 1 ) );
cbxMod = new JComboBox<String>( modInfo.getInstalledModNames() );
cbxMod.setEditable( true );
cbxMod.setSelectedIndex( -1 );
cbxMod.setActionCommand( Actions.MOD.name() );
cbxMod.addActionListener( this );
( (JTextComponent)cbxMod.getEditor().getEditorComponent() ).getDocument().addDocumentListener( new DocumentListener()
{
@Override
public void removeUpdate( DocumentEvent e )
{
onActionPerformed( Actions.MOD );
}
@Override
public void insertUpdate( DocumentEvent e )
{
onActionPerformed( Actions.MOD );
}
@Override
public void changedUpdate( DocumentEvent e )
{
onActionPerformed( Actions.MOD );
}
} );
pr.add( cbxMod );
bgSituation = new ButtonGroup();
rdoSituation = new JRadioButton[ _Situation.numItems ];
i = 0;
for ( _Situation s : _Situation.values() )
{
rdoSituation[i] = new JRadioButton( s.name(), i == 0 );
bgSituation.add( rdoSituation[i] );
rdoSituation[i].setActionCommand( Actions.SITUATION.name() );
rdoSituation[i].addActionListener( this );
pr.add( rdoSituation[i] );
i++;
}
tbxVehicle = new JTextField( "" );
tbxVehicle.setActionCommand( Actions.VEHICLE.name() );
tbxVehicle.addActionListener( this );
tbxVehicle.getDocument().addDocumentListener( new DocumentListener()
{
@Override
public void removeUpdate( DocumentEvent e )
{
onActionPerformed( Actions.VEHICLE );
}
@Override
public void insertUpdate( DocumentEvent e )
{
onActionPerformed( Actions.VEHICLE );
}
@Override
public void changedUpdate( DocumentEvent e )
{
onActionPerformed( Actions.VEHICLE );
}
} );
pr.add( tbxVehicle );
bgSession = new ButtonGroup();
rdoSession = new JRadioButton[ _SessionType.numItems ];
i = 0;
for ( _SessionType st : _SessionType.values() )
{
rdoSession[i] = new JRadioButton( st.name(), i == 0 );
bgSession.add( rdoSession[i] );
rdoSession[i].setActionCommand( Actions.SESSION.name() );
rdoSession[i].addActionListener( this );
pr.add( rdoSession[i] );
i++;
}
p2.add( pr, BorderLayout.CENTER );
p1.add( p2, BorderLayout.NORTH );
p1.add( new JPanel(), BorderLayout.CENTER );
p0.add( p1, BorderLayout.CENTER );
constructFrame = p0;
return ( p0 );
}
private JPanel createDirectPanel()
{
JPanel p0 = new JPanel( new BorderLayout() );
p0.setBorder( new TitledBorder( "Filename" ) );
JPanel p1 = new JPanel( new BorderLayout( 5, 0 ) );
p1.setBorder( new EmptyBorder( 0, 5, 5, 5 ) );
lblFilename = new JLabel( "Filename:" );
p1.add( lblFilename, BorderLayout.WEST );
tbxFilename = new JTextField( "" );
p1.add( tbxFilename, BorderLayout.CENTER );
btnBrowse = new JButton( "..." );
btnBrowse.setActionCommand( Actions.BROWSE.name() );
btnBrowse.addActionListener( this );
p1.add( btnBrowse, BorderLayout.EAST );
p0.add( p1, BorderLayout.CENTER );
directFrame = p0;
return ( p0 );
}
private JPanel createButtonsPanel()
{
JPanel p = new JPanel( new FlowLayout( FlowLayout.RIGHT ) );
JButton btnOk = new JButton( "Save" );
btnOk.setActionCommand( "SAVE" );
btnOk.addActionListener( this );
p.add( btnOk );
p.add( Box.createHorizontalStrut( 5 ) );
JButton btnCancel = new JButton( "Cancel" );
btnCancel.setActionCommand( "CANCEL" );
btnCancel.addActionListener( this );
p.add( btnCancel );
//p.add( Box.createHorizontalStrut( 5 ) );
return ( p );
}
public SaveAsDialog( RFDynHUDEditor editor, ModInfo modInfo )
{
super( editor.getMainWindow(), "Save As...", true );
this.editor = editor;
this.setDefaultCloseOperation( JDialog.DO_NOTHING_ON_CLOSE );
this.setSize( 640, 480 );
this.setLocationRelativeTo( editor.getMainWindow() );
getContentPane().setLayout( new BorderLayout() );
( (JPanel)getContentPane() ).setBorder( new EmptyBorder( 5, 5, 5, 5 ) );
ButtonGroup bgMain = new ButtonGroup();
JPanel center = new JPanel( new BorderLayout() );
rdoConstruct = new JRadioButton( "", true );
rdoConstruct.setActionCommand( "CONSTRUCT" );
rdoConstruct.addActionListener( this );
bgMain.add( rdoConstruct );
JPanel p = new JPanel( new BorderLayout() );
p.add( rdoConstruct, BorderLayout.NORTH );
center.add( p, BorderLayout.WEST );
center.add( createConstructPanel( modInfo ), BorderLayout.CENTER );
getContentPane().add( center, BorderLayout.CENTER );
JPanel footer = new JPanel( new BorderLayout() );
rdoDirect = new JRadioButton();
rdoDirect.setActionCommand( "DIRECT" );
rdoDirect.addActionListener( this );
bgMain.add( rdoDirect );
p = new JPanel( new BorderLayout() );
p.add( rdoDirect, BorderLayout.NORTH );
footer.add( p, BorderLayout.WEST );
p = new JPanel( new BorderLayout() );
p.add( createDirectPanel(), BorderLayout.NORTH );
p.add( createButtonsPanel(), BorderLayout.SOUTH );
footer.add( p, BorderLayout.CENTER );
getContentPane().add( footer, BorderLayout.SOUTH );
onMainGroupSelectionChanged( MainGroupItem.CONSTRUCT );
this.pack();
this.setSize( this.getWidth() * 2, this.getHeight() );
this.addWindowListener( new WindowAdapter()
{
@Override
public void windowClosing( WindowEvent e )
{
cancel();
}
} );
}
}