]> git.xonotic.org Git - xonotic/xonotic.git/blobdiff - misc/tools/NexuizDemoRecorder/main/src/main/java/com/nexuiz/demorecorder/ui/swinggui/SwingGUI.java
fix lots of CRLFs
[xonotic/xonotic.git] / misc / tools / NexuizDemoRecorder / main / src / main / java / com / nexuiz / demorecorder / ui / swinggui / SwingGUI.java
index 7b1d8cc0fc4db0c84e0f8c6742002b65310d7309..bb662c7c4e4af2fb2cb13faa918b3d8bcb0974f8 100644 (file)
-package com.nexuiz.demorecorder.ui.swinggui;\r
-\r
-import java.awt.Container;\r
-import java.awt.Dimension;\r
-import java.awt.Point;\r
-import java.awt.event.ActionEvent;\r
-import java.awt.event.ActionListener;\r
-import java.awt.event.MouseEvent;\r
-import java.awt.event.MouseListener;\r
-import java.awt.event.WindowEvent;\r
-import java.awt.event.WindowListener;\r
-import java.io.File;\r
-import java.io.FileInputStream;\r
-import java.io.FileOutputStream;\r
-import java.io.IOException;\r
-import java.io.InputStream;\r
-import java.io.ObjectInputStream;\r
-import java.io.ObjectOutputStream;\r
-import java.net.URL;\r
-import java.util.ArrayList;\r
-import java.util.List;\r
-\r
-import javax.help.HelpBroker;\r
-import javax.help.HelpSet;\r
-import javax.swing.BorderFactory;\r
-import javax.swing.Icon;\r
-import javax.swing.ImageIcon;\r
-import javax.swing.JButton;\r
-import javax.swing.JFileChooser;\r
-import javax.swing.JFrame;\r
-import javax.swing.JMenu;\r
-import javax.swing.JMenuBar;\r
-import javax.swing.JMenuItem;\r
-import javax.swing.JOptionPane;\r
-import javax.swing.JPanel;\r
-import javax.swing.JPopupMenu;\r
-import javax.swing.JScrollPane;\r
-import javax.swing.JTable;\r
-import javax.swing.UIManager;\r
-import javax.swing.border.TitledBorder;\r
-\r
-import net.miginfocom.swing.MigLayout;\r
-\r
-import org.jdesktop.swingx.JXTable;\r
-\r
-import com.nexuiz.demorecorder.application.DemoRecorderApplication;\r
-import com.nexuiz.demorecorder.application.DemoRecorderUtils;\r
-import com.nexuiz.demorecorder.application.NDRPreferences;\r
-import com.nexuiz.demorecorder.application.DemoRecorderApplication.Preferences;\r
-import com.nexuiz.demorecorder.application.jobs.RecordJob;\r
-import com.nexuiz.demorecorder.application.jobs.RecordJob.State;\r
-import com.nexuiz.demorecorder.application.plugins.EncoderPlugin;\r
-import com.nexuiz.demorecorder.ui.DemoRecorderUI;\r
-import com.nexuiz.demorecorder.ui.swinggui.tablemodels.RecordJobTemplatesTableModel;\r
-import com.nexuiz.demorecorder.ui.swinggui.tablemodels.RecordJobsTableModel;\r
-import com.nexuiz.demorecorder.ui.swinggui.utils.ShowErrorDialogExceptionHandler;\r
-import com.nexuiz.demorecorder.ui.swinggui.utils.XProperties;\r
-import com.nexuiz.demorecorder.ui.swinggui.utils.XProperties.XTableState;\r
-\r
-public class SwingGUI extends JFrame implements WindowListener, DemoRecorderUI {\r
-       \r
-       private static final long serialVersionUID = -7287303462488231068L;\r
-       public static final String JOB_TABLE_PREFERENCES_FILENAME = "jobsTable.pref";\r
-       public static final String TEMPLATE_TABLE_PREFERENCES_FILENAME = "templatesTable.pref";\r
-       public static final String TEMPLATE_TABLE_CONTENT_FILENAME = "templates.dat";\r
-\r
-       private DemoRecorderApplication appLayer;\r
-       private PreferencesDialog preferencesDialog;\r
-       \r
-       private JXTable jobsTable = null;\r
-       private JPopupMenu jobsTablePopupMenu;\r
-       private ActionListener jobButtonActionListener = new JobButtonActionListener();\r
-       private MouseListener jobsTableMouseListener = new JobsTableMouseListener();\r
-       \r
-       private JXTable templatesTable = null;\r
-       private JPopupMenu templatesTablePopupMenu;\r
-       private ActionListener templateButtonActionListener = new TemplateButtonActionListener();\r
-       private MouseListener templatesTableMouseListener = new TemplatesTableMouseListener();\r
-       \r
-       private ActionListener recordButtonActionListener = new RecordButtonActionListener();\r
-       \r
-       private static final String LABEL_JOB_CREATE = "Create";\r
-       private static final String LABEL_JOB_CREATE_FROM_TEMPL = "Create from template";\r
-       private static final String LABEL_JOB_DELETE = "Delete";\r
-       private static final String LABEL_JOB_CLEAR = "Clear";\r
-       private static final String LABEL_JOB_EDIT = "Edit job";\r
-       private static final String LABEL_JOB_DUPLICATE = "Duplicate job";\r
-       private static final String LABEL_JOB_APPLYTEMPL = "Apply template";\r
-       private static final String LABEL_JOB_START = "Start job";\r
-       private static final String LABEL_JOB_SHOWERROR = "Show error message";\r
-       private static final String LABEL_JOB_RESET_STATE_WAITING = "Reset job status to 'waiting'";\r
-       private static final String LABEL_JOB_RESET_STATE_DONE = "Reset job status to 'done'";\r
-       \r
-       private static final String LABEL_TEMPL_CREATE = "Create";\r
-       private static final String LABEL_TEMPL_CREATE_FROM_JOB = "Create from job";\r
-       private static final String LABEL_TEMPL_DELETE = "Delete";\r
-       private static final String LABEL_TEMPL_CLEAR = "Clear";\r
-       private static final String LABEL_TEMPL_EDIT = "Edit template";\r
-       private static final String LABEL_TEMPL_DUPLICATE = "Duplicate template";\r
-       \r
-       private ActionListener menuButtonActionListener = new MenuButtonActionListener();\r
-       private JMenuItem fileLoadQueue = new JMenuItem("Load job queue", getIcon("fileopen.png"));\r
-       private JMenuItem fileSaveQueue = new JMenuItem("Save job queue", getIcon("filesave.png"));\r
-       private JMenuItem fileLoadTemplates = new JMenuItem("Load templates", getIcon("fileopen.png"));\r
-       private JMenuItem fileSaveTemplates = new JMenuItem("Save templates", getIcon("filesave.png"));\r
-       private JMenuItem filePreferences = new JMenuItem("Preferences", getIcon("advanced.png"));\r
-       private JMenuItem fileExit = new JMenuItem("Exit", getIcon("exit.png"));\r
-       private JMenuItem helpHelp = new JMenuItem("Show help", getIcon("help.png"));\r
-       private JMenuItem helpAbout = new JMenuItem("About", getIcon("info.png"));\r
-       private JFileChooser jobQueueSaveAsFC = new JFileChooser();\r
-       private JFileChooser templatesSaveAsFC = new JFileChooser();\r
-       \r
-       private JButton jobs_create = new JButton(LABEL_JOB_CREATE, getIcon("edit_add.png"));\r
-       private JButton jobs_createFromTempl = new JButton(LABEL_JOB_CREATE_FROM_TEMPL, getIcon("view_right_p.png"));\r
-       private JButton jobs_delete = new JButton(LABEL_JOB_DELETE, getIcon("editdelete.png"));\r
-       private JButton jobs_clear = new JButton(LABEL_JOB_CLEAR, getIcon("editclear.png"));\r
-       private JMenuItem jobs_contextmenu_edit = new JMenuItem(LABEL_JOB_EDIT, getIcon("edit.png"));\r
-       private JMenuItem jobs_contextmenu_duplicate = new JMenuItem(LABEL_JOB_DUPLICATE, getIcon("editcopy.png"));\r
-       private JMenuItem jobs_contextmenu_applytempl = new JMenuItem(LABEL_JOB_APPLYTEMPL, getIcon("editpaste.png"));\r
-       private JMenuItem jobs_contextmenu_delete = new JMenuItem(LABEL_JOB_DELETE, getIcon("editdelete.png"));\r
-       private JMenuItem jobs_contextmenu_start = new JMenuItem(LABEL_JOB_START, getIcon("player_play.png"));\r
-       private JMenuItem jobs_contextmenu_showerror = new JMenuItem(LABEL_JOB_SHOWERROR, getIcon("status_unknown.png"));\r
-       private JMenuItem jobs_contextmenu_resetstate_waiting = new JMenuItem(LABEL_JOB_RESET_STATE_WAITING, getIcon("quick_restart.png"));\r
-       private JMenuItem jobs_contextmenu_resetstate_done = new JMenuItem(LABEL_JOB_RESET_STATE_DONE, getIcon("quick_restart_blue.png"));\r
-       private List<JMenuItem> jobs_contextmenu_runPluginMenuItems = new ArrayList<JMenuItem>();\r
-       \r
-       private JButton templ_create = new JButton(LABEL_TEMPL_CREATE, getIcon("edit_add.png"));\r
-       private JButton templ_createFromJob = new JButton(LABEL_TEMPL_CREATE_FROM_JOB, getIcon("view_right_p.png"));\r
-       private JButton templ_delete = new JButton(LABEL_TEMPL_DELETE, getIcon("editdelete.png"));\r
-       private JButton templ_clear = new JButton(LABEL_TEMPL_CLEAR, getIcon("editclear.png"));\r
-       private JMenuItem templ_contextmenu_edit = new JMenuItem(LABEL_TEMPL_EDIT, getIcon("edit.png"));\r
-       private JMenuItem templ_contextmenu_duplicate = new JMenuItem(LABEL_TEMPL_DUPLICATE, getIcon("editcopy.png"));\r
-       private JMenuItem templ_contextmenu_delete = new JMenuItem(LABEL_TEMPL_DELETE, getIcon("editdelete.png"));\r
-       \r
-       private static final String PROCESSING_START = "Start processing";\r
-       private static final String PROCESSING_STOP_NOW = "Stop processing";\r
-       private static final String PROCESSING_STOP_LATER = "Processing will stop after current job finished";\r
-       private JButton processing_start = new JButton(PROCESSING_START, getIcon("player_play.png"));\r
-       private JButton processing_stop = new JButton(PROCESSING_STOP_NOW, getIcon("player_pause.png"));\r
-       \r
-       private StatusBar statusBar = new StatusBar();\r
-       \r
-       private static HelpBroker mainHelpBroker = null;\r
-       private static final String mainHelpSetName = "help/DemoRecorderHelp.hs";\r
-\r
-       public SwingGUI(DemoRecorderApplication appLayer) {\r
-               super("Nexuiz Demo Recorder v0.3");\r
-               addWindowListener(this);\r
-\r
-               this.appLayer = appLayer;\r
-\r
-               this.setupLayout();\r
-               this.setupHelp();\r
-               this.preferencesDialog = new PreferencesDialog(this, appLayer);\r
-\r
-               setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);\r
-               // Display the window.\r
-               pack();\r
-               setVisible(true);\r
-               //now that we have the GUI we can set the parent window for the error dialog\r
-               ShowErrorDialogExceptionHandler.setParentWindow(this);\r
-       }\r
-\r
-       private void setupHelp() {\r
-               if (mainHelpBroker == null){\r
-                       HelpSet mainHelpSet = null;\r
-\r
-                       try {\r
-                               URL hsURL = HelpSet.findHelpSet(null, mainHelpSetName);\r
-                               mainHelpSet = new HelpSet(null, hsURL);\r
-                       } catch (Exception e) {\r
-                               DemoRecorderUtils.showNonCriticalErrorDialog("Could not properly create the help", e, true);\r
-                       }\r
-\r
-                       if (mainHelpSet != null)\r
-                               mainHelpBroker = mainHelpSet.createHelpBroker();\r
-                       }\r
-       }\r
-\r
-       private void setupLayout() {\r
-               setLayout(new MigLayout("wrap 1,insets 10", "[400:700:,grow,fill]",\r
-                               "[grow,fill][grow,fill][][]"));\r
-               Container contentPane = getContentPane();\r
-               setJMenuBar(this.buildMenu());\r
-\r
-               this.setupTemplatePanel();\r
-               this.setupJobPanel();\r
-               this.setupRecordPanel();\r
-\r
-               contentPane.add(statusBar, "south,height 23::");\r
-       }\r
-\r
-       private void setupTemplatePanel() {\r
-               JPanel templatePanel = new JPanel(new MigLayout("", "[500:500:,grow,fill][170!,fill,grow]", "[grow,fill]"));\r
-               TitledBorder templatePanelTitle = BorderFactory.createTitledBorder("Templates");\r
-               templatePanel.setBorder(templatePanelTitle);\r
-               getContentPane().add(templatePanel);\r
-               \r
-               this.setupTemplatesTable();\r
-               this.loadTableStates(this.templatesTable);\r
-               JScrollPane templateScrollPane = new JScrollPane(templatesTable);\r
-               templatePanel.add(templateScrollPane);\r
-               \r
-               this.templ_create.addActionListener(this.templateButtonActionListener);\r
-               this.templ_createFromJob.addActionListener(this.templateButtonActionListener);\r
-               this.templ_delete.addActionListener(this.templateButtonActionListener);\r
-               this.templ_clear.addActionListener(this.templateButtonActionListener);\r
-               \r
-               this.templ_contextmenu_edit.addActionListener(this.templateButtonActionListener);\r
-               this.templ_contextmenu_duplicate.addActionListener(this.templateButtonActionListener);\r
-               this.templ_contextmenu_delete.addActionListener(this.templateButtonActionListener);\r
-               \r
-               this.configureTableButtons();\r
-               \r
-               JPanel templateControlButtonPanel = new JPanel(new MigLayout("wrap 1", "fill,grow"));\r
-               templateControlButtonPanel.add(this.templ_create);\r
-               templateControlButtonPanel.add(this.templ_createFromJob);\r
-               templateControlButtonPanel.add(this.templ_delete);\r
-               templateControlButtonPanel.add(this.templ_clear);\r
-               templatePanel.add(templateControlButtonPanel);\r
-       }\r
-\r
-       private void setupJobPanel() {\r
-               JPanel jobPanel = new JPanel(new MigLayout("", "[500:500:,grow,fill][170!,fill,grow]", "[grow,fill]"));\r
-               TitledBorder jobPanelTitle = BorderFactory.createTitledBorder("Jobs");\r
-               jobPanel.setBorder(jobPanelTitle);\r
-               getContentPane().add(jobPanel);\r
-\r
-               this.setupJobsTable();\r
-               this.loadTableStates(this.jobsTable);\r
-               \r
-               JScrollPane jobScrollPane = new JScrollPane(jobsTable);\r
-               jobPanel.add(jobScrollPane);\r
-               \r
-               this.jobs_create.addActionListener(this.jobButtonActionListener);\r
-               this.jobs_createFromTempl.addActionListener(this.jobButtonActionListener);\r
-               this.jobs_delete.addActionListener(this.jobButtonActionListener);\r
-               this.jobs_clear.addActionListener(this.jobButtonActionListener);\r
-               \r
-               this.jobs_contextmenu_edit.addActionListener(this.jobButtonActionListener);\r
-               this.jobs_contextmenu_duplicate.addActionListener(this.jobButtonActionListener);\r
-               this.jobs_contextmenu_applytempl.addActionListener(this.jobButtonActionListener);\r
-               this.jobs_contextmenu_delete.addActionListener(this.jobButtonActionListener);\r
-               this.jobs_contextmenu_start.addActionListener(this.jobButtonActionListener);\r
-               this.jobs_contextmenu_showerror.addActionListener(this.jobButtonActionListener);\r
-               this.jobs_contextmenu_resetstate_waiting.addActionListener(this.jobButtonActionListener);\r
-               this.jobs_contextmenu_resetstate_done.addActionListener(this.jobButtonActionListener);\r
-               \r
-               //initialize button states\r
-               configureTableButtons();\r
-               \r
-               JPanel jobControlButtonPanel = new JPanel(new MigLayout("wrap 1", "fill,grow"));\r
-               jobControlButtonPanel.add(this.jobs_create);\r
-               jobControlButtonPanel.add(this.jobs_createFromTempl);\r
-               jobControlButtonPanel.add(this.jobs_delete);\r
-               jobControlButtonPanel.add(this.jobs_clear);\r
-               jobPanel.add(jobControlButtonPanel);\r
-       }\r
-       \r
-       private void setupJobsTable() {\r
-               RecordJobsTableModel tableModel = new RecordJobsTableModel(this.appLayer);\r
-               jobsTable = new JXTable(tableModel);\r
-               jobsTable.setColumnControlVisible(true);\r
-               jobsTable.setPreferredScrollableViewportSize(new Dimension(400, 100));\r
-               jobsTable.addMouseListener(this.jobsTableMouseListener);\r
-       }\r
-       \r
-       private void setupTemplatesTable() {\r
-               RecordJobTemplatesTableModel tableModel = new RecordJobTemplatesTableModel();\r
-               templatesTable = new JXTable(tableModel);\r
-               templatesTable.setColumnControlVisible(true);\r
-               templatesTable.setPreferredScrollableViewportSize(new Dimension(400, 100));\r
-               templatesTable.addMouseListener(this.templatesTableMouseListener);\r
-       }\r
-\r
-       private void setupRecordPanel() {\r
-               JPanel recButtonPanel = new JPanel(new MigLayout());\r
-               recButtonPanel.add(processing_start);\r
-               recButtonPanel.add(processing_stop);\r
-               processing_stop.setEnabled(false);\r
-               processing_start.addActionListener(recordButtonActionListener);\r
-               processing_stop.addActionListener(recordButtonActionListener);\r
-               getContentPane().add(recButtonPanel);\r
-       }\r
-\r
-       public static void setSystemLAF() {\r
-               try {\r
-                       // Set System L&F\r
-                       UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());\r
-               } catch (Exception e) {\r
-               }\r
-       }\r
-       \r
-       public void RecordJobPropertiesChange(RecordJob job) {\r
-               RecordJobsTableModel jobsTableModel = (RecordJobsTableModel) this.jobsTable.getModel();\r
-               List<RecordJob> recordJobs = jobsTableModel.getRecordJobs();\r
-               int jobIndex = recordJobs.indexOf(job);\r
-               if (jobIndex == -1) {\r
-                       //new job\r
-                       recordJobs.add(job);\r
-                       //add job at the end of the table:\r
-                       int position = jobsTableModel.getRowCount() - 1;\r
-                       jobsTableModel.fireTableRowsInserted(position, position);\r
-               } else {\r
-                       //job already existed\r
-                       jobIndex = this.jobsTable.convertRowIndexToView(jobIndex); //convert due to possible view sorting\r
-                       jobsTableModel.fireTableRowsUpdated(jobIndex, jobIndex);\r
-               }\r
-       }\r
-\r
-       public void recordingFinished() {\r
-               JOptionPane.showMessageDialog(SwingGUI.this, "Finished recording all jobs", "Recording done", JOptionPane.INFORMATION_MESSAGE);\r
-               statusBar.showState(false);\r
-               processing_start.setEnabled(true);\r
-               processing_stop.setEnabled(false);\r
-               processing_stop.setText(PROCESSING_STOP_NOW);\r
-       }\r
-\r
-       private JMenuBar buildMenu() {\r
-               JMenuBar menuBar = new JMenuBar();\r
-\r
-               JMenu fileMenu = new JMenu("File");\r
-               fileMenu.add(fileLoadQueue);\r
-               fileMenu.add(fileSaveQueue);\r
-               fileMenu.add(fileLoadTemplates);\r
-               fileMenu.add(fileSaveTemplates);\r
-               fileMenu.add(filePreferences);\r
-               fileMenu.add(fileExit);\r
-               menuBar.add(fileMenu);\r
-               \r
-               fileLoadQueue.addActionListener(menuButtonActionListener);\r
-               fileSaveQueue.addActionListener(menuButtonActionListener);\r
-               fileLoadTemplates.addActionListener(menuButtonActionListener);\r
-               fileSaveTemplates.addActionListener(menuButtonActionListener);\r
-               filePreferences.addActionListener(menuButtonActionListener);\r
-               fileExit.addActionListener(menuButtonActionListener);\r
-\r
-               JMenu helpMenu = new JMenu("Help");\r
-               helpMenu.add(helpHelp);\r
-               helpMenu.add(helpAbout);\r
-               menuBar.add(helpMenu);\r
-               \r
-               helpHelp.addActionListener(menuButtonActionListener);\r
-               helpAbout.addActionListener(menuButtonActionListener);\r
-               \r
-               this.setupEncoderPluginButtons();\r
-               \r
-               this.jobsTablePopupMenu = new JPopupMenu();\r
-               this.jobsTablePopupMenu.add(jobs_contextmenu_edit);\r
-               this.jobsTablePopupMenu.add(jobs_contextmenu_duplicate);\r
-               this.jobsTablePopupMenu.add(jobs_contextmenu_applytempl);\r
-               this.jobsTablePopupMenu.add(jobs_contextmenu_delete);\r
-               this.jobsTablePopupMenu.add(jobs_contextmenu_start);\r
-               //add JMenus for plugins\r
-               for (JMenuItem menuItem : jobs_contextmenu_runPluginMenuItems) {\r
-                       this.jobsTablePopupMenu.add(menuItem);\r
-               }\r
-               this.jobsTablePopupMenu.add(jobs_contextmenu_showerror);\r
-               this.jobsTablePopupMenu.add(jobs_contextmenu_resetstate_waiting);\r
-               this.jobsTablePopupMenu.add(jobs_contextmenu_resetstate_done);\r
-               \r
-               \r
-               \r
-               \r
-               this.templatesTablePopupMenu = new JPopupMenu();\r
-               this.templatesTablePopupMenu.add(templ_contextmenu_edit);\r
-               this.templatesTablePopupMenu.add(templ_contextmenu_duplicate);\r
-               this.templatesTablePopupMenu.add(templ_contextmenu_delete);\r
-\r
-               return menuBar;\r
-       }\r
-       \r
-       private void setupEncoderPluginButtons() {\r
-               for (EncoderPlugin plugin : appLayer.getEncoderPlugins()) {\r
-                       JMenuItem pluginMenuItem = new JMenuItem("Just run " + plugin.getName() + " plugin", getIcon("package.png"));\r
-                       pluginMenuItem.addActionListener(jobButtonActionListener);\r
-                       this.jobs_contextmenu_runPluginMenuItems.add(pluginMenuItem);\r
-               }\r
-       }\r
-\r
-       private void saveTableStates(JXTable table) {\r
-               String fileName;\r
-               if (table == jobsTable) {\r
-                       fileName = JOB_TABLE_PREFERENCES_FILENAME;\r
-               } else {\r
-                       fileName = TEMPLATE_TABLE_PREFERENCES_FILENAME;\r
-               }\r
-               String exceptionMessage = "An error occurred while trying to save the table state file " + fileName;\r
-               \r
-               XProperties.XTableProperty t = new XProperties.XTableProperty();\r
-               XTableState tableState;\r
-               try {\r
-                       tableState = (XTableState) t.getSessionState(table);\r
-               } catch (Exception e) { //most likely ClassCastException\r
-                       DemoRecorderUtils.showNonCriticalErrorDialog(exceptionMessage, e, true);\r
-                       return;\r
-               }\r
-               \r
-               File tableStateFile = DemoRecorderUtils.computeLocalFile(DemoRecorderApplication.PREFERENCES_DIRNAME, fileName);\r
-               DemoRecorderUtils.attemptFileCreation(tableStateFile);\r
-               \r
-               try {\r
-                       FileOutputStream fout = new FileOutputStream(tableStateFile);\r
-                       ObjectOutputStream oos = new ObjectOutputStream(fout);\r
-                       oos.writeObject(tableState);\r
-                       oos.close();\r
-               } catch (Exception e) {\r
-                       DemoRecorderUtils.showNonCriticalErrorDialog(exceptionMessage, e, true);\r
-               }\r
-       }\r
-       \r
-       private void loadTableStates(JXTable table) {\r
-               String fileName;\r
-               if (table == jobsTable) {\r
-                       fileName = JOB_TABLE_PREFERENCES_FILENAME;\r
-               } else {\r
-                       fileName = TEMPLATE_TABLE_PREFERENCES_FILENAME;\r
-               }\r
-               \r
-               XProperties.XTableProperty t = new XProperties.XTableProperty();\r
-               \r
-               File tableStateFile = DemoRecorderUtils.computeLocalFile(DemoRecorderApplication.PREFERENCES_DIRNAME, fileName);\r
-               \r
-               XTableState tableState;\r
-               \r
-               try {\r
-                       FileInputStream fin = new FileInputStream(tableStateFile);\r
-                       ObjectInputStream ois = new ObjectInputStream(fin);\r
-                       tableState = (XTableState) ois.readObject();\r
-                       t.setSessionState(table, tableState);\r
-               } catch (Exception e) {\r
-                        //manually hide columns\r
-                       if (table == jobsTable) {\r
-                               //re-create table to be sure\r
-                               this.setupJobsTable();\r
-                               //manually hide some columns\r
-                               jobsTable.getColumnExt(RecordJobsTableModel.EXECUTE_AFTER_CAP).setVisible(false);\r
-                               jobsTable.getColumnExt(RecordJobsTableModel.EXECUTE_BEFORE_CAP).setVisible(false);\r
-                               jobsTable.getColumnExt(RecordJobsTableModel.VIDEO_DESTINATION_PATH).setVisible(false);\r
-                               jobsTable.getColumnExt(RecordJobsTableModel.DPVIDEO_PATH).setVisible(false);\r
-                               jobsTable.getColumnExt(RecordJobsTableModel.RELATIVE_DEMO_PATH).setVisible(false);\r
-                               jobsTable.getColumnExt(RecordJobsTableModel.ENGINE_PARAMETERS).setVisible(false);\r
-                               jobsTable.getColumnExt(RecordJobsTableModel.ENGINE_PATH).setVisible(false);\r
-                       } else {\r
-                               //re-create table to be sure\r
-                               this.setupTemplatesTable();\r
-                               //manually hide some columns\r
-                               templatesTable.getColumnExt(RecordJobTemplatesTableModel.EXECUTE_AFTER_CAP).setVisible(false);\r
-                               templatesTable.getColumnExt(RecordJobTemplatesTableModel.EXECUTE_BEFORE_CAP).setVisible(false);\r
-                               templatesTable.getColumnExt(RecordJobTemplatesTableModel.VIDEO_DESTINATION_PATH).setVisible(false);\r
-                               templatesTable.getColumnExt(RecordJobTemplatesTableModel.DPVIDEO_PATH).setVisible(false);\r
-                               templatesTable.getColumnExt(RecordJobTemplatesTableModel.RELATIVE_DEMO_PATH).setVisible(false);\r
-                               templatesTable.getColumnExt(RecordJobTemplatesTableModel.DEMO_FILE_PATH).setVisible(false);\r
-                               templatesTable.getColumnExt(RecordJobTemplatesTableModel.ENGINE_PARAMETERS).setVisible(false);\r
-                               templatesTable.getColumnExt(RecordJobTemplatesTableModel.ENGINE_PATH).setVisible(false);\r
-                               templatesTable.getColumnExt(RecordJobTemplatesTableModel.JOB_NAME).setVisible(false);\r
-                       }\r
-               }\r
-       }\r
-       \r
-       private class MenuButtonActionListener implements ActionListener {\r
-\r
-               public void actionPerformed(ActionEvent e) {\r
-                       if (e.getSource() == fileLoadQueue) {\r
-                               int result = jobQueueSaveAsFC.showOpenDialog(SwingGUI.this);\r
-                               if (result == JFileChooser.APPROVE_OPTION) {\r
-                                       File selectedFile = jobQueueSaveAsFC.getSelectedFile();\r
-                                       if (selectedFile.isFile()) {\r
-                                               RecordJobsTableModel tableModel = (RecordJobsTableModel) jobsTable.getModel();\r
-                                               tableModel.loadNewJobQueue(SwingGUI.this, selectedFile, jobsTable);\r
-                                               configureTableButtons();\r
-                                       }\r
-                               }\r
-                               \r
-                       } else if (e.getSource() == fileSaveQueue) {\r
-                               int result = jobQueueSaveAsFC.showSaveDialog(SwingGUI.this);\r
-                               if (result == JFileChooser.APPROVE_OPTION) {\r
-                                       File selectedFile = jobQueueSaveAsFC.getSelectedFile();\r
-                                       if (!DemoRecorderUtils.getFileExtension(selectedFile).equals("queue")) {\r
-                                               //if file is not a .queue file, make it one\r
-                                               selectedFile = new File(selectedFile.getAbsoluteFile() + ".queue");\r
-                                       }\r
-                                       if (selectedFile.exists()) {\r
-                                               int confirm = JOptionPane.showConfirmDialog(SwingGUI.this, "File already exists. Are you sure you want to overwrite it?", "Confirm overwrite", JOptionPane.YES_NO_OPTION);\r
-                                               if (confirm == JOptionPane.NO_OPTION) {\r
-                                                       return;\r
-                                               }\r
-                                       }\r
-                                       appLayer.saveJobQueue(selectedFile);\r
-                               }\r
-                       } else if (e.getSource() == fileLoadTemplates) {\r
-                               int result = templatesSaveAsFC.showOpenDialog(SwingGUI.this);\r
-                               if (result == JFileChooser.APPROVE_OPTION) {\r
-                                       File selectedFile = templatesSaveAsFC.getSelectedFile();\r
-                                       if (selectedFile.isFile()) {\r
-                                               RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) templatesTable.getModel();\r
-                                               tableModel.loadNewTemplateList(SwingGUI.this, selectedFile, templatesTable);\r
-                                               configureTableButtons();\r
-                                       }\r
-                               }\r
-                       } else if (e.getSource() == fileSaveTemplates) {\r
-                               int result = templatesSaveAsFC.showSaveDialog(SwingGUI.this);\r
-                               if (result == JFileChooser.APPROVE_OPTION) {\r
-                                       File selectedFile = templatesSaveAsFC.getSelectedFile();\r
-                                       if (!DemoRecorderUtils.getFileExtension(selectedFile).equals("templ")) {\r
-                                               selectedFile = new File(selectedFile.getAbsoluteFile() + ".templ");\r
-                                       }\r
-                                       if (selectedFile.exists()) {\r
-                                               int confirm = JOptionPane.showConfirmDialog(SwingGUI.this, "File already exists. Are you sure you want to overwrite it?", "Confirm overwrite", JOptionPane.YES_NO_OPTION);\r
-                                               if (confirm == JOptionPane.NO_OPTION) {\r
-                                                       return;\r
-                                               }\r
-                                       }\r
-                                       RecordJobTemplatesTableModel model = (RecordJobTemplatesTableModel) templatesTable.getModel();\r
-                                       model.saveTemplateListToFile(selectedFile);\r
-                               }\r
-                       } else if (e.getSource() == filePreferences) {\r
-                               preferencesDialog.showDialog();\r
-                       } else if (e.getSource() == fileExit) {\r
-                               shutDown();\r
-                       } else if (e.getSource() == helpHelp) {\r
-                               if (mainHelpBroker != null) {\r
-                                       mainHelpBroker.setDisplayed(true);\r
-                               }\r
-                       } else if (e.getSource() == helpAbout) {\r
-                               showAboutBox();\r
-                       }\r
-               }\r
-               \r
-       }\r
-\r
-       /**\r
-        * Listens to the clicks on buttons that are in the job panel (next to the jobs table)\r
-        * or its context menu.\r
-        */\r
-       private class JobButtonActionListener implements ActionListener {\r
-\r
-               public void actionPerformed(ActionEvent e) {\r
-                       List<RecordJob> selectedJobs = getSelectedRecordJobs(jobsTable);\r
-                       List<RecordJob> selectedTemplates = getSelectedRecordJobs(templatesTable);\r
-                       if (e.getSource() == jobs_create) {\r
-                               JobDialog jobDialog = new JobDialog(SwingGUI.this, appLayer);\r
-                               jobDialog.showDialog();\r
-                               configureTableButtons();\r
-                       }\r
-                       else if (e.getSource() == jobs_createFromTempl) {\r
-                               if (selectedTemplates.size() != 1) {\r
-                                       return;\r
-                               }\r
-                               RecordJobTemplate template = (RecordJobTemplate) selectedTemplates.get(0);\r
-//                             JobDialog jobDialog = new JobDialog(SwingGUI.this, template, appLayer);\r
-                               JobDialog jobDialog = new JobDialog(SwingGUI.this, template, appLayer, JobDialog.CREATE_JOB_FROM_TEMPLATE);\r
-                               jobDialog.showDialog();\r
-                               configureTableButtons();\r
-                       }\r
-                       else if (e.getSource() == jobs_delete || e.getSource() == jobs_contextmenu_delete) {\r
-                               int result = JOptionPane.showConfirmDialog(SwingGUI.this, "Are you sure you want to delete the selected job(s)?", "Confirm delete", JOptionPane.YES_NO_OPTION);\r
-                               if (result == JOptionPane.YES_OPTION) {\r
-                                       deleteSelectedJobs(false);\r
-                                       configureTableButtons();\r
-                               }\r
-                       }\r
-                       else if (e.getSource() == jobs_clear) {\r
-                               int result = JOptionPane.showConfirmDialog(SwingGUI.this, "Are you sure you want to clear the job list?", "Confirm clear", JOptionPane.YES_NO_OPTION);\r
-                               if (result == JOptionPane.YES_OPTION) {\r
-                                       deleteSelectedJobs(true);\r
-                                       configureTableButtons();\r
-                               }\r
-                       } else if (e.getSource() == jobs_contextmenu_edit) {\r
-                               if (selectedJobs.size() == 1) {\r
-                                       RecordJob selectedJob = selectedJobs.get(0);\r
-                                       JobDialog jobDialog = new JobDialog(SwingGUI.this, selectedJob, appLayer);\r
-                                       jobDialog.showDialog();\r
-                                       configureTableButtons();\r
-                               }\r
-                       } else if (e.getSource() == jobs_contextmenu_showerror) {\r
-                               if (selectedJobs.size() == 1) {\r
-                                       RecordJob selectedJob = selectedJobs.get(0);\r
-                                       DemoRecorderUtils.showNonCriticalErrorDialog(selectedJob.getLastException());\r
-                               }\r
-                       } else if (e.getSource() == jobs_contextmenu_resetstate_waiting) {\r
-                               for (RecordJob job : selectedJobs) {\r
-                                       job.setState(RecordJob.State.WAITING);\r
-                               }\r
-                       } else if (e.getSource() == jobs_contextmenu_resetstate_done) {\r
-                               for (RecordJob job : selectedJobs) {\r
-                                       if (job.getState() == State.ERROR_PLUGIN) {\r
-                                               job.setState(RecordJob.State.DONE);\r
-                                       }\r
-                               }\r
-                       } else if (e.getSource() == jobs_contextmenu_start) {\r
-                               appLayer.recordSelectedJobs(selectedJobs);\r
-                               if (appLayer.getState() == DemoRecorderApplication.STATE_WORKING) {\r
-                                       processing_start.setEnabled(false);\r
-                                       processing_stop.setEnabled(true);\r
-                                       statusBar.showState(true);\r
-                               }\r
-                       } else if (e.getSource() == jobs_contextmenu_duplicate) {\r
-                               if (selectedJobs.size() > 0) {\r
-                                       this.duplicateRecordJobs(selectedJobs);\r
-                                       //select all new duplicates in the table automatically\r
-                                       jobsTable.setRowSelectionInterval(jobsTable.getRowCount() - selectedJobs.size(), jobsTable.getRowCount() - 1);\r
-                                       configureTableButtons();\r
-                               }\r
-                       } else if (e.getSource() == jobs_contextmenu_applytempl) {\r
-                               if (selectedTemplates.size() == 1 && selectedJobs.size() > 0) {\r
-                                       RecordJobTemplate template = (RecordJobTemplate) selectedTemplates.get(0);\r
-                                       ApplyTemplateDialog applyDialog = new ApplyTemplateDialog(SwingGUI.this, template, selectedJobs);\r
-                                       applyDialog.showDialog();\r
-                               }\r
-                       } else if (jobs_contextmenu_runPluginMenuItems.contains(e.getSource())) {\r
-                               int index = jobs_contextmenu_runPluginMenuItems.indexOf(e.getSource());\r
-                               EncoderPlugin selectedPlugin = appLayer.getEncoderPlugins().get(index);\r
-                               \r
-                               appLayer.executePluginForSelectedJobs(selectedPlugin, selectedJobs);\r
-                               if (appLayer.getState() == DemoRecorderApplication.STATE_WORKING) {\r
-                                       processing_start.setEnabled(false);\r
-                                       processing_stop.setEnabled(true);\r
-                                       statusBar.showState(true);\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               private void duplicateRecordJobs(List<RecordJob> jobs) {\r
-                       String nameSuffix = appLayer.getPreferences().getProperty(NDRPreferences.MAIN_APPLICATION, Preferences.JOB_NAME_APPEND_DUPLICATE);\r
-                       for (RecordJob job : jobs) {\r
-                               RecordJob newJob = appLayer.createRecordJob(\r
-                                       job.getJobName() + nameSuffix,\r
-                                       job.getEnginePath(),\r
-                                       job.getEngineParameters(),\r
-                                       job.getDemoFile(),\r
-                                       job.getRelativeDemoPath(),\r
-                                       job.getDpVideoPath(),\r
-                                       job.getVideoDestination(),\r
-                                       job.getExecuteBeforeCap(),\r
-                                       job.getExecuteAfterCap(),\r
-                                       job.getStartSecond(),\r
-                                       job.getEndSecond()\r
-                               );\r
-                               newJob.setEncoderPluginSettings(job.getEncoderPluginSettings());\r
-                       }\r
-               }\r
-               \r
-       }\r
-       \r
-       private class TemplateButtonActionListener implements ActionListener {\r
-               public void actionPerformed(ActionEvent e) {\r
-                       if (e.getSource() == templ_create) {\r
-                               RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) templatesTable.getModel();\r
-                               JobDialog jobDialog = new JobDialog(SwingGUI.this, tableModel, templatesTable, appLayer);\r
-                               jobDialog.showDialog();\r
-                               configureTableButtons();\r
-                       }\r
-                       else if (e.getSource() == templ_createFromJob) {\r
-                               this.createTemplateFromJob();\r
-                               configureTableButtons();\r
-                       }\r
-                       else if (e.getSource() == templ_delete || e.getSource() == templ_contextmenu_delete) {\r
-                               int result = JOptionPane.showConfirmDialog(SwingGUI.this, "Are you sure you want to delete the selected template(s)?", "Confirm delete", JOptionPane.YES_NO_OPTION);\r
-                               if (result == JOptionPane.YES_OPTION) {\r
-                                       deleteSelectedTemplates(false);\r
-                               }\r
-                               configureTableButtons();\r
-                       }\r
-                       else if (e.getSource() == templ_clear) {\r
-                               int result = JOptionPane.showConfirmDialog(SwingGUI.this, "Are you sure you want to clear the template list?", "Confirm clear", JOptionPane.YES_NO_OPTION);\r
-                               if (result == JOptionPane.YES_OPTION) {\r
-                                       deleteSelectedTemplates(true);\r
-                               }\r
-                               configureTableButtons();\r
-                       }\r
-                       else if (e.getSource() == templ_contextmenu_edit) {\r
-                               List<RecordJob> selectedTemplates = getSelectedRecordJobs(templatesTable);\r
-                               if (selectedTemplates.size() == 1) {\r
-                                       RecordJobTemplate selectedTemplate = (RecordJobTemplate) selectedTemplates.get(0);\r
-                                       JobDialog jobDialog = new JobDialog(SwingGUI.this, selectedTemplate, appLayer, JobDialog.EDIT_TEMPLATE);\r
-                                       jobDialog.showDialog();\r
-                                       configureTableButtons();\r
-                               }\r
-                       }\r
-                       else if (e.getSource() == templ_contextmenu_duplicate) {\r
-                               List<RecordJob> selectedTemplates = getSelectedRecordJobs(templatesTable);\r
-                               if (selectedTemplates.size() > 0) {\r
-                                       this.duplicateTemplates(selectedTemplates);\r
-                                       //select all new duplicates in the table automatically\r
-                                       templatesTable.setRowSelectionInterval(templatesTable.getRowCount() - selectedTemplates.size(), templatesTable.getRowCount() - 1);\r
-                                       configureTableButtons();\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               private void createTemplateFromJob() {\r
-                       List<RecordJob> selectedJobs = getSelectedRecordJobs(jobsTable);\r
-                       if (selectedJobs.size() == 1) {\r
-                               RecordJob job = selectedJobs.get(0);\r
-                               RecordJobTemplate templ = new RecordJobTemplate(\r
-                                       "Generated from job",\r
-                                       "Generated from job",\r
-                                       job.getJobName(),\r
-                                       job.getEnginePath(),\r
-                                       job.getEngineParameters(),\r
-                                       job.getDemoFile().getParentFile(),\r
-                                       job.getRelativeDemoPath(),\r
-                                       job.getDpVideoPath(),\r
-                                       job.getVideoDestination().getParentFile(),\r
-                                       job.getExecuteBeforeCap(),\r
-                                       job.getExecuteAfterCap()\r
-                               );\r
-                               templ.setEncoderPluginSettings(job.getEncoderPluginSettings());\r
-                               \r
-                               RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) templatesTable.getModel();\r
-                               tableModel.addRecordJobTemplate(templ);\r
-                       }\r
-               }\r
-               \r
-               private void duplicateTemplates(List<RecordJob> selectedTemplates) {\r
-                       for (RecordJob job : selectedTemplates) {\r
-                               RecordJobTemplate template = (RecordJobTemplate) job;\r
-                               RecordJobTemplate templ = new RecordJobTemplate(\r
-                                       template.getName(),\r
-                                       template.getSummary(),\r
-                                       template.getJobName(),\r
-                                       template.getEnginePath(),\r
-                                       template.getEngineParameters(),\r
-                                       template.getDemoFile(),\r
-                                       template.getRelativeDemoPath(),\r
-                                       template.getDpVideoPath(),\r
-                                       template.getVideoDestination(),\r
-                                       template.getExecuteBeforeCap(),\r
-                                       template.getExecuteAfterCap()\r
-                               );\r
-                               templ.setEncoderPluginSettings(template.getEncoderPluginSettings());\r
-                               \r
-                               RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) templatesTable.getModel();\r
-                               tableModel.addRecordJobTemplate(templ);\r
-                       }\r
-               }\r
-       }\r
-       \r
-       private class RecordButtonActionListener implements ActionListener {\r
-\r
-               public void actionPerformed(ActionEvent e) {\r
-                       if (e.getSource() == processing_start) {\r
-                               appLayer.startRecording();\r
-                               if (appLayer.getState() == DemoRecorderApplication.STATE_WORKING) {\r
-                                       processing_start.setEnabled(false);\r
-                                       processing_stop.setEnabled(true);\r
-                                       statusBar.showState(true);\r
-                               }\r
-                       } else if (e.getSource() == processing_stop) {\r
-                               if (appLayer.getState() == DemoRecorderApplication.STATE_WORKING) {\r
-                                       appLayer.stopRecording();\r
-                                       processing_stop.setEnabled(false);\r
-                                       processing_stop.setText(PROCESSING_STOP_LATER);\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       \r
-       private void deleteSelectedJobs(boolean deleteAllJobs) {\r
-               RecordJobsTableModel tableModel = (RecordJobsTableModel) jobsTable.getModel();\r
-               if (deleteAllJobs) {\r
-                       int rowCount = jobsTable.getRowCount();\r
-                       for (int i = rowCount - 1; i >= 0; i--) {\r
-                               int modelRowIndex = jobsTable.convertRowIndexToModel(i);\r
-                               tableModel.deleteRecordJob(modelRowIndex, i);\r
-                       }\r
-               } else {\r
-                       int[] selectedRows = jobsTable.getSelectedRows();\r
-                       for (int i = selectedRows.length - 1; i >= 0; i--) {\r
-                               int modelRowIndex = jobsTable.convertRowIndexToModel(selectedRows[i]);\r
-                               tableModel.deleteRecordJob(modelRowIndex, selectedRows[i]);\r
-                       }\r
-               }\r
-       }\r
-       \r
-       private void deleteSelectedTemplates(boolean deleteAllTemplates) {\r
-               RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) templatesTable.getModel();\r
-               if (deleteAllTemplates) {\r
-                       int rowCount = templatesTable.getRowCount();\r
-                       for (int i = rowCount - 1; i >= 0; i--) {\r
-                               int modelRowIndex = templatesTable.convertRowIndexToModel(i);\r
-                               tableModel.deleteRecordJobTemplate(modelRowIndex, i);\r
-                       }\r
-               } else {\r
-                       int[] selectedRows = templatesTable.getSelectedRows();\r
-                       for (int i = selectedRows.length - 1; i >= 0; i--) {\r
-                               int modelRowIndex = templatesTable.convertRowIndexToModel(selectedRows[i]);\r
-                               tableModel.deleteRecordJobTemplate(modelRowIndex, selectedRows[i]);\r
-                       }\r
-               }\r
-               //update the button state of buttons dealing with jobs\r
-               this.configureTableButtons();\r
-       }\r
-       \r
-       /**\r
-        * Iterates through all RecordJob objects (or just the selected ones) and returns true\r
-        * if at least one of them has one or more has the given state(s).\r
-        * @param state\r
-        * @param justSelectedJobs\r
-        * @return\r
-        */\r
-       private boolean checkJobStates(RecordJob.State[] state, boolean justSelectedJobs) {\r
-               boolean foundState = false;\r
-               List<RecordJob> jobsToLookAt = null;\r
-               if (!justSelectedJobs) {\r
-                       jobsToLookAt = this.appLayer.getRecordJobs();\r
-               } else {\r
-                       jobsToLookAt = getSelectedRecordJobs(jobsTable);\r
-               }\r
-               \r
-               for (RecordJob currentJob : jobsToLookAt) {\r
-                       for (int i = 0; i < state.length; i++) {\r
-                               if (currentJob.getState() == state[i]) {\r
-                                       foundState = true;\r
-                                       break;\r
-                               }\r
-                       }\r
-               }\r
-               return foundState;\r
-       }\r
-       \r
-       /**\r
-        * Returns the list of selected RecordJobs or RecordJobTemplates.\r
-        * @param table jobsTable or templatesTable\r
-        * @return list of selected RecordJobs or RecordJobTemplates\r
-        */\r
-       private List<RecordJob> getSelectedRecordJobs(JXTable table) {\r
-               List<RecordJob> list = new ArrayList<RecordJob>();\r
-               if (table.getSelectedRowCount() > 0) {\r
-                       int[] selectedRows = table.getSelectedRows();\r
-                       for (int i = 0; i < selectedRows.length; i++) {\r
-                               int modelRowIndex = table.convertRowIndexToModel(selectedRows[i]);\r
-                               if (table == jobsTable) {\r
-                                       RecordJobsTableModel tableModel = (RecordJobsTableModel) table.getModel();\r
-                                       RecordJob job = tableModel.getRecordJob(modelRowIndex);\r
-                                       if (job != null) {\r
-                                               list.add(job);\r
-                                       }\r
-                               } else {\r
-                                       RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) table.getModel();\r
-                                       RecordJobTemplate template = tableModel.getRecordJobTemplate(modelRowIndex);\r
-                                       if (template != null) {\r
-                                               list.add(template);\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               return list;\r
-       }\r
-       \r
-       private void configureTableButtons() {\r
-               if (jobsTable != null) {\r
-                       if (jobsTable.getRowCount() == 0) {\r
-                               jobs_clear.setEnabled(false);\r
-                               jobs_delete.setEnabled(false);\r
-                       } else {\r
-                               jobs_clear.setEnabled(true);\r
-                               jobs_delete.setEnabled(true);\r
-                               if (jobsTable.getSelectedRowCount() == 0) {\r
-                                       jobs_delete.setEnabled(false);\r
-                               } else {\r
-                                       //go through all elements and check for attributes PROCESSING\r
-                                       RecordJob.State[] lookForState = {RecordJob.State.PROCESSING};\r
-                                       boolean foundState = checkJobStates(lookForState, false);\r
-                                       if (foundState) {\r
-                                               //we have to disable the clear and delete button\r
-                                               jobs_delete.setEnabled(false);\r
-                                       }\r
-                               }\r
-                       }\r
-                       if (templatesTable.getSelectedRowCount() == 1) {\r
-                               jobs_createFromTempl.setEnabled(true);\r
-                       } else {\r
-                               jobs_createFromTempl.setEnabled(false);\r
-                       }\r
-               }\r
-               \r
-               if (templatesTable != null) {\r
-                       templ_createFromJob.setEnabled(false);\r
-                       templ_delete.setEnabled(false);\r
-                       templ_clear.setEnabled(false);\r
-                       \r
-                       if (jobsTable != null && jobsTable.getSelectedRowCount() == 1) {\r
-                               templ_createFromJob.setEnabled(true);\r
-                       }\r
-                       \r
-                       if (templatesTable.getSelectedRowCount() > 0) {\r
-                               templ_delete.setEnabled(true);\r
-                       }\r
-                       \r
-                       if (templatesTable.getRowCount() > 0) {\r
-                               templ_clear.setEnabled(true);\r
-                       }\r
-               }\r
-       }\r
-       \r
-       private class JobsTableMouseListener implements MouseListener {\r
-\r
-               public void mouseClicked(MouseEvent e) {\r
-                       if (e != null && e.getClickCount() == 2) {\r
-                               List<RecordJob> selectedJobs = getSelectedRecordJobs(jobsTable);\r
-                               if (selectedJobs.size() == 1) {\r
-                                       RecordJob selectedJob = selectedJobs.get(0);\r
-                                       if (selectedJob.getState() != RecordJob.State.PROCESSING) {\r
-                                               JobDialog jobDialog = new JobDialog(SwingGUI.this, selectedJob, appLayer);\r
-                                               jobDialog.showDialog();\r
-                                       }\r
-                               }\r
-                       } else {\r
-                               configureTableButtons();\r
-                       }\r
-               }\r
-\r
-               public void mouseEntered(MouseEvent e) {}\r
-\r
-               public void mouseExited(MouseEvent e) {}\r
-\r
-               public void mousePressed(MouseEvent e) {\r
-                       this.showPopupMenu(e);\r
-               }\r
-\r
-               public void mouseReleased(MouseEvent e) {\r
-                       this.showPopupMenu(e);\r
-               }\r
-               \r
-               private void showPopupMenu(MouseEvent e) {\r
-                       if (e.isPopupTrigger()) {\r
-                               JTable table = (JTable)(e.getSource());\r
-                               Point p = e.getPoint();\r
-                               int row = table.rowAtPoint(p);\r
-                               int[] selectedRows = table.getSelectedRows();\r
-                               //figure out whether we have to reselect the current row under the pointer,\r
-                               //which is only the case if the already selected rows don't include the one under\r
-                               //the pointer yet\r
-                               boolean reSelect = true;\r
-                               for (int i = 0; i < selectedRows.length; i++) {\r
-                                       if (row == selectedRows[i]) {\r
-                                               reSelect = false;\r
-                                               break;\r
-                                       }\r
-                               }\r
-                               \r
-                               if (row != -1 && reSelect) {\r
-                                       table.setRowSelectionInterval(row, row);\r
-                               }\r
-                               \r
-                               this.configurePopupMenu();\r
-                               configureTableButtons();\r
-                               jobsTablePopupMenu.show(e.getComponent(), e.getX(), e.getY());\r
-                       }\r
-               }\r
-               \r
-               private void configurePopupMenu() {\r
-                       //Disable all buttons first\r
-                       jobs_contextmenu_edit.setEnabled(false);\r
-                       jobs_contextmenu_duplicate.setEnabled(false);\r
-                       jobs_contextmenu_applytempl.setEnabled(false);\r
-                       jobs_contextmenu_delete.setEnabled(false);\r
-                       jobs_contextmenu_resetstate_waiting.setEnabled(false);\r
-                       jobs_contextmenu_resetstate_done.setEnabled(false);\r
-                       jobs_contextmenu_showerror.setEnabled(false);\r
-                       jobs_contextmenu_start.setEnabled(false);\r
-                       for (JMenuItem pluginItem : jobs_contextmenu_runPluginMenuItems) {\r
-                               pluginItem.setEnabled(false);\r
-                       }\r
-                       \r
-                       //edit, duplicate, and show error buttons\r
-                       if (jobsTable.getSelectedRowCount() == 1) {\r
-                               jobs_contextmenu_edit.setEnabled(true);\r
-                               \r
-                               //Show error button\r
-                               List<RecordJob> selectedJobs = getSelectedRecordJobs(jobsTable);\r
-                               RecordJob selectedJob = selectedJobs.get(0);\r
-                               if (selectedJob.getState() == RecordJob.State.ERROR || selectedJob.getState() == RecordJob.State.ERROR_PLUGIN) {\r
-                                       jobs_contextmenu_showerror.setEnabled(true);\r
-                               }\r
-                       }\r
-                       \r
-                       if (jobsTable.getSelectedRowCount() > 0) {\r
-                               jobs_contextmenu_duplicate.setEnabled(true);\r
-                               //Delete button\r
-                               RecordJob.State[] states = {RecordJob.State.PROCESSING};\r
-                               if (!checkJobStates(states, false)) {\r
-                                       //none of the jobs is processing\r
-                                       jobs_contextmenu_delete.setEnabled(true);\r
-                                       jobs_contextmenu_resetstate_waiting.setEnabled(true);\r
-                                       \r
-                                       if (templatesTable.getSelectedRowCount() == 1) {\r
-                                               jobs_contextmenu_applytempl.setEnabled(true);\r
-                                       }\r
-                               }\r
-                               \r
-                               //Start button\r
-                               RecordJob.State[] states2 = {RecordJob.State.ERROR, RecordJob.State.DONE, RecordJob.State.PROCESSING, RecordJob.State.ERROR_PLUGIN};\r
-                               if (!checkJobStates(states2, true)) {\r
-                                       //only enable start if none of the selected jobs as any of the States above\r
-                                       //as the only job State that is not listed is "waiting", we only enable the button if all jobs are waiting\r
-                                       jobs_contextmenu_start.setEnabled(true);\r
-                               }\r
-                               \r
-                               //reset to 'done' button\r
-                               RecordJob.State[] states3 = {RecordJob.State.ERROR, RecordJob.State.WAITING, RecordJob.State.PROCESSING};\r
-                               if (!checkJobStates(states3, true)) {\r
-                                       //only enable the "reset to done" button when processes have the state DONE or ERROR_PLUGIN\r
-                                       jobs_contextmenu_resetstate_done.setEnabled(true);\r
-                               }\r
-                               \r
-                               //plugin buttons, enable only when state of the job is DONE\r
-                               RecordJob.State[] states4 = {RecordJob.State.ERROR, RecordJob.State.WAITING, RecordJob.State.PROCESSING, RecordJob.State.ERROR_PLUGIN};\r
-                               if (!checkJobStates(states4, true)) {\r
-                                       int counter = 0;\r
-                                       for (JMenuItem pluginItem : jobs_contextmenu_runPluginMenuItems) {\r
-                                               if (appLayer.getEncoderPlugins().get(counter).isEnabled()) {\r
-                                                       pluginItem.setEnabled(true);\r
-                                               }\r
-                                               counter++;\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-               \r
-       }\r
-       \r
-       private class TemplatesTableMouseListener implements MouseListener {\r
-\r
-               public void mouseClicked(MouseEvent e) {\r
-                       if (e != null && e.getClickCount() == 2) {\r
-                               List<RecordJob> selectedJobs = getSelectedRecordJobs(templatesTable);\r
-                               if (selectedJobs.size() == 1) {\r
-                                       RecordJobTemplate selectedJob = (RecordJobTemplate) selectedJobs.get(0);\r
-                                       JobDialog jobDialog = new JobDialog(SwingGUI.this, selectedJob, appLayer, JobDialog.EDIT_TEMPLATE);\r
-                                       jobDialog.showDialog();\r
-                                       configureTableButtons();\r
-                               }\r
-                       } else {\r
-                               configureTableButtons();\r
-                       }\r
-               }\r
-\r
-               public void mouseEntered(MouseEvent e) {}\r
-\r
-               public void mouseExited(MouseEvent e) {}\r
-\r
-               public void mousePressed(MouseEvent e) {\r
-                       this.showPopupMenu(e);\r
-               }\r
-\r
-               public void mouseReleased(MouseEvent e) {\r
-                       this.showPopupMenu(e);\r
-               }\r
-               \r
-               private void showPopupMenu(MouseEvent e) {\r
-                       if (e.isPopupTrigger()) {\r
-                               JTable table = (JTable)(e.getSource());\r
-                               Point p = e.getPoint();\r
-                               int row = table.rowAtPoint(p);\r
-                               int[] selectedRows = table.getSelectedRows();\r
-                               //figure out whether we have to reselect the current row under the pointer,\r
-                               //which is only the case if the already selected rows don't include the one under\r
-                               //the pointer yet\r
-                               boolean reSelect = true;\r
-                               for (int i = 0; i < selectedRows.length; i++) {\r
-                                       if (row == selectedRows[i]) {\r
-                                               reSelect = false;\r
-                                               break;\r
-                                       }\r
-                               }\r
-                               \r
-                               if (row != -1 && reSelect) {\r
-                                       table.setRowSelectionInterval(row, row);\r
-                               }\r
-                               \r
-                               this.configurePopupMenu();\r
-                               configureTableButtons();\r
-                               templatesTablePopupMenu.show(e.getComponent(), e.getX(), e.getY());\r
-                       }\r
-               }\r
-               \r
-               private void configurePopupMenu() {\r
-                       //Various buttons\r
-                       templ_contextmenu_edit.setEnabled(false);\r
-                       templ_contextmenu_duplicate.setEnabled(false);\r
-                       templ_contextmenu_delete.setEnabled(false);\r
-                       \r
-                       //Edit button\r
-                       if (templatesTable.getSelectedRowCount() == 1) {\r
-                               templ_contextmenu_edit.setEnabled(true);\r
-                       }\r
-                       \r
-                       //Delete and duplicate button\r
-                       if (templatesTable.getSelectedRowCount() > 0) {\r
-                               templ_contextmenu_delete.setEnabled(true);\r
-                               templ_contextmenu_duplicate.setEnabled(true);\r
-                       }\r
-               }\r
-       }\r
-               \r
-       private void showAboutBox() {\r
-        try {\r
-            InputStream inStream = ClassLoader.getSystemResourceAsStream("about.html");\r
-            StringBuffer out = new StringBuffer();\r
-            byte[] b = new byte[4096];\r
-            for (int n; (n = inStream.read(b)) != -1;) {\r
-                out.append(new String(b, 0, n));\r
-            }\r
-            String htmlString = out.toString();\r
-            htmlString = htmlString.replaceAll("[\\r\\n]", "");\r
-            JOptionPane.showMessageDialog(this, htmlString, "About", JOptionPane.PLAIN_MESSAGE);\r
-        } catch (IOException ex) {\r
-            ex.printStackTrace();\r
-        }\r
-    }\r
-\r
-       public void windowActivated(WindowEvent e) {}\r
-       public void windowClosed(WindowEvent e) {}\r
-       public void windowDeactivated(WindowEvent e) {}\r
-       public void windowDeiconified(WindowEvent e) {}\r
-       public void windowIconified(WindowEvent e) {}\r
-       public void windowOpened(WindowEvent e) {}\r
-\r
-       public void windowClosing(WindowEvent e) {\r
-               this.shutDown();\r
-       }\r
-\r
-       private void shutDown() {\r
-               if (this.appLayer.getState() == DemoRecorderApplication.STATE_WORKING) {\r
-                       int result = JOptionPane.showConfirmDialog(this, "There are still jobs being recorded. Are you sure you want to exit?", "Confirm close", JOptionPane.YES_NO_OPTION);\r
-                       if (result == JOptionPane.NO_OPTION) {\r
-                               return;\r
-                       }\r
-               }\r
-               saveTableStates(jobsTable);\r
-               saveTableStates(templatesTable);\r
-               saveTemplateTableContent();\r
-               this.appLayer.shutDown();\r
-               this.dispose();\r
-               System.exit(0);\r
-       }\r
-       \r
-       private void saveTemplateTableContent() {\r
-               File path = DemoRecorderUtils.computeLocalFile(DemoRecorderApplication.PREFERENCES_DIRNAME, TEMPLATE_TABLE_CONTENT_FILENAME);\r
-               RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) templatesTable.getModel();\r
-               tableModel.saveTemplateListToFile(path);\r
-       }\r
-       \r
-       private Icon getIcon(String iconString) {\r
-               URL url = ClassLoader.getSystemResource("icons/" + iconString);\r
-               Icon i = new ImageIcon(url);\r
-               return i;\r
-       }\r
-\r
-}\r
+package com.nexuiz.demorecorder.ui.swinggui;
+
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.help.HelpBroker;
+import javax.help.HelpSet;
+import javax.swing.BorderFactory;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.UIManager;
+import javax.swing.border.TitledBorder;
+
+import net.miginfocom.swing.MigLayout;
+
+import org.jdesktop.swingx.JXTable;
+
+import com.nexuiz.demorecorder.application.DemoRecorderApplication;
+import com.nexuiz.demorecorder.application.DemoRecorderUtils;
+import com.nexuiz.demorecorder.application.NDRPreferences;
+import com.nexuiz.demorecorder.application.DemoRecorderApplication.Preferences;
+import com.nexuiz.demorecorder.application.jobs.RecordJob;
+import com.nexuiz.demorecorder.application.jobs.RecordJob.State;
+import com.nexuiz.demorecorder.application.plugins.EncoderPlugin;
+import com.nexuiz.demorecorder.ui.DemoRecorderUI;
+import com.nexuiz.demorecorder.ui.swinggui.tablemodels.RecordJobTemplatesTableModel;
+import com.nexuiz.demorecorder.ui.swinggui.tablemodels.RecordJobsTableModel;
+import com.nexuiz.demorecorder.ui.swinggui.utils.ShowErrorDialogExceptionHandler;
+import com.nexuiz.demorecorder.ui.swinggui.utils.XProperties;
+import com.nexuiz.demorecorder.ui.swinggui.utils.XProperties.XTableState;
+
+public class SwingGUI extends JFrame implements WindowListener, DemoRecorderUI {
+       
+       private static final long serialVersionUID = -7287303462488231068L;
+       public static final String JOB_TABLE_PREFERENCES_FILENAME = "jobsTable.pref";
+       public static final String TEMPLATE_TABLE_PREFERENCES_FILENAME = "templatesTable.pref";
+       public static final String TEMPLATE_TABLE_CONTENT_FILENAME = "templates.dat";
+
+       private DemoRecorderApplication appLayer;
+       private PreferencesDialog preferencesDialog;
+       
+       private JXTable jobsTable = null;
+       private JPopupMenu jobsTablePopupMenu;
+       private ActionListener jobButtonActionListener = new JobButtonActionListener();
+       private MouseListener jobsTableMouseListener = new JobsTableMouseListener();
+       
+       private JXTable templatesTable = null;
+       private JPopupMenu templatesTablePopupMenu;
+       private ActionListener templateButtonActionListener = new TemplateButtonActionListener();
+       private MouseListener templatesTableMouseListener = new TemplatesTableMouseListener();
+       
+       private ActionListener recordButtonActionListener = new RecordButtonActionListener();
+       
+       private static final String LABEL_JOB_CREATE = "Create";
+       private static final String LABEL_JOB_CREATE_FROM_TEMPL = "Create from template";
+       private static final String LABEL_JOB_DELETE = "Delete";
+       private static final String LABEL_JOB_CLEAR = "Clear";
+       private static final String LABEL_JOB_EDIT = "Edit job";
+       private static final String LABEL_JOB_DUPLICATE = "Duplicate job";
+       private static final String LABEL_JOB_APPLYTEMPL = "Apply template";
+       private static final String LABEL_JOB_START = "Start job";
+       private static final String LABEL_JOB_SHOWERROR = "Show error message";
+       private static final String LABEL_JOB_RESET_STATE_WAITING = "Reset job status to 'waiting'";
+       private static final String LABEL_JOB_RESET_STATE_DONE = "Reset job status to 'done'";
+       
+       private static final String LABEL_TEMPL_CREATE = "Create";
+       private static final String LABEL_TEMPL_CREATE_FROM_JOB = "Create from job";
+       private static final String LABEL_TEMPL_DELETE = "Delete";
+       private static final String LABEL_TEMPL_CLEAR = "Clear";
+       private static final String LABEL_TEMPL_EDIT = "Edit template";
+       private static final String LABEL_TEMPL_DUPLICATE = "Duplicate template";
+       
+       private ActionListener menuButtonActionListener = new MenuButtonActionListener();
+       private JMenuItem fileLoadQueue = new JMenuItem("Load job queue", getIcon("fileopen.png"));
+       private JMenuItem fileSaveQueue = new JMenuItem("Save job queue", getIcon("filesave.png"));
+       private JMenuItem fileLoadTemplates = new JMenuItem("Load templates", getIcon("fileopen.png"));
+       private JMenuItem fileSaveTemplates = new JMenuItem("Save templates", getIcon("filesave.png"));
+       private JMenuItem filePreferences = new JMenuItem("Preferences", getIcon("advanced.png"));
+       private JMenuItem fileExit = new JMenuItem("Exit", getIcon("exit.png"));
+       private JMenuItem helpHelp = new JMenuItem("Show help", getIcon("help.png"));
+       private JMenuItem helpAbout = new JMenuItem("About", getIcon("info.png"));
+       private JFileChooser jobQueueSaveAsFC = new JFileChooser();
+       private JFileChooser templatesSaveAsFC = new JFileChooser();
+       
+       private JButton jobs_create = new JButton(LABEL_JOB_CREATE, getIcon("edit_add.png"));
+       private JButton jobs_createFromTempl = new JButton(LABEL_JOB_CREATE_FROM_TEMPL, getIcon("view_right_p.png"));
+       private JButton jobs_delete = new JButton(LABEL_JOB_DELETE, getIcon("editdelete.png"));
+       private JButton jobs_clear = new JButton(LABEL_JOB_CLEAR, getIcon("editclear.png"));
+       private JMenuItem jobs_contextmenu_edit = new JMenuItem(LABEL_JOB_EDIT, getIcon("edit.png"));
+       private JMenuItem jobs_contextmenu_duplicate = new JMenuItem(LABEL_JOB_DUPLICATE, getIcon("editcopy.png"));
+       private JMenuItem jobs_contextmenu_applytempl = new JMenuItem(LABEL_JOB_APPLYTEMPL, getIcon("editpaste.png"));
+       private JMenuItem jobs_contextmenu_delete = new JMenuItem(LABEL_JOB_DELETE, getIcon("editdelete.png"));
+       private JMenuItem jobs_contextmenu_start = new JMenuItem(LABEL_JOB_START, getIcon("player_play.png"));
+       private JMenuItem jobs_contextmenu_showerror = new JMenuItem(LABEL_JOB_SHOWERROR, getIcon("status_unknown.png"));
+       private JMenuItem jobs_contextmenu_resetstate_waiting = new JMenuItem(LABEL_JOB_RESET_STATE_WAITING, getIcon("quick_restart.png"));
+       private JMenuItem jobs_contextmenu_resetstate_done = new JMenuItem(LABEL_JOB_RESET_STATE_DONE, getIcon("quick_restart_blue.png"));
+       private List<JMenuItem> jobs_contextmenu_runPluginMenuItems = new ArrayList<JMenuItem>();
+       
+       private JButton templ_create = new JButton(LABEL_TEMPL_CREATE, getIcon("edit_add.png"));
+       private JButton templ_createFromJob = new JButton(LABEL_TEMPL_CREATE_FROM_JOB, getIcon("view_right_p.png"));
+       private JButton templ_delete = new JButton(LABEL_TEMPL_DELETE, getIcon("editdelete.png"));
+       private JButton templ_clear = new JButton(LABEL_TEMPL_CLEAR, getIcon("editclear.png"));
+       private JMenuItem templ_contextmenu_edit = new JMenuItem(LABEL_TEMPL_EDIT, getIcon("edit.png"));
+       private JMenuItem templ_contextmenu_duplicate = new JMenuItem(LABEL_TEMPL_DUPLICATE, getIcon("editcopy.png"));
+       private JMenuItem templ_contextmenu_delete = new JMenuItem(LABEL_TEMPL_DELETE, getIcon("editdelete.png"));
+       
+       private static final String PROCESSING_START = "Start processing";
+       private static final String PROCESSING_STOP_NOW = "Stop processing";
+       private static final String PROCESSING_STOP_LATER = "Processing will stop after current job finished";
+       private JButton processing_start = new JButton(PROCESSING_START, getIcon("player_play.png"));
+       private JButton processing_stop = new JButton(PROCESSING_STOP_NOW, getIcon("player_pause.png"));
+       
+       private StatusBar statusBar = new StatusBar();
+       
+       private static HelpBroker mainHelpBroker = null;
+       private static final String mainHelpSetName = "help/DemoRecorderHelp.hs";
+
+       public SwingGUI(DemoRecorderApplication appLayer) {
+               super("Nexuiz Demo Recorder v0.3");
+               addWindowListener(this);
+
+               this.appLayer = appLayer;
+
+               this.setupLayout();
+               this.setupHelp();
+               this.preferencesDialog = new PreferencesDialog(this, appLayer);
+
+               setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+               // Display the window.
+               pack();
+               setVisible(true);
+               //now that we have the GUI we can set the parent window for the error dialog
+               ShowErrorDialogExceptionHandler.setParentWindow(this);
+       }
+
+       private void setupHelp() {
+               if (mainHelpBroker == null){
+                       HelpSet mainHelpSet = null;
+
+                       try {
+                               URL hsURL = HelpSet.findHelpSet(null, mainHelpSetName);
+                               mainHelpSet = new HelpSet(null, hsURL);
+                       } catch (Exception e) {
+                               DemoRecorderUtils.showNonCriticalErrorDialog("Could not properly create the help", e, true);
+                       }
+
+                       if (mainHelpSet != null)
+                               mainHelpBroker = mainHelpSet.createHelpBroker();
+                       }
+       }
+
+       private void setupLayout() {
+               setLayout(new MigLayout("wrap 1,insets 10", "[400:700:,grow,fill]",
+                               "[grow,fill][grow,fill][][]"));
+               Container contentPane = getContentPane();
+               setJMenuBar(this.buildMenu());
+
+               this.setupTemplatePanel();
+               this.setupJobPanel();
+               this.setupRecordPanel();
+
+               contentPane.add(statusBar, "south,height 23::");
+       }
+
+       private void setupTemplatePanel() {
+               JPanel templatePanel = new JPanel(new MigLayout("", "[500:500:,grow,fill][170!,fill,grow]", "[grow,fill]"));
+               TitledBorder templatePanelTitle = BorderFactory.createTitledBorder("Templates");
+               templatePanel.setBorder(templatePanelTitle);
+               getContentPane().add(templatePanel);
+               
+               this.setupTemplatesTable();
+               this.loadTableStates(this.templatesTable);
+               JScrollPane templateScrollPane = new JScrollPane(templatesTable);
+               templatePanel.add(templateScrollPane);
+               
+               this.templ_create.addActionListener(this.templateButtonActionListener);
+               this.templ_createFromJob.addActionListener(this.templateButtonActionListener);
+               this.templ_delete.addActionListener(this.templateButtonActionListener);
+               this.templ_clear.addActionListener(this.templateButtonActionListener);
+               
+               this.templ_contextmenu_edit.addActionListener(this.templateButtonActionListener);
+               this.templ_contextmenu_duplicate.addActionListener(this.templateButtonActionListener);
+               this.templ_contextmenu_delete.addActionListener(this.templateButtonActionListener);
+               
+               this.configureTableButtons();
+               
+               JPanel templateControlButtonPanel = new JPanel(new MigLayout("wrap 1", "fill,grow"));
+               templateControlButtonPanel.add(this.templ_create);
+               templateControlButtonPanel.add(this.templ_createFromJob);
+               templateControlButtonPanel.add(this.templ_delete);
+               templateControlButtonPanel.add(this.templ_clear);
+               templatePanel.add(templateControlButtonPanel);
+       }
+
+       private void setupJobPanel() {
+               JPanel jobPanel = new JPanel(new MigLayout("", "[500:500:,grow,fill][170!,fill,grow]", "[grow,fill]"));
+               TitledBorder jobPanelTitle = BorderFactory.createTitledBorder("Jobs");
+               jobPanel.setBorder(jobPanelTitle);
+               getContentPane().add(jobPanel);
+
+               this.setupJobsTable();
+               this.loadTableStates(this.jobsTable);
+               
+               JScrollPane jobScrollPane = new JScrollPane(jobsTable);
+               jobPanel.add(jobScrollPane);
+               
+               this.jobs_create.addActionListener(this.jobButtonActionListener);
+               this.jobs_createFromTempl.addActionListener(this.jobButtonActionListener);
+               this.jobs_delete.addActionListener(this.jobButtonActionListener);
+               this.jobs_clear.addActionListener(this.jobButtonActionListener);
+               
+               this.jobs_contextmenu_edit.addActionListener(this.jobButtonActionListener);
+               this.jobs_contextmenu_duplicate.addActionListener(this.jobButtonActionListener);
+               this.jobs_contextmenu_applytempl.addActionListener(this.jobButtonActionListener);
+               this.jobs_contextmenu_delete.addActionListener(this.jobButtonActionListener);
+               this.jobs_contextmenu_start.addActionListener(this.jobButtonActionListener);
+               this.jobs_contextmenu_showerror.addActionListener(this.jobButtonActionListener);
+               this.jobs_contextmenu_resetstate_waiting.addActionListener(this.jobButtonActionListener);
+               this.jobs_contextmenu_resetstate_done.addActionListener(this.jobButtonActionListener);
+               
+               //initialize button states
+               configureTableButtons();
+               
+               JPanel jobControlButtonPanel = new JPanel(new MigLayout("wrap 1", "fill,grow"));
+               jobControlButtonPanel.add(this.jobs_create);
+               jobControlButtonPanel.add(this.jobs_createFromTempl);
+               jobControlButtonPanel.add(this.jobs_delete);
+               jobControlButtonPanel.add(this.jobs_clear);
+               jobPanel.add(jobControlButtonPanel);
+       }
+       
+       private void setupJobsTable() {
+               RecordJobsTableModel tableModel = new RecordJobsTableModel(this.appLayer);
+               jobsTable = new JXTable(tableModel);
+               jobsTable.setColumnControlVisible(true);
+               jobsTable.setPreferredScrollableViewportSize(new Dimension(400, 100));
+               jobsTable.addMouseListener(this.jobsTableMouseListener);
+       }
+       
+       private void setupTemplatesTable() {
+               RecordJobTemplatesTableModel tableModel = new RecordJobTemplatesTableModel();
+               templatesTable = new JXTable(tableModel);
+               templatesTable.setColumnControlVisible(true);
+               templatesTable.setPreferredScrollableViewportSize(new Dimension(400, 100));
+               templatesTable.addMouseListener(this.templatesTableMouseListener);
+       }
+
+       private void setupRecordPanel() {
+               JPanel recButtonPanel = new JPanel(new MigLayout());
+               recButtonPanel.add(processing_start);
+               recButtonPanel.add(processing_stop);
+               processing_stop.setEnabled(false);
+               processing_start.addActionListener(recordButtonActionListener);
+               processing_stop.addActionListener(recordButtonActionListener);
+               getContentPane().add(recButtonPanel);
+       }
+
+       public static void setSystemLAF() {
+               try {
+                       // Set System L&F
+                       UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+               } catch (Exception e) {
+               }
+       }
+       
+       public void RecordJobPropertiesChange(RecordJob job) {
+               RecordJobsTableModel jobsTableModel = (RecordJobsTableModel) this.jobsTable.getModel();
+               List<RecordJob> recordJobs = jobsTableModel.getRecordJobs();
+               int jobIndex = recordJobs.indexOf(job);
+               if (jobIndex == -1) {
+                       //new job
+                       recordJobs.add(job);
+                       //add job at the end of the table:
+                       int position = jobsTableModel.getRowCount() - 1;
+                       jobsTableModel.fireTableRowsInserted(position, position);
+               } else {
+                       //job already existed
+                       jobIndex = this.jobsTable.convertRowIndexToView(jobIndex); //convert due to possible view sorting
+                       jobsTableModel.fireTableRowsUpdated(jobIndex, jobIndex);
+               }
+       }
+
+       public void recordingFinished() {
+               JOptionPane.showMessageDialog(SwingGUI.this, "Finished recording all jobs", "Recording done", JOptionPane.INFORMATION_MESSAGE);
+               statusBar.showState(false);
+               processing_start.setEnabled(true);
+               processing_stop.setEnabled(false);
+               processing_stop.setText(PROCESSING_STOP_NOW);
+       }
+
+       private JMenuBar buildMenu() {
+               JMenuBar menuBar = new JMenuBar();
+
+               JMenu fileMenu = new JMenu("File");
+               fileMenu.add(fileLoadQueue);
+               fileMenu.add(fileSaveQueue);
+               fileMenu.add(fileLoadTemplates);
+               fileMenu.add(fileSaveTemplates);
+               fileMenu.add(filePreferences);
+               fileMenu.add(fileExit);
+               menuBar.add(fileMenu);
+               
+               fileLoadQueue.addActionListener(menuButtonActionListener);
+               fileSaveQueue.addActionListener(menuButtonActionListener);
+               fileLoadTemplates.addActionListener(menuButtonActionListener);
+               fileSaveTemplates.addActionListener(menuButtonActionListener);
+               filePreferences.addActionListener(menuButtonActionListener);
+               fileExit.addActionListener(menuButtonActionListener);
+
+               JMenu helpMenu = new JMenu("Help");
+               helpMenu.add(helpHelp);
+               helpMenu.add(helpAbout);
+               menuBar.add(helpMenu);
+               
+               helpHelp.addActionListener(menuButtonActionListener);
+               helpAbout.addActionListener(menuButtonActionListener);
+               
+               this.setupEncoderPluginButtons();
+               
+               this.jobsTablePopupMenu = new JPopupMenu();
+               this.jobsTablePopupMenu.add(jobs_contextmenu_edit);
+               this.jobsTablePopupMenu.add(jobs_contextmenu_duplicate);
+               this.jobsTablePopupMenu.add(jobs_contextmenu_applytempl);
+               this.jobsTablePopupMenu.add(jobs_contextmenu_delete);
+               this.jobsTablePopupMenu.add(jobs_contextmenu_start);
+               //add JMenus for plugins
+               for (JMenuItem menuItem : jobs_contextmenu_runPluginMenuItems) {
+                       this.jobsTablePopupMenu.add(menuItem);
+               }
+               this.jobsTablePopupMenu.add(jobs_contextmenu_showerror);
+               this.jobsTablePopupMenu.add(jobs_contextmenu_resetstate_waiting);
+               this.jobsTablePopupMenu.add(jobs_contextmenu_resetstate_done);
+               
+               
+               
+               
+               this.templatesTablePopupMenu = new JPopupMenu();
+               this.templatesTablePopupMenu.add(templ_contextmenu_edit);
+               this.templatesTablePopupMenu.add(templ_contextmenu_duplicate);
+               this.templatesTablePopupMenu.add(templ_contextmenu_delete);
+
+               return menuBar;
+       }
+       
+       private void setupEncoderPluginButtons() {
+               for (EncoderPlugin plugin : appLayer.getEncoderPlugins()) {
+                       JMenuItem pluginMenuItem = new JMenuItem("Just run " + plugin.getName() + " plugin", getIcon("package.png"));
+                       pluginMenuItem.addActionListener(jobButtonActionListener);
+                       this.jobs_contextmenu_runPluginMenuItems.add(pluginMenuItem);
+               }
+       }
+
+       private void saveTableStates(JXTable table) {
+               String fileName;
+               if (table == jobsTable) {
+                       fileName = JOB_TABLE_PREFERENCES_FILENAME;
+               } else {
+                       fileName = TEMPLATE_TABLE_PREFERENCES_FILENAME;
+               }
+               String exceptionMessage = "An error occurred while trying to save the table state file " + fileName;
+               
+               XProperties.XTableProperty t = new XProperties.XTableProperty();
+               XTableState tableState;
+               try {
+                       tableState = (XTableState) t.getSessionState(table);
+               } catch (Exception e) { //most likely ClassCastException
+                       DemoRecorderUtils.showNonCriticalErrorDialog(exceptionMessage, e, true);
+                       return;
+               }
+               
+               File tableStateFile = DemoRecorderUtils.computeLocalFile(DemoRecorderApplication.PREFERENCES_DIRNAME, fileName);
+               DemoRecorderUtils.attemptFileCreation(tableStateFile);
+               
+               try {
+                       FileOutputStream fout = new FileOutputStream(tableStateFile);
+                       ObjectOutputStream oos = new ObjectOutputStream(fout);
+                       oos.writeObject(tableState);
+                       oos.close();
+               } catch (Exception e) {
+                       DemoRecorderUtils.showNonCriticalErrorDialog(exceptionMessage, e, true);
+               }
+       }
+       
+       private void loadTableStates(JXTable table) {
+               String fileName;
+               if (table == jobsTable) {
+                       fileName = JOB_TABLE_PREFERENCES_FILENAME;
+               } else {
+                       fileName = TEMPLATE_TABLE_PREFERENCES_FILENAME;
+               }
+               
+               XProperties.XTableProperty t = new XProperties.XTableProperty();
+               
+               File tableStateFile = DemoRecorderUtils.computeLocalFile(DemoRecorderApplication.PREFERENCES_DIRNAME, fileName);
+               
+               XTableState tableState;
+               
+               try {
+                       FileInputStream fin = new FileInputStream(tableStateFile);
+                       ObjectInputStream ois = new ObjectInputStream(fin);
+                       tableState = (XTableState) ois.readObject();
+                       t.setSessionState(table, tableState);
+               } catch (Exception e) {
+                        //manually hide columns
+                       if (table == jobsTable) {
+                               //re-create table to be sure
+                               this.setupJobsTable();
+                               //manually hide some columns
+                               jobsTable.getColumnExt(RecordJobsTableModel.EXECUTE_AFTER_CAP).setVisible(false);
+                               jobsTable.getColumnExt(RecordJobsTableModel.EXECUTE_BEFORE_CAP).setVisible(false);
+                               jobsTable.getColumnExt(RecordJobsTableModel.VIDEO_DESTINATION_PATH).setVisible(false);
+                               jobsTable.getColumnExt(RecordJobsTableModel.DPVIDEO_PATH).setVisible(false);
+                               jobsTable.getColumnExt(RecordJobsTableModel.RELATIVE_DEMO_PATH).setVisible(false);
+                               jobsTable.getColumnExt(RecordJobsTableModel.ENGINE_PARAMETERS).setVisible(false);
+                               jobsTable.getColumnExt(RecordJobsTableModel.ENGINE_PATH).setVisible(false);
+                       } else {
+                               //re-create table to be sure
+                               this.setupTemplatesTable();
+                               //manually hide some columns
+                               templatesTable.getColumnExt(RecordJobTemplatesTableModel.EXECUTE_AFTER_CAP).setVisible(false);
+                               templatesTable.getColumnExt(RecordJobTemplatesTableModel.EXECUTE_BEFORE_CAP).setVisible(false);
+                               templatesTable.getColumnExt(RecordJobTemplatesTableModel.VIDEO_DESTINATION_PATH).setVisible(false);
+                               templatesTable.getColumnExt(RecordJobTemplatesTableModel.DPVIDEO_PATH).setVisible(false);
+                               templatesTable.getColumnExt(RecordJobTemplatesTableModel.RELATIVE_DEMO_PATH).setVisible(false);
+                               templatesTable.getColumnExt(RecordJobTemplatesTableModel.DEMO_FILE_PATH).setVisible(false);
+                               templatesTable.getColumnExt(RecordJobTemplatesTableModel.ENGINE_PARAMETERS).setVisible(false);
+                               templatesTable.getColumnExt(RecordJobTemplatesTableModel.ENGINE_PATH).setVisible(false);
+                               templatesTable.getColumnExt(RecordJobTemplatesTableModel.JOB_NAME).setVisible(false);
+                       }
+               }
+       }
+       
+       private class MenuButtonActionListener implements ActionListener {
+
+               public void actionPerformed(ActionEvent e) {
+                       if (e.getSource() == fileLoadQueue) {
+                               int result = jobQueueSaveAsFC.showOpenDialog(SwingGUI.this);
+                               if (result == JFileChooser.APPROVE_OPTION) {
+                                       File selectedFile = jobQueueSaveAsFC.getSelectedFile();
+                                       if (selectedFile.isFile()) {
+                                               RecordJobsTableModel tableModel = (RecordJobsTableModel) jobsTable.getModel();
+                                               tableModel.loadNewJobQueue(SwingGUI.this, selectedFile, jobsTable);
+                                               configureTableButtons();
+                                       }
+                               }
+                               
+                       } else if (e.getSource() == fileSaveQueue) {
+                               int result = jobQueueSaveAsFC.showSaveDialog(SwingGUI.this);
+                               if (result == JFileChooser.APPROVE_OPTION) {
+                                       File selectedFile = jobQueueSaveAsFC.getSelectedFile();
+                                       if (!DemoRecorderUtils.getFileExtension(selectedFile).equals("queue")) {
+                                               //if file is not a .queue file, make it one
+                                               selectedFile = new File(selectedFile.getAbsoluteFile() + ".queue");
+                                       }
+                                       if (selectedFile.exists()) {
+                                               int confirm = JOptionPane.showConfirmDialog(SwingGUI.this, "File already exists. Are you sure you want to overwrite it?", "Confirm overwrite", JOptionPane.YES_NO_OPTION);
+                                               if (confirm == JOptionPane.NO_OPTION) {
+                                                       return;
+                                               }
+                                       }
+                                       appLayer.saveJobQueue(selectedFile);
+                               }
+                       } else if (e.getSource() == fileLoadTemplates) {
+                               int result = templatesSaveAsFC.showOpenDialog(SwingGUI.this);
+                               if (result == JFileChooser.APPROVE_OPTION) {
+                                       File selectedFile = templatesSaveAsFC.getSelectedFile();
+                                       if (selectedFile.isFile()) {
+                                               RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) templatesTable.getModel();
+                                               tableModel.loadNewTemplateList(SwingGUI.this, selectedFile, templatesTable);
+                                               configureTableButtons();
+                                       }
+                               }
+                       } else if (e.getSource() == fileSaveTemplates) {
+                               int result = templatesSaveAsFC.showSaveDialog(SwingGUI.this);
+                               if (result == JFileChooser.APPROVE_OPTION) {
+                                       File selectedFile = templatesSaveAsFC.getSelectedFile();
+                                       if (!DemoRecorderUtils.getFileExtension(selectedFile).equals("templ")) {
+                                               selectedFile = new File(selectedFile.getAbsoluteFile() + ".templ");
+                                       }
+                                       if (selectedFile.exists()) {
+                                               int confirm = JOptionPane.showConfirmDialog(SwingGUI.this, "File already exists. Are you sure you want to overwrite it?", "Confirm overwrite", JOptionPane.YES_NO_OPTION);
+                                               if (confirm == JOptionPane.NO_OPTION) {
+                                                       return;
+                                               }
+                                       }
+                                       RecordJobTemplatesTableModel model = (RecordJobTemplatesTableModel) templatesTable.getModel();
+                                       model.saveTemplateListToFile(selectedFile);
+                               }
+                       } else if (e.getSource() == filePreferences) {
+                               preferencesDialog.showDialog();
+                       } else if (e.getSource() == fileExit) {
+                               shutDown();
+                       } else if (e.getSource() == helpHelp) {
+                               if (mainHelpBroker != null) {
+                                       mainHelpBroker.setDisplayed(true);
+                               }
+                       } else if (e.getSource() == helpAbout) {
+                               showAboutBox();
+                       }
+               }
+               
+       }
+
+       /**
+        * Listens to the clicks on buttons that are in the job panel (next to the jobs table)
+        * or its context menu.
+        */
+       private class JobButtonActionListener implements ActionListener {
+
+               public void actionPerformed(ActionEvent e) {
+                       List<RecordJob> selectedJobs = getSelectedRecordJobs(jobsTable);
+                       List<RecordJob> selectedTemplates = getSelectedRecordJobs(templatesTable);
+                       if (e.getSource() == jobs_create) {
+                               JobDialog jobDialog = new JobDialog(SwingGUI.this, appLayer);
+                               jobDialog.showDialog();
+                               configureTableButtons();
+                       }
+                       else if (e.getSource() == jobs_createFromTempl) {
+                               if (selectedTemplates.size() != 1) {
+                                       return;
+                               }
+                               RecordJobTemplate template = (RecordJobTemplate) selectedTemplates.get(0);
+//                             JobDialog jobDialog = new JobDialog(SwingGUI.this, template, appLayer);
+                               JobDialog jobDialog = new JobDialog(SwingGUI.this, template, appLayer, JobDialog.CREATE_JOB_FROM_TEMPLATE);
+                               jobDialog.showDialog();
+                               configureTableButtons();
+                       }
+                       else if (e.getSource() == jobs_delete || e.getSource() == jobs_contextmenu_delete) {
+                               int result = JOptionPane.showConfirmDialog(SwingGUI.this, "Are you sure you want to delete the selected job(s)?", "Confirm delete", JOptionPane.YES_NO_OPTION);
+                               if (result == JOptionPane.YES_OPTION) {
+                                       deleteSelectedJobs(false);
+                                       configureTableButtons();
+                               }
+                       }
+                       else if (e.getSource() == jobs_clear) {
+                               int result = JOptionPane.showConfirmDialog(SwingGUI.this, "Are you sure you want to clear the job list?", "Confirm clear", JOptionPane.YES_NO_OPTION);
+                               if (result == JOptionPane.YES_OPTION) {
+                                       deleteSelectedJobs(true);
+                                       configureTableButtons();
+                               }
+                       } else if (e.getSource() == jobs_contextmenu_edit) {
+                               if (selectedJobs.size() == 1) {
+                                       RecordJob selectedJob = selectedJobs.get(0);
+                                       JobDialog jobDialog = new JobDialog(SwingGUI.this, selectedJob, appLayer);
+                                       jobDialog.showDialog();
+                                       configureTableButtons();
+                               }
+                       } else if (e.getSource() == jobs_contextmenu_showerror) {
+                               if (selectedJobs.size() == 1) {
+                                       RecordJob selectedJob = selectedJobs.get(0);
+                                       DemoRecorderUtils.showNonCriticalErrorDialog(selectedJob.getLastException());
+                               }
+                       } else if (e.getSource() == jobs_contextmenu_resetstate_waiting) {
+                               for (RecordJob job : selectedJobs) {
+                                       job.setState(RecordJob.State.WAITING);
+                               }
+                       } else if (e.getSource() == jobs_contextmenu_resetstate_done) {
+                               for (RecordJob job : selectedJobs) {
+                                       if (job.getState() == State.ERROR_PLUGIN) {
+                                               job.setState(RecordJob.State.DONE);
+                                       }
+                               }
+                       } else if (e.getSource() == jobs_contextmenu_start) {
+                               appLayer.recordSelectedJobs(selectedJobs);
+                               if (appLayer.getState() == DemoRecorderApplication.STATE_WORKING) {
+                                       processing_start.setEnabled(false);
+                                       processing_stop.setEnabled(true);
+                                       statusBar.showState(true);
+                               }
+                       } else if (e.getSource() == jobs_contextmenu_duplicate) {
+                               if (selectedJobs.size() > 0) {
+                                       this.duplicateRecordJobs(selectedJobs);
+                                       //select all new duplicates in the table automatically
+                                       jobsTable.setRowSelectionInterval(jobsTable.getRowCount() - selectedJobs.size(), jobsTable.getRowCount() - 1);
+                                       configureTableButtons();
+                               }
+                       } else if (e.getSource() == jobs_contextmenu_applytempl) {
+                               if (selectedTemplates.size() == 1 && selectedJobs.size() > 0) {
+                                       RecordJobTemplate template = (RecordJobTemplate) selectedTemplates.get(0);
+                                       ApplyTemplateDialog applyDialog = new ApplyTemplateDialog(SwingGUI.this, template, selectedJobs);
+                                       applyDialog.showDialog();
+                               }
+                       } else if (jobs_contextmenu_runPluginMenuItems.contains(e.getSource())) {
+                               int index = jobs_contextmenu_runPluginMenuItems.indexOf(e.getSource());
+                               EncoderPlugin selectedPlugin = appLayer.getEncoderPlugins().get(index);
+                               
+                               appLayer.executePluginForSelectedJobs(selectedPlugin, selectedJobs);
+                               if (appLayer.getState() == DemoRecorderApplication.STATE_WORKING) {
+                                       processing_start.setEnabled(false);
+                                       processing_stop.setEnabled(true);
+                                       statusBar.showState(true);
+                               }
+                       }
+               }
+               
+               private void duplicateRecordJobs(List<RecordJob> jobs) {
+                       String nameSuffix = appLayer.getPreferences().getProperty(NDRPreferences.MAIN_APPLICATION, Preferences.JOB_NAME_APPEND_DUPLICATE);
+                       for (RecordJob job : jobs) {
+                               RecordJob newJob = appLayer.createRecordJob(
+                                       job.getJobName() + nameSuffix,
+                                       job.getEnginePath(),
+                                       job.getEngineParameters(),
+                                       job.getDemoFile(),
+                                       job.getRelativeDemoPath(),
+                                       job.getDpVideoPath(),
+                                       job.getVideoDestination(),
+                                       job.getExecuteBeforeCap(),
+                                       job.getExecuteAfterCap(),
+                                       job.getStartSecond(),
+                                       job.getEndSecond()
+                               );
+                               newJob.setEncoderPluginSettings(job.getEncoderPluginSettings());
+                       }
+               }
+               
+       }
+       
+       private class TemplateButtonActionListener implements ActionListener {
+               public void actionPerformed(ActionEvent e) {
+                       if (e.getSource() == templ_create) {
+                               RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) templatesTable.getModel();
+                               JobDialog jobDialog = new JobDialog(SwingGUI.this, tableModel, templatesTable, appLayer);
+                               jobDialog.showDialog();
+                               configureTableButtons();
+                       }
+                       else if (e.getSource() == templ_createFromJob) {
+                               this.createTemplateFromJob();
+                               configureTableButtons();
+                       }
+                       else if (e.getSource() == templ_delete || e.getSource() == templ_contextmenu_delete) {
+                               int result = JOptionPane.showConfirmDialog(SwingGUI.this, "Are you sure you want to delete the selected template(s)?", "Confirm delete", JOptionPane.YES_NO_OPTION);
+                               if (result == JOptionPane.YES_OPTION) {
+                                       deleteSelectedTemplates(false);
+                               }
+                               configureTableButtons();
+                       }
+                       else if (e.getSource() == templ_clear) {
+                               int result = JOptionPane.showConfirmDialog(SwingGUI.this, "Are you sure you want to clear the template list?", "Confirm clear", JOptionPane.YES_NO_OPTION);
+                               if (result == JOptionPane.YES_OPTION) {
+                                       deleteSelectedTemplates(true);
+                               }
+                               configureTableButtons();
+                       }
+                       else if (e.getSource() == templ_contextmenu_edit) {
+                               List<RecordJob> selectedTemplates = getSelectedRecordJobs(templatesTable);
+                               if (selectedTemplates.size() == 1) {
+                                       RecordJobTemplate selectedTemplate = (RecordJobTemplate) selectedTemplates.get(0);
+                                       JobDialog jobDialog = new JobDialog(SwingGUI.this, selectedTemplate, appLayer, JobDialog.EDIT_TEMPLATE);
+                                       jobDialog.showDialog();
+                                       configureTableButtons();
+                               }
+                       }
+                       else if (e.getSource() == templ_contextmenu_duplicate) {
+                               List<RecordJob> selectedTemplates = getSelectedRecordJobs(templatesTable);
+                               if (selectedTemplates.size() > 0) {
+                                       this.duplicateTemplates(selectedTemplates);
+                                       //select all new duplicates in the table automatically
+                                       templatesTable.setRowSelectionInterval(templatesTable.getRowCount() - selectedTemplates.size(), templatesTable.getRowCount() - 1);
+                                       configureTableButtons();
+                               }
+                       }
+               }
+               
+               private void createTemplateFromJob() {
+                       List<RecordJob> selectedJobs = getSelectedRecordJobs(jobsTable);
+                       if (selectedJobs.size() == 1) {
+                               RecordJob job = selectedJobs.get(0);
+                               RecordJobTemplate templ = new RecordJobTemplate(
+                                       "Generated from job",
+                                       "Generated from job",
+                                       job.getJobName(),
+                                       job.getEnginePath(),
+                                       job.getEngineParameters(),
+                                       job.getDemoFile().getParentFile(),
+                                       job.getRelativeDemoPath(),
+                                       job.getDpVideoPath(),
+                                       job.getVideoDestination().getParentFile(),
+                                       job.getExecuteBeforeCap(),
+                                       job.getExecuteAfterCap()
+                               );
+                               templ.setEncoderPluginSettings(job.getEncoderPluginSettings());
+                               
+                               RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) templatesTable.getModel();
+                               tableModel.addRecordJobTemplate(templ);
+                       }
+               }
+               
+               private void duplicateTemplates(List<RecordJob> selectedTemplates) {
+                       for (RecordJob job : selectedTemplates) {
+                               RecordJobTemplate template = (RecordJobTemplate) job;
+                               RecordJobTemplate templ = new RecordJobTemplate(
+                                       template.getName(),
+                                       template.getSummary(),
+                                       template.getJobName(),
+                                       template.getEnginePath(),
+                                       template.getEngineParameters(),
+                                       template.getDemoFile(),
+                                       template.getRelativeDemoPath(),
+                                       template.getDpVideoPath(),
+                                       template.getVideoDestination(),
+                                       template.getExecuteBeforeCap(),
+                                       template.getExecuteAfterCap()
+                               );
+                               templ.setEncoderPluginSettings(template.getEncoderPluginSettings());
+                               
+                               RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) templatesTable.getModel();
+                               tableModel.addRecordJobTemplate(templ);
+                       }
+               }
+       }
+       
+       private class RecordButtonActionListener implements ActionListener {
+
+               public void actionPerformed(ActionEvent e) {
+                       if (e.getSource() == processing_start) {
+                               appLayer.startRecording();
+                               if (appLayer.getState() == DemoRecorderApplication.STATE_WORKING) {
+                                       processing_start.setEnabled(false);
+                                       processing_stop.setEnabled(true);
+                                       statusBar.showState(true);
+                               }
+                       } else if (e.getSource() == processing_stop) {
+                               if (appLayer.getState() == DemoRecorderApplication.STATE_WORKING) {
+                                       appLayer.stopRecording();
+                                       processing_stop.setEnabled(false);
+                                       processing_stop.setText(PROCESSING_STOP_LATER);
+                               }
+                       }
+               }
+       }
+       
+       private void deleteSelectedJobs(boolean deleteAllJobs) {
+               RecordJobsTableModel tableModel = (RecordJobsTableModel) jobsTable.getModel();
+               if (deleteAllJobs) {
+                       int rowCount = jobsTable.getRowCount();
+                       for (int i = rowCount - 1; i >= 0; i--) {
+                               int modelRowIndex = jobsTable.convertRowIndexToModel(i);
+                               tableModel.deleteRecordJob(modelRowIndex, i);
+                       }
+               } else {
+                       int[] selectedRows = jobsTable.getSelectedRows();
+                       for (int i = selectedRows.length - 1; i >= 0; i--) {
+                               int modelRowIndex = jobsTable.convertRowIndexToModel(selectedRows[i]);
+                               tableModel.deleteRecordJob(modelRowIndex, selectedRows[i]);
+                       }
+               }
+       }
+       
+       private void deleteSelectedTemplates(boolean deleteAllTemplates) {
+               RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) templatesTable.getModel();
+               if (deleteAllTemplates) {
+                       int rowCount = templatesTable.getRowCount();
+                       for (int i = rowCount - 1; i >= 0; i--) {
+                               int modelRowIndex = templatesTable.convertRowIndexToModel(i);
+                               tableModel.deleteRecordJobTemplate(modelRowIndex, i);
+                       }
+               } else {
+                       int[] selectedRows = templatesTable.getSelectedRows();
+                       for (int i = selectedRows.length - 1; i >= 0; i--) {
+                               int modelRowIndex = templatesTable.convertRowIndexToModel(selectedRows[i]);
+                               tableModel.deleteRecordJobTemplate(modelRowIndex, selectedRows[i]);
+                       }
+               }
+               //update the button state of buttons dealing with jobs
+               this.configureTableButtons();
+       }
+       
+       /**
+        * Iterates through all RecordJob objects (or just the selected ones) and returns true
+        * if at least one of them has one or more has the given state(s).
+        * @param state
+        * @param justSelectedJobs
+        * @return
+        */
+       private boolean checkJobStates(RecordJob.State[] state, boolean justSelectedJobs) {
+               boolean foundState = false;
+               List<RecordJob> jobsToLookAt = null;
+               if (!justSelectedJobs) {
+                       jobsToLookAt = this.appLayer.getRecordJobs();
+               } else {
+                       jobsToLookAt = getSelectedRecordJobs(jobsTable);
+               }
+               
+               for (RecordJob currentJob : jobsToLookAt) {
+                       for (int i = 0; i < state.length; i++) {
+                               if (currentJob.getState() == state[i]) {
+                                       foundState = true;
+                                       break;
+                               }
+                       }
+               }
+               return foundState;
+       }
+       
+       /**
+        * Returns the list of selected RecordJobs or RecordJobTemplates.
+        * @param table jobsTable or templatesTable
+        * @return list of selected RecordJobs or RecordJobTemplates
+        */
+       private List<RecordJob> getSelectedRecordJobs(JXTable table) {
+               List<RecordJob> list = new ArrayList<RecordJob>();
+               if (table.getSelectedRowCount() > 0) {
+                       int[] selectedRows = table.getSelectedRows();
+                       for (int i = 0; i < selectedRows.length; i++) {
+                               int modelRowIndex = table.convertRowIndexToModel(selectedRows[i]);
+                               if (table == jobsTable) {
+                                       RecordJobsTableModel tableModel = (RecordJobsTableModel) table.getModel();
+                                       RecordJob job = tableModel.getRecordJob(modelRowIndex);
+                                       if (job != null) {
+                                               list.add(job);
+                                       }
+                               } else {
+                                       RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) table.getModel();
+                                       RecordJobTemplate template = tableModel.getRecordJobTemplate(modelRowIndex);
+                                       if (template != null) {
+                                               list.add(template);
+                                       }
+                               }
+                       }
+               }
+               
+               return list;
+       }
+       
+       private void configureTableButtons() {
+               if (jobsTable != null) {
+                       if (jobsTable.getRowCount() == 0) {
+                               jobs_clear.setEnabled(false);
+                               jobs_delete.setEnabled(false);
+                       } else {
+                               jobs_clear.setEnabled(true);
+                               jobs_delete.setEnabled(true);
+                               if (jobsTable.getSelectedRowCount() == 0) {
+                                       jobs_delete.setEnabled(false);
+                               } else {
+                                       //go through all elements and check for attributes PROCESSING
+                                       RecordJob.State[] lookForState = {RecordJob.State.PROCESSING};
+                                       boolean foundState = checkJobStates(lookForState, false);
+                                       if (foundState) {
+                                               //we have to disable the clear and delete button
+                                               jobs_delete.setEnabled(false);
+                                       }
+                               }
+                       }
+                       if (templatesTable.getSelectedRowCount() == 1) {
+                               jobs_createFromTempl.setEnabled(true);
+                       } else {
+                               jobs_createFromTempl.setEnabled(false);
+                       }
+               }
+               
+               if (templatesTable != null) {
+                       templ_createFromJob.setEnabled(false);
+                       templ_delete.setEnabled(false);
+                       templ_clear.setEnabled(false);
+                       
+                       if (jobsTable != null && jobsTable.getSelectedRowCount() == 1) {
+                               templ_createFromJob.setEnabled(true);
+                       }
+                       
+                       if (templatesTable.getSelectedRowCount() > 0) {
+                               templ_delete.setEnabled(true);
+                       }
+                       
+                       if (templatesTable.getRowCount() > 0) {
+                               templ_clear.setEnabled(true);
+                       }
+               }
+       }
+       
+       private class JobsTableMouseListener implements MouseListener {
+
+               public void mouseClicked(MouseEvent e) {
+                       if (e != null && e.getClickCount() == 2) {
+                               List<RecordJob> selectedJobs = getSelectedRecordJobs(jobsTable);
+                               if (selectedJobs.size() == 1) {
+                                       RecordJob selectedJob = selectedJobs.get(0);
+                                       if (selectedJob.getState() != RecordJob.State.PROCESSING) {
+                                               JobDialog jobDialog = new JobDialog(SwingGUI.this, selectedJob, appLayer);
+                                               jobDialog.showDialog();
+                                       }
+                               }
+                       } else {
+                               configureTableButtons();
+                       }
+               }
+
+               public void mouseEntered(MouseEvent e) {}
+
+               public void mouseExited(MouseEvent e) {}
+
+               public void mousePressed(MouseEvent e) {
+                       this.showPopupMenu(e);
+               }
+
+               public void mouseReleased(MouseEvent e) {
+                       this.showPopupMenu(e);
+               }
+               
+               private void showPopupMenu(MouseEvent e) {
+                       if (e.isPopupTrigger()) {
+                               JTable table = (JTable)(e.getSource());
+                               Point p = e.getPoint();
+                               int row = table.rowAtPoint(p);
+                               int[] selectedRows = table.getSelectedRows();
+                               //figure out whether we have to reselect the current row under the pointer,
+                               //which is only the case if the already selected rows don't include the one under
+                               //the pointer yet
+                               boolean reSelect = true;
+                               for (int i = 0; i < selectedRows.length; i++) {
+                                       if (row == selectedRows[i]) {
+                                               reSelect = false;
+                                               break;
+                                       }
+                               }
+                               
+                               if (row != -1 && reSelect) {
+                                       table.setRowSelectionInterval(row, row);
+                               }
+                               
+                               this.configurePopupMenu();
+                               configureTableButtons();
+                               jobsTablePopupMenu.show(e.getComponent(), e.getX(), e.getY());
+                       }
+               }
+               
+               private void configurePopupMenu() {
+                       //Disable all buttons first
+                       jobs_contextmenu_edit.setEnabled(false);
+                       jobs_contextmenu_duplicate.setEnabled(false);
+                       jobs_contextmenu_applytempl.setEnabled(false);
+                       jobs_contextmenu_delete.setEnabled(false);
+                       jobs_contextmenu_resetstate_waiting.setEnabled(false);
+                       jobs_contextmenu_resetstate_done.setEnabled(false);
+                       jobs_contextmenu_showerror.setEnabled(false);
+                       jobs_contextmenu_start.setEnabled(false);
+                       for (JMenuItem pluginItem : jobs_contextmenu_runPluginMenuItems) {
+                               pluginItem.setEnabled(false);
+                       }
+                       
+                       //edit, duplicate, and show error buttons
+                       if (jobsTable.getSelectedRowCount() == 1) {
+                               jobs_contextmenu_edit.setEnabled(true);
+                               
+                               //Show error button
+                               List<RecordJob> selectedJobs = getSelectedRecordJobs(jobsTable);
+                               RecordJob selectedJob = selectedJobs.get(0);
+                               if (selectedJob.getState() == RecordJob.State.ERROR || selectedJob.getState() == RecordJob.State.ERROR_PLUGIN) {
+                                       jobs_contextmenu_showerror.setEnabled(true);
+                               }
+                       }
+                       
+                       if (jobsTable.getSelectedRowCount() > 0) {
+                               jobs_contextmenu_duplicate.setEnabled(true);
+                               //Delete button
+                               RecordJob.State[] states = {RecordJob.State.PROCESSING};
+                               if (!checkJobStates(states, false)) {
+                                       //none of the jobs is processing
+                                       jobs_contextmenu_delete.setEnabled(true);
+                                       jobs_contextmenu_resetstate_waiting.setEnabled(true);
+                                       
+                                       if (templatesTable.getSelectedRowCount() == 1) {
+                                               jobs_contextmenu_applytempl.setEnabled(true);
+                                       }
+                               }
+                               
+                               //Start button
+                               RecordJob.State[] states2 = {RecordJob.State.ERROR, RecordJob.State.DONE, RecordJob.State.PROCESSING, RecordJob.State.ERROR_PLUGIN};
+                               if (!checkJobStates(states2, true)) {
+                                       //only enable start if none of the selected jobs as any of the States above
+                                       //as the only job State that is not listed is "waiting", we only enable the button if all jobs are waiting
+                                       jobs_contextmenu_start.setEnabled(true);
+                               }
+                               
+                               //reset to 'done' button
+                               RecordJob.State[] states3 = {RecordJob.State.ERROR, RecordJob.State.WAITING, RecordJob.State.PROCESSING};
+                               if (!checkJobStates(states3, true)) {
+                                       //only enable the "reset to done" button when processes have the state DONE or ERROR_PLUGIN
+                                       jobs_contextmenu_resetstate_done.setEnabled(true);
+                               }
+                               
+                               //plugin buttons, enable only when state of the job is DONE
+                               RecordJob.State[] states4 = {RecordJob.State.ERROR, RecordJob.State.WAITING, RecordJob.State.PROCESSING, RecordJob.State.ERROR_PLUGIN};
+                               if (!checkJobStates(states4, true)) {
+                                       int counter = 0;
+                                       for (JMenuItem pluginItem : jobs_contextmenu_runPluginMenuItems) {
+                                               if (appLayer.getEncoderPlugins().get(counter).isEnabled()) {
+                                                       pluginItem.setEnabled(true);
+                                               }
+                                               counter++;
+                                       }
+                               }
+                       }
+               }
+               
+       }
+       
+       private class TemplatesTableMouseListener implements MouseListener {
+
+               public void mouseClicked(MouseEvent e) {
+                       if (e != null && e.getClickCount() == 2) {
+                               List<RecordJob> selectedJobs = getSelectedRecordJobs(templatesTable);
+                               if (selectedJobs.size() == 1) {
+                                       RecordJobTemplate selectedJob = (RecordJobTemplate) selectedJobs.get(0);
+                                       JobDialog jobDialog = new JobDialog(SwingGUI.this, selectedJob, appLayer, JobDialog.EDIT_TEMPLATE);
+                                       jobDialog.showDialog();
+                                       configureTableButtons();
+                               }
+                       } else {
+                               configureTableButtons();
+                       }
+               }
+
+               public void mouseEntered(MouseEvent e) {}
+
+               public void mouseExited(MouseEvent e) {}
+
+               public void mousePressed(MouseEvent e) {
+                       this.showPopupMenu(e);
+               }
+
+               public void mouseReleased(MouseEvent e) {
+                       this.showPopupMenu(e);
+               }
+               
+               private void showPopupMenu(MouseEvent e) {
+                       if (e.isPopupTrigger()) {
+                               JTable table = (JTable)(e.getSource());
+                               Point p = e.getPoint();
+                               int row = table.rowAtPoint(p);
+                               int[] selectedRows = table.getSelectedRows();
+                               //figure out whether we have to reselect the current row under the pointer,
+                               //which is only the case if the already selected rows don't include the one under
+                               //the pointer yet
+                               boolean reSelect = true;
+                               for (int i = 0; i < selectedRows.length; i++) {
+                                       if (row == selectedRows[i]) {
+                                               reSelect = false;
+                                               break;
+                                       }
+                               }
+                               
+                               if (row != -1 && reSelect) {
+                                       table.setRowSelectionInterval(row, row);
+                               }
+                               
+                               this.configurePopupMenu();
+                               configureTableButtons();
+                               templatesTablePopupMenu.show(e.getComponent(), e.getX(), e.getY());
+                       }
+               }
+               
+               private void configurePopupMenu() {
+                       //Various buttons
+                       templ_contextmenu_edit.setEnabled(false);
+                       templ_contextmenu_duplicate.setEnabled(false);
+                       templ_contextmenu_delete.setEnabled(false);
+                       
+                       //Edit button
+                       if (templatesTable.getSelectedRowCount() == 1) {
+                               templ_contextmenu_edit.setEnabled(true);
+                       }
+                       
+                       //Delete and duplicate button
+                       if (templatesTable.getSelectedRowCount() > 0) {
+                               templ_contextmenu_delete.setEnabled(true);
+                               templ_contextmenu_duplicate.setEnabled(true);
+                       }
+               }
+       }
+               
+       private void showAboutBox() {
+        try {
+            InputStream inStream = ClassLoader.getSystemResourceAsStream("about.html");
+            StringBuffer out = new StringBuffer();
+            byte[] b = new byte[4096];
+            for (int n; (n = inStream.read(b)) != -1;) {
+                out.append(new String(b, 0, n));
+            }
+            String htmlString = out.toString();
+            htmlString = htmlString.replaceAll("[\\r\\n]", "");
+            JOptionPane.showMessageDialog(this, htmlString, "About", JOptionPane.PLAIN_MESSAGE);
+        } catch (IOException ex) {
+            ex.printStackTrace();
+        }
+    }
+
+       public void windowActivated(WindowEvent e) {}
+       public void windowClosed(WindowEvent e) {}
+       public void windowDeactivated(WindowEvent e) {}
+       public void windowDeiconified(WindowEvent e) {}
+       public void windowIconified(WindowEvent e) {}
+       public void windowOpened(WindowEvent e) {}
+
+       public void windowClosing(WindowEvent e) {
+               this.shutDown();
+       }
+
+       private void shutDown() {
+               if (this.appLayer.getState() == DemoRecorderApplication.STATE_WORKING) {
+                       int result = JOptionPane.showConfirmDialog(this, "There are still jobs being recorded. Are you sure you want to exit?", "Confirm close", JOptionPane.YES_NO_OPTION);
+                       if (result == JOptionPane.NO_OPTION) {
+                               return;
+                       }
+               }
+               saveTableStates(jobsTable);
+               saveTableStates(templatesTable);
+               saveTemplateTableContent();
+               this.appLayer.shutDown();
+               this.dispose();
+               System.exit(0);
+       }
+       
+       private void saveTemplateTableContent() {
+               File path = DemoRecorderUtils.computeLocalFile(DemoRecorderApplication.PREFERENCES_DIRNAME, TEMPLATE_TABLE_CONTENT_FILENAME);
+               RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) templatesTable.getModel();
+               tableModel.saveTemplateListToFile(path);
+       }
+       
+       private Icon getIcon(String iconString) {
+               URL url = ClassLoader.getSystemResource("icons/" + iconString);
+               Icon i = new ImageIcon(url);
+               return i;
+       }
+
+}