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 jobs_contextmenu_runPluginMenuItems = new ArrayList(); 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 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 selectedJobs = getSelectedRecordJobs(jobsTable); List 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 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 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 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 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 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 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 getSelectedRecordJobs(JXTable table) { List list = new ArrayList(); 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 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 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 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; } }