package de.lighti.components.batch; import java.awt.Component; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.io.IOException; import java.util.Enumeration; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.BorderFactory; import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JSplitPane; import javax.swing.JTextField; import javax.swing.UIManager; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import de.lighti.components.ProgressDialog; import de.lighti.components.map.MapComponent; import de.lighti.io.ChartCreator; import de.lighti.io.DataExporter; import de.lighti.io.DataImporter; import de.lighti.model.AppState; import de.lighti.model.Statics; import de.lighti.model.game.Player; public class BatchDialog extends JDialog { private static String escapeUrlAsFilename( String url ) { final StringBuffer sb = new StringBuffer(); // Apply the regex. final Matcher m = PATTERN.matcher( url ); while (m.find()) { m.appendReplacement( sb, // Convert matched character to percent-encoded. "%" + Integer.toHexString( m.group().charAt( 0 ) ).toUpperCase() ); } m.appendTail( sb ); final String encoded = sb.toString(); // Truncate the string. final int end = Math.min( encoded.length(), MAX_LENGTH ); return encoded.substring( 0, end ); } public static void main( String[] args ) { try { UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() ); } catch (final Exception e) { // Don't care } final BatchDialog d = new BatchDialog( null ); d.addWindowListener( new WindowAdapter() { @Override public void windowClosed( WindowEvent e ) { super.windowClosed( e ); System.exit( 0 ); } } ); d.setVisible( true ); } private JList<File> fileList; private CheckBoxList propertyList; private JButton okButton; private JTextField savePathField; /** * */ private static final long serialVersionUID = 7655122816807766787L; private static final Pattern PATTERN = Pattern.compile( "[^A-Za-z0-9_]" ); private static final int MAX_LENGTH = 127; public BatchDialog( JFrame parent ) { super( parent, Statics.BATCH_EXPORT ); setPreferredSize( new Dimension( 800, 600 ) ); setDefaultCloseOperation( DISPOSE_ON_CLOSE ); setModal( true ); final JSplitPane splitPane = new JSplitPane(); splitPane.setLeftComponent( createFilePanel() ); splitPane.setRightComponent( createPropertyOkButtonPanel() ); setContentPane( splitPane ); pack(); splitPane.setDividerLocation( 0.5 ); } private Component createFilePanel() { final JButton plusButton = new JButton( "+" ); plusButton.addActionListener( new ActionListener() { @Override public void actionPerformed( ActionEvent e ) { final JFileChooser chooser = new JFileChooser( new File( "." ) ); chooser.setMultiSelectionEnabled( true ); chooser.setFileFilter( DataImporter.FILE_FILTER ); final int returnVal = chooser.showOpenDialog( BatchDialog.this ); if (returnVal == JFileChooser.APPROVE_OPTION) { final DefaultListModel<File> model = (DefaultListModel<File>) getFileList().getModel(); for (final File f : chooser.getSelectedFiles()) { model.addElement( f ); } validateInput(); } } } ); final JButton minusButton = new JButton( "-" ); minusButton.addActionListener( new ActionListener() { @Override public void actionPerformed( ActionEvent e ) { final DefaultListModel<File> model = (DefaultListModel<File>) getFileList().getModel(); for (final File f : getFileList().getSelectedValuesList()) { model.removeElement( f ); } } } ); final JPanel filePanel = new JPanel(); filePanel.setLayout( new GridBagLayout() ); GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.BOTH; c.gridx = 0; c.gridy = 0; c.weighty = 1.0; c.weightx = 1.0; c.gridwidth = 2; c.insets = new Insets( 5, 5, 5, 5 ); filePanel.add( getFileList(), c ); c = new GridBagConstraints(); c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_END; c.gridx = 0; c.gridy = 1; c.weightx = 0.5; filePanel.add( plusButton, c ); c = new GridBagConstraints(); c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; c.gridx = 1; c.gridy = 1; c.weightx = 0.5; filePanel.add( minusButton, c ); return filePanel; } private JPanel createPropertyOkButtonPanel() { final JPanel propertyOkButtonPanel = new JPanel(); propertyOkButtonPanel.setLayout( new GridBagLayout() ); GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.BOTH; c.gridx = 0; c.gridy = 0; c.weighty = 1.0; c.weightx = 1.0; c.gridwidth = 1; c.insets = new Insets( 5, 5, 5, 5 ); propertyOkButtonPanel.add( getPropertyList(), c ); c = new GridBagConstraints(); c.fill = GridBagConstraints.BOTH; c.gridx = 0; c.gridy = 1; c.weighty = 0.0; c.weightx = 0.0; c.gridwidth = 1; c.insets = new Insets( 10, 10, 10, 10 ); propertyOkButtonPanel.add( createSavePathPanel(), c ); c = new GridBagConstraints(); c.fill = GridBagConstraints.VERTICAL; c.gridx = 0; c.gridy = 2; c.weighty = 0.0; c.weightx = 0.0; c.gridwidth = 1; c.insets = new Insets( 10, 10, 10, 10 ); propertyOkButtonPanel.add( getOkButton(), c ); return propertyOkButtonPanel; } private JPanel createSavePathPanel() { final JPanel savePathPanel = new JPanel(); final JLabel label = new JLabel( Statics.SAVE_TO ); final JTextField savePathField = getSavePathField(); final JButton button = new JButton( Statics.BROWSE ); button.addActionListener( new ActionListener() { @Override public void actionPerformed( ActionEvent evt ) { final JFileChooser chooser = new JFileChooser(); chooser.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY ); final int retVal = chooser.showSaveDialog( BatchDialog.this ); if (retVal == JFileChooser.APPROVE_OPTION) { savePathField.setText( chooser.getSelectedFile().getAbsolutePath() ); } } } ); savePathPanel.add( label ); savePathPanel.add( savePathField ); savePathPanel.add( button ); return savePathPanel; } private void export() { final File dir = new File( getSavePathField().getText() ); if (!dir.exists() || !dir.isDirectory()) { handleError( dir.getAbsolutePath() + " is not a writable directory" ); return; } final Enumeration<File> fileList = ((DefaultListModel<File>) getFileList().getModel()).elements(); final List<CheckBoxListEntry> properties = getPropertyList().getSelectedValuesList(); final ProgressDialog pd = new ProgressDialog( BatchDialog.this ); pd.setMaximum( 10 * properties.size() * ((DefaultListModel<File>) getFileList().getModel()).getSize() ); final Thread t = new Thread( new Runnable() { private void exportData( String header, String[][] data, String fileOut ) { final File file = new File( fileOut ); try { DataExporter.exportCSV( file, header, data ); } catch (final IOException e) { handleError( e.getLocalizedMessage() ); } } @Override public void run() { int progress = 0; while (fileList.hasMoreElements()) { final File f = fileList.nextElement(); final AppState state = new AppState(); DataImporter.parseReplayFile( state, null, f ); for (final CheckBoxListEntry entry : properties) { for (final Player p : state.getPlayers()) { final String fileOut = dir.getAbsolutePath() + "/" + f.getName().replace( ".dem", "" ) + "_" + entry.getValue() + "_" + escapeUrlAsFilename( p.getName() ) + ".csv"; String header; String[][] data; switch (entry.getValue()) { case MapComponent.CAT_MOVEMENT: header = "#tickms, x , y"; data = ChartCreator.createMoveLog( p.getName(), state ); break; case MapComponent.CAT_ZONES: header = "#tickms, zone"; data = ChartCreator.createZoneLog( p.getName(), state ); break; case MapComponent.CAT_ABILITIES: header = "#tickms, x, y, ability"; data = ChartCreator.createAbilityLog( p ); case MapComponent.CAT_ITEMS: header = "#tickms, x, y, item"; data = ChartCreator.createItemLog( p ); break; default: throw new RuntimeException( "Unknown property " + entry.getValue() ); } exportData( header, data, fileOut ); } progress++; pd.setValue( progress ); } } pd.setVisible( false ); } } ); t.start(); pd.setVisible( true ); } private JList<File> getFileList() { if (fileList == null) { fileList = new JList<File>( new DefaultListModel<File>() ); fileList.setBorder( BorderFactory.createLoweredBevelBorder() ); } return fileList; } private JButton getOkButton() { if (okButton == null) { okButton = new JButton( Statics.OK ); okButton.setEnabled( false ); okButton.addActionListener( new ActionListener() { @Override public void actionPerformed( ActionEvent e ) { export(); } } ); } return okButton; } private CheckBoxList getPropertyList() { if (propertyList == null) { propertyList = new CheckBoxList(); propertyList.setBorder( BorderFactory.createLoweredBevelBorder() ); ((DefaultListModel<CheckBoxListEntry>) propertyList.getModel()).addElement( new CheckBoxListEntry( MapComponent.CAT_MOVEMENT, false ) ); ((DefaultListModel<CheckBoxListEntry>) propertyList.getModel()).addElement( new CheckBoxListEntry( MapComponent.CAT_ZONES, false ) ); ((DefaultListModel<CheckBoxListEntry>) propertyList.getModel()).addElement( new CheckBoxListEntry( MapComponent.CAT_ABILITIES, false ) ); ((DefaultListModel<CheckBoxListEntry>) propertyList.getModel()).addElement( new CheckBoxListEntry( MapComponent.CAT_ITEMS, false ) ); propertyList.addPropertyChangeListener( new PropertyChangeListener() { @Override public void propertyChange( PropertyChangeEvent arg0 ) { validateInput(); } } ); } return propertyList; } private JTextField getSavePathField() { if (savePathField == null) { savePathField = new JTextField( new File( "." ).getAbsolutePath(), 20 ); savePathField.getDocument().addDocumentListener( new DocumentListener() { @Override public void changedUpdate( DocumentEvent e ) { validateInput(); } @Override public void insertUpdate( DocumentEvent e ) { } @Override public void removeUpdate( DocumentEvent e ) { } } ); } return savePathField; } private void handleError( String error ) { JOptionPane.showMessageDialog( BatchDialog.this, error, "An error has occured", JOptionPane.ERROR_MESSAGE ); } private void validateInput() { boolean ret = true; ret &= getFileList().getModel().getSize() > 0; ret &= !getPropertyList().getSelectedValuesList().isEmpty(); ret &= !getSavePathField().getText().isEmpty(); getOkButton().setEnabled( ret ); } }