]> git.xonotic.org Git - xonotic/xonotic.git/blob - misc/tools/NexuizDemoRecorder/main/src/main/java/com/nexuiz/demorecorder/ui/swinggui/SwingGUI.java
oops, typo
[xonotic/xonotic.git] / misc / tools / NexuizDemoRecorder / main / src / main / java / com / nexuiz / demorecorder / ui / swinggui / SwingGUI.java
1 package com.nexuiz.demorecorder.ui.swinggui;
2
3 import java.awt.Container;
4 import java.awt.Dimension;
5 import java.awt.Point;
6 import java.awt.event.ActionEvent;
7 import java.awt.event.ActionListener;
8 import java.awt.event.MouseEvent;
9 import java.awt.event.MouseListener;
10 import java.awt.event.WindowEvent;
11 import java.awt.event.WindowListener;
12 import java.io.File;
13 import java.io.FileInputStream;
14 import java.io.FileOutputStream;
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.io.ObjectInputStream;
18 import java.io.ObjectOutputStream;
19 import java.net.URL;
20 import java.util.ArrayList;
21 import java.util.List;
22
23 import javax.help.HelpBroker;
24 import javax.help.HelpSet;
25 import javax.swing.BorderFactory;
26 import javax.swing.Icon;
27 import javax.swing.ImageIcon;
28 import javax.swing.JButton;
29 import javax.swing.JFileChooser;
30 import javax.swing.JFrame;
31 import javax.swing.JMenu;
32 import javax.swing.JMenuBar;
33 import javax.swing.JMenuItem;
34 import javax.swing.JOptionPane;
35 import javax.swing.JPanel;
36 import javax.swing.JPopupMenu;
37 import javax.swing.JScrollPane;
38 import javax.swing.JTable;
39 import javax.swing.UIManager;
40 import javax.swing.border.TitledBorder;
41
42 import net.miginfocom.swing.MigLayout;
43
44 import org.jdesktop.swingx.JXTable;
45
46 import com.nexuiz.demorecorder.application.DemoRecorderApplication;
47 import com.nexuiz.demorecorder.application.DemoRecorderUtils;
48 import com.nexuiz.demorecorder.application.NDRPreferences;
49 import com.nexuiz.demorecorder.application.DemoRecorderApplication.Preferences;
50 import com.nexuiz.demorecorder.application.jobs.RecordJob;
51 import com.nexuiz.demorecorder.application.jobs.RecordJob.State;
52 import com.nexuiz.demorecorder.application.plugins.EncoderPlugin;
53 import com.nexuiz.demorecorder.ui.DemoRecorderUI;
54 import com.nexuiz.demorecorder.ui.swinggui.tablemodels.RecordJobTemplatesTableModel;
55 import com.nexuiz.demorecorder.ui.swinggui.tablemodels.RecordJobsTableModel;
56 import com.nexuiz.demorecorder.ui.swinggui.utils.ShowErrorDialogExceptionHandler;
57 import com.nexuiz.demorecorder.ui.swinggui.utils.XProperties;
58 import com.nexuiz.demorecorder.ui.swinggui.utils.XProperties.XTableState;
59
60 public class SwingGUI extends JFrame implements WindowListener, DemoRecorderUI {
61         
62         private static final long serialVersionUID = -7287303462488231068L;
63         public static final String JOB_TABLE_PREFERENCES_FILENAME = "jobsTable.pref";
64         public static final String TEMPLATE_TABLE_PREFERENCES_FILENAME = "templatesTable.pref";
65         public static final String TEMPLATE_TABLE_CONTENT_FILENAME = "templates.dat";
66
67         private DemoRecorderApplication appLayer;
68         private PreferencesDialog preferencesDialog;
69         
70         private JXTable jobsTable = null;
71         private JPopupMenu jobsTablePopupMenu;
72         private ActionListener jobButtonActionListener = new JobButtonActionListener();
73         private MouseListener jobsTableMouseListener = new JobsTableMouseListener();
74         
75         private JXTable templatesTable = null;
76         private JPopupMenu templatesTablePopupMenu;
77         private ActionListener templateButtonActionListener = new TemplateButtonActionListener();
78         private MouseListener templatesTableMouseListener = new TemplatesTableMouseListener();
79         
80         private ActionListener recordButtonActionListener = new RecordButtonActionListener();
81         
82         private static final String LABEL_JOB_CREATE = "Create";
83         private static final String LABEL_JOB_CREATE_FROM_TEMPL = "Create from template";
84         private static final String LABEL_JOB_DELETE = "Delete";
85         private static final String LABEL_JOB_CLEAR = "Clear";
86         private static final String LABEL_JOB_EDIT = "Edit job";
87         private static final String LABEL_JOB_DUPLICATE = "Duplicate job";
88         private static final String LABEL_JOB_APPLYTEMPL = "Apply template";
89         private static final String LABEL_JOB_START = "Start job";
90         private static final String LABEL_JOB_SHOWERROR = "Show error message";
91         private static final String LABEL_JOB_RESET_STATE_WAITING = "Reset job status to 'waiting'";
92         private static final String LABEL_JOB_RESET_STATE_DONE = "Reset job status to 'done'";
93         
94         private static final String LABEL_TEMPL_CREATE = "Create";
95         private static final String LABEL_TEMPL_CREATE_FROM_JOB = "Create from job";
96         private static final String LABEL_TEMPL_DELETE = "Delete";
97         private static final String LABEL_TEMPL_CLEAR = "Clear";
98         private static final String LABEL_TEMPL_EDIT = "Edit template";
99         private static final String LABEL_TEMPL_DUPLICATE = "Duplicate template";
100         
101         private ActionListener menuButtonActionListener = new MenuButtonActionListener();
102         private JMenuItem fileLoadQueue = new JMenuItem("Load job queue", getIcon("fileopen.png"));
103         private JMenuItem fileSaveQueue = new JMenuItem("Save job queue", getIcon("filesave.png"));
104         private JMenuItem fileLoadTemplates = new JMenuItem("Load templates", getIcon("fileopen.png"));
105         private JMenuItem fileSaveTemplates = new JMenuItem("Save templates", getIcon("filesave.png"));
106         private JMenuItem filePreferences = new JMenuItem("Preferences", getIcon("advanced.png"));
107         private JMenuItem fileExit = new JMenuItem("Exit", getIcon("exit.png"));
108         private JMenuItem helpHelp = new JMenuItem("Show help", getIcon("help.png"));
109         private JMenuItem helpAbout = new JMenuItem("About", getIcon("info.png"));
110         private JFileChooser jobQueueSaveAsFC = new JFileChooser();
111         private JFileChooser templatesSaveAsFC = new JFileChooser();
112         
113         private JButton jobs_create = new JButton(LABEL_JOB_CREATE, getIcon("edit_add.png"));
114         private JButton jobs_createFromTempl = new JButton(LABEL_JOB_CREATE_FROM_TEMPL, getIcon("view_right_p.png"));
115         private JButton jobs_delete = new JButton(LABEL_JOB_DELETE, getIcon("editdelete.png"));
116         private JButton jobs_clear = new JButton(LABEL_JOB_CLEAR, getIcon("editclear.png"));
117         private JMenuItem jobs_contextmenu_edit = new JMenuItem(LABEL_JOB_EDIT, getIcon("edit.png"));
118         private JMenuItem jobs_contextmenu_duplicate = new JMenuItem(LABEL_JOB_DUPLICATE, getIcon("editcopy.png"));
119         private JMenuItem jobs_contextmenu_applytempl = new JMenuItem(LABEL_JOB_APPLYTEMPL, getIcon("editpaste.png"));
120         private JMenuItem jobs_contextmenu_delete = new JMenuItem(LABEL_JOB_DELETE, getIcon("editdelete.png"));
121         private JMenuItem jobs_contextmenu_start = new JMenuItem(LABEL_JOB_START, getIcon("player_play.png"));
122         private JMenuItem jobs_contextmenu_showerror = new JMenuItem(LABEL_JOB_SHOWERROR, getIcon("status_unknown.png"));
123         private JMenuItem jobs_contextmenu_resetstate_waiting = new JMenuItem(LABEL_JOB_RESET_STATE_WAITING, getIcon("quick_restart.png"));
124         private JMenuItem jobs_contextmenu_resetstate_done = new JMenuItem(LABEL_JOB_RESET_STATE_DONE, getIcon("quick_restart_blue.png"));
125         private List<JMenuItem> jobs_contextmenu_runPluginMenuItems = new ArrayList<JMenuItem>();
126         
127         private JButton templ_create = new JButton(LABEL_TEMPL_CREATE, getIcon("edit_add.png"));
128         private JButton templ_createFromJob = new JButton(LABEL_TEMPL_CREATE_FROM_JOB, getIcon("view_right_p.png"));
129         private JButton templ_delete = new JButton(LABEL_TEMPL_DELETE, getIcon("editdelete.png"));
130         private JButton templ_clear = new JButton(LABEL_TEMPL_CLEAR, getIcon("editclear.png"));
131         private JMenuItem templ_contextmenu_edit = new JMenuItem(LABEL_TEMPL_EDIT, getIcon("edit.png"));
132         private JMenuItem templ_contextmenu_duplicate = new JMenuItem(LABEL_TEMPL_DUPLICATE, getIcon("editcopy.png"));
133         private JMenuItem templ_contextmenu_delete = new JMenuItem(LABEL_TEMPL_DELETE, getIcon("editdelete.png"));
134         
135         private static final String PROCESSING_START = "Start processing";
136         private static final String PROCESSING_STOP_NOW = "Stop processing";
137         private static final String PROCESSING_STOP_LATER = "Processing will stop after current job finished";
138         private JButton processing_start = new JButton(PROCESSING_START, getIcon("player_play.png"));
139         private JButton processing_stop = new JButton(PROCESSING_STOP_NOW, getIcon("player_pause.png"));
140         
141         private StatusBar statusBar = new StatusBar();
142         
143         private static HelpBroker mainHelpBroker = null;
144         private static final String mainHelpSetName = "help/DemoRecorderHelp.hs";
145
146         public SwingGUI(DemoRecorderApplication appLayer) {
147                 super("Nexuiz Demo Recorder v0.3");
148                 addWindowListener(this);
149
150                 this.appLayer = appLayer;
151
152                 this.setupLayout();
153                 this.setupHelp();
154                 this.preferencesDialog = new PreferencesDialog(this, appLayer);
155
156                 setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
157                 // Display the window.
158                 pack();
159                 setVisible(true);
160                 //now that we have the GUI we can set the parent window for the error dialog
161                 ShowErrorDialogExceptionHandler.setParentWindow(this);
162         }
163
164         private void setupHelp() {
165                 if (mainHelpBroker == null){
166                         HelpSet mainHelpSet = null;
167
168                         try {
169                                 URL hsURL = HelpSet.findHelpSet(null, mainHelpSetName);
170                                 mainHelpSet = new HelpSet(null, hsURL);
171                         } catch (Exception e) {
172                                 DemoRecorderUtils.showNonCriticalErrorDialog("Could not properly create the help", e, true);
173                         }
174
175                         if (mainHelpSet != null)
176                                 mainHelpBroker = mainHelpSet.createHelpBroker();
177                         }
178         }
179
180         private void setupLayout() {
181                 setLayout(new MigLayout("wrap 1,insets 10", "[400:700:,grow,fill]",
182                                 "[grow,fill][grow,fill][][]"));
183                 Container contentPane = getContentPane();
184                 setJMenuBar(this.buildMenu());
185
186                 this.setupTemplatePanel();
187                 this.setupJobPanel();
188                 this.setupRecordPanel();
189
190                 contentPane.add(statusBar, "south,height 23::");
191         }
192
193         private void setupTemplatePanel() {
194                 JPanel templatePanel = new JPanel(new MigLayout("", "[500:500:,grow,fill][170!,fill,grow]", "[grow,fill]"));
195                 TitledBorder templatePanelTitle = BorderFactory.createTitledBorder("Templates");
196                 templatePanel.setBorder(templatePanelTitle);
197                 getContentPane().add(templatePanel);
198                 
199                 this.setupTemplatesTable();
200                 this.loadTableStates(this.templatesTable);
201                 JScrollPane templateScrollPane = new JScrollPane(templatesTable);
202                 templatePanel.add(templateScrollPane);
203                 
204                 this.templ_create.addActionListener(this.templateButtonActionListener);
205                 this.templ_createFromJob.addActionListener(this.templateButtonActionListener);
206                 this.templ_delete.addActionListener(this.templateButtonActionListener);
207                 this.templ_clear.addActionListener(this.templateButtonActionListener);
208                 
209                 this.templ_contextmenu_edit.addActionListener(this.templateButtonActionListener);
210                 this.templ_contextmenu_duplicate.addActionListener(this.templateButtonActionListener);
211                 this.templ_contextmenu_delete.addActionListener(this.templateButtonActionListener);
212                 
213                 this.configureTableButtons();
214                 
215                 JPanel templateControlButtonPanel = new JPanel(new MigLayout("wrap 1", "fill,grow"));
216                 templateControlButtonPanel.add(this.templ_create);
217                 templateControlButtonPanel.add(this.templ_createFromJob);
218                 templateControlButtonPanel.add(this.templ_delete);
219                 templateControlButtonPanel.add(this.templ_clear);
220                 templatePanel.add(templateControlButtonPanel);
221         }
222
223         private void setupJobPanel() {
224                 JPanel jobPanel = new JPanel(new MigLayout("", "[500:500:,grow,fill][170!,fill,grow]", "[grow,fill]"));
225                 TitledBorder jobPanelTitle = BorderFactory.createTitledBorder("Jobs");
226                 jobPanel.setBorder(jobPanelTitle);
227                 getContentPane().add(jobPanel);
228
229                 this.setupJobsTable();
230                 this.loadTableStates(this.jobsTable);
231                 
232                 JScrollPane jobScrollPane = new JScrollPane(jobsTable);
233                 jobPanel.add(jobScrollPane);
234                 
235                 this.jobs_create.addActionListener(this.jobButtonActionListener);
236                 this.jobs_createFromTempl.addActionListener(this.jobButtonActionListener);
237                 this.jobs_delete.addActionListener(this.jobButtonActionListener);
238                 this.jobs_clear.addActionListener(this.jobButtonActionListener);
239                 
240                 this.jobs_contextmenu_edit.addActionListener(this.jobButtonActionListener);
241                 this.jobs_contextmenu_duplicate.addActionListener(this.jobButtonActionListener);
242                 this.jobs_contextmenu_applytempl.addActionListener(this.jobButtonActionListener);
243                 this.jobs_contextmenu_delete.addActionListener(this.jobButtonActionListener);
244                 this.jobs_contextmenu_start.addActionListener(this.jobButtonActionListener);
245                 this.jobs_contextmenu_showerror.addActionListener(this.jobButtonActionListener);
246                 this.jobs_contextmenu_resetstate_waiting.addActionListener(this.jobButtonActionListener);
247                 this.jobs_contextmenu_resetstate_done.addActionListener(this.jobButtonActionListener);
248                 
249                 //initialize button states
250                 configureTableButtons();
251                 
252                 JPanel jobControlButtonPanel = new JPanel(new MigLayout("wrap 1", "fill,grow"));
253                 jobControlButtonPanel.add(this.jobs_create);
254                 jobControlButtonPanel.add(this.jobs_createFromTempl);
255                 jobControlButtonPanel.add(this.jobs_delete);
256                 jobControlButtonPanel.add(this.jobs_clear);
257                 jobPanel.add(jobControlButtonPanel);
258         }
259         
260         private void setupJobsTable() {
261                 RecordJobsTableModel tableModel = new RecordJobsTableModel(this.appLayer);
262                 jobsTable = new JXTable(tableModel);
263                 jobsTable.setColumnControlVisible(true);
264                 jobsTable.setPreferredScrollableViewportSize(new Dimension(400, 100));
265                 jobsTable.addMouseListener(this.jobsTableMouseListener);
266         }
267         
268         private void setupTemplatesTable() {
269                 RecordJobTemplatesTableModel tableModel = new RecordJobTemplatesTableModel();
270                 templatesTable = new JXTable(tableModel);
271                 templatesTable.setColumnControlVisible(true);
272                 templatesTable.setPreferredScrollableViewportSize(new Dimension(400, 100));
273                 templatesTable.addMouseListener(this.templatesTableMouseListener);
274         }
275
276         private void setupRecordPanel() {
277                 JPanel recButtonPanel = new JPanel(new MigLayout());
278                 recButtonPanel.add(processing_start);
279                 recButtonPanel.add(processing_stop);
280                 processing_stop.setEnabled(false);
281                 processing_start.addActionListener(recordButtonActionListener);
282                 processing_stop.addActionListener(recordButtonActionListener);
283                 getContentPane().add(recButtonPanel);
284         }
285
286         public static void setSystemLAF() {
287                 try {
288                         // Set System L&F
289                         UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
290                 } catch (Exception e) {
291                 }
292         }
293         
294         public void RecordJobPropertiesChange(RecordJob job) {
295                 RecordJobsTableModel jobsTableModel = (RecordJobsTableModel) this.jobsTable.getModel();
296                 List<RecordJob> recordJobs = jobsTableModel.getRecordJobs();
297                 int jobIndex = recordJobs.indexOf(job);
298                 if (jobIndex == -1) {
299                         //new job
300                         recordJobs.add(job);
301                         //add job at the end of the table:
302                         int position = jobsTableModel.getRowCount() - 1;
303                         jobsTableModel.fireTableRowsInserted(position, position);
304                 } else {
305                         //job already existed
306                         jobIndex = this.jobsTable.convertRowIndexToView(jobIndex); //convert due to possible view sorting
307                         jobsTableModel.fireTableRowsUpdated(jobIndex, jobIndex);
308                 }
309         }
310
311         public void recordingFinished() {
312                 JOptionPane.showMessageDialog(SwingGUI.this, "Finished recording all jobs", "Recording done", JOptionPane.INFORMATION_MESSAGE);
313                 statusBar.showState(false);
314                 processing_start.setEnabled(true);
315                 processing_stop.setEnabled(false);
316                 processing_stop.setText(PROCESSING_STOP_NOW);
317         }
318
319         private JMenuBar buildMenu() {
320                 JMenuBar menuBar = new JMenuBar();
321
322                 JMenu fileMenu = new JMenu("File");
323                 fileMenu.add(fileLoadQueue);
324                 fileMenu.add(fileSaveQueue);
325                 fileMenu.add(fileLoadTemplates);
326                 fileMenu.add(fileSaveTemplates);
327                 fileMenu.add(filePreferences);
328                 fileMenu.add(fileExit);
329                 menuBar.add(fileMenu);
330                 
331                 fileLoadQueue.addActionListener(menuButtonActionListener);
332                 fileSaveQueue.addActionListener(menuButtonActionListener);
333                 fileLoadTemplates.addActionListener(menuButtonActionListener);
334                 fileSaveTemplates.addActionListener(menuButtonActionListener);
335                 filePreferences.addActionListener(menuButtonActionListener);
336                 fileExit.addActionListener(menuButtonActionListener);
337
338                 JMenu helpMenu = new JMenu("Help");
339                 helpMenu.add(helpHelp);
340                 helpMenu.add(helpAbout);
341                 menuBar.add(helpMenu);
342                 
343                 helpHelp.addActionListener(menuButtonActionListener);
344                 helpAbout.addActionListener(menuButtonActionListener);
345                 
346                 this.setupEncoderPluginButtons();
347                 
348                 this.jobsTablePopupMenu = new JPopupMenu();
349                 this.jobsTablePopupMenu.add(jobs_contextmenu_edit);
350                 this.jobsTablePopupMenu.add(jobs_contextmenu_duplicate);
351                 this.jobsTablePopupMenu.add(jobs_contextmenu_applytempl);
352                 this.jobsTablePopupMenu.add(jobs_contextmenu_delete);
353                 this.jobsTablePopupMenu.add(jobs_contextmenu_start);
354                 //add JMenus for plugins
355                 for (JMenuItem menuItem : jobs_contextmenu_runPluginMenuItems) {
356                         this.jobsTablePopupMenu.add(menuItem);
357                 }
358                 this.jobsTablePopupMenu.add(jobs_contextmenu_showerror);
359                 this.jobsTablePopupMenu.add(jobs_contextmenu_resetstate_waiting);
360                 this.jobsTablePopupMenu.add(jobs_contextmenu_resetstate_done);
361                 
362                 
363                 
364                 
365                 this.templatesTablePopupMenu = new JPopupMenu();
366                 this.templatesTablePopupMenu.add(templ_contextmenu_edit);
367                 this.templatesTablePopupMenu.add(templ_contextmenu_duplicate);
368                 this.templatesTablePopupMenu.add(templ_contextmenu_delete);
369
370                 return menuBar;
371         }
372         
373         private void setupEncoderPluginButtons() {
374                 for (EncoderPlugin plugin : appLayer.getEncoderPlugins()) {
375                         JMenuItem pluginMenuItem = new JMenuItem("Just run " + plugin.getName() + " plugin", getIcon("package.png"));
376                         pluginMenuItem.addActionListener(jobButtonActionListener);
377                         this.jobs_contextmenu_runPluginMenuItems.add(pluginMenuItem);
378                 }
379         }
380
381         private void saveTableStates(JXTable table) {
382                 String fileName;
383                 if (table == jobsTable) {
384                         fileName = JOB_TABLE_PREFERENCES_FILENAME;
385                 } else {
386                         fileName = TEMPLATE_TABLE_PREFERENCES_FILENAME;
387                 }
388                 String exceptionMessage = "An error occurred while trying to save the table state file " + fileName;
389                 
390                 XProperties.XTableProperty t = new XProperties.XTableProperty();
391                 XTableState tableState;
392                 try {
393                         tableState = (XTableState) t.getSessionState(table);
394                 } catch (Exception e) { //most likely ClassCastException
395                         DemoRecorderUtils.showNonCriticalErrorDialog(exceptionMessage, e, true);
396                         return;
397                 }
398                 
399                 File tableStateFile = DemoRecorderUtils.computeLocalFile(DemoRecorderApplication.PREFERENCES_DIRNAME, fileName);
400                 DemoRecorderUtils.attemptFileCreation(tableStateFile);
401                 
402                 try {
403                         FileOutputStream fout = new FileOutputStream(tableStateFile);
404                         ObjectOutputStream oos = new ObjectOutputStream(fout);
405                         oos.writeObject(tableState);
406                         oos.close();
407                 } catch (Exception e) {
408                         DemoRecorderUtils.showNonCriticalErrorDialog(exceptionMessage, e, true);
409                 }
410         }
411         
412         private void loadTableStates(JXTable table) {
413                 String fileName;
414                 if (table == jobsTable) {
415                         fileName = JOB_TABLE_PREFERENCES_FILENAME;
416                 } else {
417                         fileName = TEMPLATE_TABLE_PREFERENCES_FILENAME;
418                 }
419                 
420                 XProperties.XTableProperty t = new XProperties.XTableProperty();
421                 
422                 File tableStateFile = DemoRecorderUtils.computeLocalFile(DemoRecorderApplication.PREFERENCES_DIRNAME, fileName);
423                 
424                 XTableState tableState;
425                 
426                 try {
427                         FileInputStream fin = new FileInputStream(tableStateFile);
428                         ObjectInputStream ois = new ObjectInputStream(fin);
429                         tableState = (XTableState) ois.readObject();
430                         t.setSessionState(table, tableState);
431                 } catch (Exception e) {
432                          //manually hide columns
433                         if (table == jobsTable) {
434                                 //re-create table to be sure
435                                 this.setupJobsTable();
436                                 //manually hide some columns
437                                 jobsTable.getColumnExt(RecordJobsTableModel.EXECUTE_AFTER_CAP).setVisible(false);
438                                 jobsTable.getColumnExt(RecordJobsTableModel.EXECUTE_BEFORE_CAP).setVisible(false);
439                                 jobsTable.getColumnExt(RecordJobsTableModel.VIDEO_DESTINATION_PATH).setVisible(false);
440                                 jobsTable.getColumnExt(RecordJobsTableModel.DPVIDEO_PATH).setVisible(false);
441                                 jobsTable.getColumnExt(RecordJobsTableModel.RELATIVE_DEMO_PATH).setVisible(false);
442                                 jobsTable.getColumnExt(RecordJobsTableModel.ENGINE_PARAMETERS).setVisible(false);
443                                 jobsTable.getColumnExt(RecordJobsTableModel.ENGINE_PATH).setVisible(false);
444                         } else {
445                                 //re-create table to be sure
446                                 this.setupTemplatesTable();
447                                 //manually hide some columns
448                                 templatesTable.getColumnExt(RecordJobTemplatesTableModel.EXECUTE_AFTER_CAP).setVisible(false);
449                                 templatesTable.getColumnExt(RecordJobTemplatesTableModel.EXECUTE_BEFORE_CAP).setVisible(false);
450                                 templatesTable.getColumnExt(RecordJobTemplatesTableModel.VIDEO_DESTINATION_PATH).setVisible(false);
451                                 templatesTable.getColumnExt(RecordJobTemplatesTableModel.DPVIDEO_PATH).setVisible(false);
452                                 templatesTable.getColumnExt(RecordJobTemplatesTableModel.RELATIVE_DEMO_PATH).setVisible(false);
453                                 templatesTable.getColumnExt(RecordJobTemplatesTableModel.DEMO_FILE_PATH).setVisible(false);
454                                 templatesTable.getColumnExt(RecordJobTemplatesTableModel.ENGINE_PARAMETERS).setVisible(false);
455                                 templatesTable.getColumnExt(RecordJobTemplatesTableModel.ENGINE_PATH).setVisible(false);
456                                 templatesTable.getColumnExt(RecordJobTemplatesTableModel.JOB_NAME).setVisible(false);
457                         }
458                 }
459         }
460         
461         private class MenuButtonActionListener implements ActionListener {
462
463                 public void actionPerformed(ActionEvent e) {
464                         if (e.getSource() == fileLoadQueue) {
465                                 int result = jobQueueSaveAsFC.showOpenDialog(SwingGUI.this);
466                                 if (result == JFileChooser.APPROVE_OPTION) {
467                                         File selectedFile = jobQueueSaveAsFC.getSelectedFile();
468                                         if (selectedFile.isFile()) {
469                                                 RecordJobsTableModel tableModel = (RecordJobsTableModel) jobsTable.getModel();
470                                                 tableModel.loadNewJobQueue(SwingGUI.this, selectedFile, jobsTable);
471                                                 configureTableButtons();
472                                         }
473                                 }
474                                 
475                         } else if (e.getSource() == fileSaveQueue) {
476                                 int result = jobQueueSaveAsFC.showSaveDialog(SwingGUI.this);
477                                 if (result == JFileChooser.APPROVE_OPTION) {
478                                         File selectedFile = jobQueueSaveAsFC.getSelectedFile();
479                                         if (!DemoRecorderUtils.getFileExtension(selectedFile).equals("queue")) {
480                                                 //if file is not a .queue file, make it one
481                                                 selectedFile = new File(selectedFile.getAbsoluteFile() + ".queue");
482                                         }
483                                         if (selectedFile.exists()) {
484                                                 int confirm = JOptionPane.showConfirmDialog(SwingGUI.this, "File already exists. Are you sure you want to overwrite it?", "Confirm overwrite", JOptionPane.YES_NO_OPTION);
485                                                 if (confirm == JOptionPane.NO_OPTION) {
486                                                         return;
487                                                 }
488                                         }
489                                         appLayer.saveJobQueue(selectedFile);
490                                 }
491                         } else if (e.getSource() == fileLoadTemplates) {
492                                 int result = templatesSaveAsFC.showOpenDialog(SwingGUI.this);
493                                 if (result == JFileChooser.APPROVE_OPTION) {
494                                         File selectedFile = templatesSaveAsFC.getSelectedFile();
495                                         if (selectedFile.isFile()) {
496                                                 RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) templatesTable.getModel();
497                                                 tableModel.loadNewTemplateList(SwingGUI.this, selectedFile, templatesTable);
498                                                 configureTableButtons();
499                                         }
500                                 }
501                         } else if (e.getSource() == fileSaveTemplates) {
502                                 int result = templatesSaveAsFC.showSaveDialog(SwingGUI.this);
503                                 if (result == JFileChooser.APPROVE_OPTION) {
504                                         File selectedFile = templatesSaveAsFC.getSelectedFile();
505                                         if (!DemoRecorderUtils.getFileExtension(selectedFile).equals("templ")) {
506                                                 selectedFile = new File(selectedFile.getAbsoluteFile() + ".templ");
507                                         }
508                                         if (selectedFile.exists()) {
509                                                 int confirm = JOptionPane.showConfirmDialog(SwingGUI.this, "File already exists. Are you sure you want to overwrite it?", "Confirm overwrite", JOptionPane.YES_NO_OPTION);
510                                                 if (confirm == JOptionPane.NO_OPTION) {
511                                                         return;
512                                                 }
513                                         }
514                                         RecordJobTemplatesTableModel model = (RecordJobTemplatesTableModel) templatesTable.getModel();
515                                         model.saveTemplateListToFile(selectedFile);
516                                 }
517                         } else if (e.getSource() == filePreferences) {
518                                 preferencesDialog.showDialog();
519                         } else if (e.getSource() == fileExit) {
520                                 shutDown();
521                         } else if (e.getSource() == helpHelp) {
522                                 if (mainHelpBroker != null) {
523                                         mainHelpBroker.setDisplayed(true);
524                                 }
525                         } else if (e.getSource() == helpAbout) {
526                                 showAboutBox();
527                         }
528                 }
529                 
530         }
531
532         /**
533          * Listens to the clicks on buttons that are in the job panel (next to the jobs table)
534          * or its context menu.
535          */
536         private class JobButtonActionListener implements ActionListener {
537
538                 public void actionPerformed(ActionEvent e) {
539                         List<RecordJob> selectedJobs = getSelectedRecordJobs(jobsTable);
540                         List<RecordJob> selectedTemplates = getSelectedRecordJobs(templatesTable);
541                         if (e.getSource() == jobs_create) {
542                                 JobDialog jobDialog = new JobDialog(SwingGUI.this, appLayer);
543                                 jobDialog.showDialog();
544                                 configureTableButtons();
545                         }
546                         else if (e.getSource() == jobs_createFromTempl) {
547                                 if (selectedTemplates.size() != 1) {
548                                         return;
549                                 }
550                                 RecordJobTemplate template = (RecordJobTemplate) selectedTemplates.get(0);
551 //                              JobDialog jobDialog = new JobDialog(SwingGUI.this, template, appLayer);
552                                 JobDialog jobDialog = new JobDialog(SwingGUI.this, template, appLayer, JobDialog.CREATE_JOB_FROM_TEMPLATE);
553                                 jobDialog.showDialog();
554                                 configureTableButtons();
555                         }
556                         else if (e.getSource() == jobs_delete || e.getSource() == jobs_contextmenu_delete) {
557                                 int result = JOptionPane.showConfirmDialog(SwingGUI.this, "Are you sure you want to delete the selected job(s)?", "Confirm delete", JOptionPane.YES_NO_OPTION);
558                                 if (result == JOptionPane.YES_OPTION) {
559                                         deleteSelectedJobs(false);
560                                         configureTableButtons();
561                                 }
562                         }
563                         else if (e.getSource() == jobs_clear) {
564                                 int result = JOptionPane.showConfirmDialog(SwingGUI.this, "Are you sure you want to clear the job list?", "Confirm clear", JOptionPane.YES_NO_OPTION);
565                                 if (result == JOptionPane.YES_OPTION) {
566                                         deleteSelectedJobs(true);
567                                         configureTableButtons();
568                                 }
569                         } else if (e.getSource() == jobs_contextmenu_edit) {
570                                 if (selectedJobs.size() == 1) {
571                                         RecordJob selectedJob = selectedJobs.get(0);
572                                         JobDialog jobDialog = new JobDialog(SwingGUI.this, selectedJob, appLayer);
573                                         jobDialog.showDialog();
574                                         configureTableButtons();
575                                 }
576                         } else if (e.getSource() == jobs_contextmenu_showerror) {
577                                 if (selectedJobs.size() == 1) {
578                                         RecordJob selectedJob = selectedJobs.get(0);
579                                         DemoRecorderUtils.showNonCriticalErrorDialog(selectedJob.getLastException());
580                                 }
581                         } else if (e.getSource() == jobs_contextmenu_resetstate_waiting) {
582                                 for (RecordJob job : selectedJobs) {
583                                         job.setState(RecordJob.State.WAITING);
584                                 }
585                         } else if (e.getSource() == jobs_contextmenu_resetstate_done) {
586                                 for (RecordJob job : selectedJobs) {
587                                         if (job.getState() == State.ERROR_PLUGIN) {
588                                                 job.setState(RecordJob.State.DONE);
589                                         }
590                                 }
591                         } else if (e.getSource() == jobs_contextmenu_start) {
592                                 appLayer.recordSelectedJobs(selectedJobs);
593                                 if (appLayer.getState() == DemoRecorderApplication.STATE_WORKING) {
594                                         processing_start.setEnabled(false);
595                                         processing_stop.setEnabled(true);
596                                         statusBar.showState(true);
597                                 }
598                         } else if (e.getSource() == jobs_contextmenu_duplicate) {
599                                 if (selectedJobs.size() > 0) {
600                                         this.duplicateRecordJobs(selectedJobs);
601                                         //select all new duplicates in the table automatically
602                                         jobsTable.setRowSelectionInterval(jobsTable.getRowCount() - selectedJobs.size(), jobsTable.getRowCount() - 1);
603                                         configureTableButtons();
604                                 }
605                         } else if (e.getSource() == jobs_contextmenu_applytempl) {
606                                 if (selectedTemplates.size() == 1 && selectedJobs.size() > 0) {
607                                         RecordJobTemplate template = (RecordJobTemplate) selectedTemplates.get(0);
608                                         ApplyTemplateDialog applyDialog = new ApplyTemplateDialog(SwingGUI.this, template, selectedJobs);
609                                         applyDialog.showDialog();
610                                 }
611                         } else if (jobs_contextmenu_runPluginMenuItems.contains(e.getSource())) {
612                                 int index = jobs_contextmenu_runPluginMenuItems.indexOf(e.getSource());
613                                 EncoderPlugin selectedPlugin = appLayer.getEncoderPlugins().get(index);
614                                 
615                                 appLayer.executePluginForSelectedJobs(selectedPlugin, selectedJobs);
616                                 if (appLayer.getState() == DemoRecorderApplication.STATE_WORKING) {
617                                         processing_start.setEnabled(false);
618                                         processing_stop.setEnabled(true);
619                                         statusBar.showState(true);
620                                 }
621                         }
622                 }
623                 
624                 private void duplicateRecordJobs(List<RecordJob> jobs) {
625                         String nameSuffix = appLayer.getPreferences().getProperty(NDRPreferences.MAIN_APPLICATION, Preferences.JOB_NAME_APPEND_DUPLICATE);
626                         for (RecordJob job : jobs) {
627                                 RecordJob newJob = appLayer.createRecordJob(
628                                         job.getJobName() + nameSuffix,
629                                         job.getEnginePath(),
630                                         job.getEngineParameters(),
631                                         job.getDemoFile(),
632                                         job.getRelativeDemoPath(),
633                                         job.getDpVideoPath(),
634                                         job.getVideoDestination(),
635                                         job.getExecuteBeforeCap(),
636                                         job.getExecuteAfterCap(),
637                                         job.getStartSecond(),
638                                         job.getEndSecond()
639                                 );
640                                 newJob.setEncoderPluginSettings(job.getEncoderPluginSettings());
641                         }
642                 }
643                 
644         }
645         
646         private class TemplateButtonActionListener implements ActionListener {
647                 public void actionPerformed(ActionEvent e) {
648                         if (e.getSource() == templ_create) {
649                                 RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) templatesTable.getModel();
650                                 JobDialog jobDialog = new JobDialog(SwingGUI.this, tableModel, templatesTable, appLayer);
651                                 jobDialog.showDialog();
652                                 configureTableButtons();
653                         }
654                         else if (e.getSource() == templ_createFromJob) {
655                                 this.createTemplateFromJob();
656                                 configureTableButtons();
657                         }
658                         else if (e.getSource() == templ_delete || e.getSource() == templ_contextmenu_delete) {
659                                 int result = JOptionPane.showConfirmDialog(SwingGUI.this, "Are you sure you want to delete the selected template(s)?", "Confirm delete", JOptionPane.YES_NO_OPTION);
660                                 if (result == JOptionPane.YES_OPTION) {
661                                         deleteSelectedTemplates(false);
662                                 }
663                                 configureTableButtons();
664                         }
665                         else if (e.getSource() == templ_clear) {
666                                 int result = JOptionPane.showConfirmDialog(SwingGUI.this, "Are you sure you want to clear the template list?", "Confirm clear", JOptionPane.YES_NO_OPTION);
667                                 if (result == JOptionPane.YES_OPTION) {
668                                         deleteSelectedTemplates(true);
669                                 }
670                                 configureTableButtons();
671                         }
672                         else if (e.getSource() == templ_contextmenu_edit) {
673                                 List<RecordJob> selectedTemplates = getSelectedRecordJobs(templatesTable);
674                                 if (selectedTemplates.size() == 1) {
675                                         RecordJobTemplate selectedTemplate = (RecordJobTemplate) selectedTemplates.get(0);
676                                         JobDialog jobDialog = new JobDialog(SwingGUI.this, selectedTemplate, appLayer, JobDialog.EDIT_TEMPLATE);
677                                         jobDialog.showDialog();
678                                         configureTableButtons();
679                                 }
680                         }
681                         else if (e.getSource() == templ_contextmenu_duplicate) {
682                                 List<RecordJob> selectedTemplates = getSelectedRecordJobs(templatesTable);
683                                 if (selectedTemplates.size() > 0) {
684                                         this.duplicateTemplates(selectedTemplates);
685                                         //select all new duplicates in the table automatically
686                                         templatesTable.setRowSelectionInterval(templatesTable.getRowCount() - selectedTemplates.size(), templatesTable.getRowCount() - 1);
687                                         configureTableButtons();
688                                 }
689                         }
690                 }
691                 
692                 private void createTemplateFromJob() {
693                         List<RecordJob> selectedJobs = getSelectedRecordJobs(jobsTable);
694                         if (selectedJobs.size() == 1) {
695                                 RecordJob job = selectedJobs.get(0);
696                                 RecordJobTemplate templ = new RecordJobTemplate(
697                                         "Generated from job",
698                                         "Generated from job",
699                                         job.getJobName(),
700                                         job.getEnginePath(),
701                                         job.getEngineParameters(),
702                                         job.getDemoFile().getParentFile(),
703                                         job.getRelativeDemoPath(),
704                                         job.getDpVideoPath(),
705                                         job.getVideoDestination().getParentFile(),
706                                         job.getExecuteBeforeCap(),
707                                         job.getExecuteAfterCap()
708                                 );
709                                 templ.setEncoderPluginSettings(job.getEncoderPluginSettings());
710                                 
711                                 RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) templatesTable.getModel();
712                                 tableModel.addRecordJobTemplate(templ);
713                         }
714                 }
715                 
716                 private void duplicateTemplates(List<RecordJob> selectedTemplates) {
717                         for (RecordJob job : selectedTemplates) {
718                                 RecordJobTemplate template = (RecordJobTemplate) job;
719                                 RecordJobTemplate templ = new RecordJobTemplate(
720                                         template.getName(),
721                                         template.getSummary(),
722                                         template.getJobName(),
723                                         template.getEnginePath(),
724                                         template.getEngineParameters(),
725                                         template.getDemoFile(),
726                                         template.getRelativeDemoPath(),
727                                         template.getDpVideoPath(),
728                                         template.getVideoDestination(),
729                                         template.getExecuteBeforeCap(),
730                                         template.getExecuteAfterCap()
731                                 );
732                                 templ.setEncoderPluginSettings(template.getEncoderPluginSettings());
733                                 
734                                 RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) templatesTable.getModel();
735                                 tableModel.addRecordJobTemplate(templ);
736                         }
737                 }
738         }
739         
740         private class RecordButtonActionListener implements ActionListener {
741
742                 public void actionPerformed(ActionEvent e) {
743                         if (e.getSource() == processing_start) {
744                                 appLayer.startRecording();
745                                 if (appLayer.getState() == DemoRecorderApplication.STATE_WORKING) {
746                                         processing_start.setEnabled(false);
747                                         processing_stop.setEnabled(true);
748                                         statusBar.showState(true);
749                                 }
750                         } else if (e.getSource() == processing_stop) {
751                                 if (appLayer.getState() == DemoRecorderApplication.STATE_WORKING) {
752                                         appLayer.stopRecording();
753                                         processing_stop.setEnabled(false);
754                                         processing_stop.setText(PROCESSING_STOP_LATER);
755                                 }
756                         }
757                 }
758         }
759         
760         private void deleteSelectedJobs(boolean deleteAllJobs) {
761                 RecordJobsTableModel tableModel = (RecordJobsTableModel) jobsTable.getModel();
762                 if (deleteAllJobs) {
763                         int rowCount = jobsTable.getRowCount();
764                         for (int i = rowCount - 1; i >= 0; i--) {
765                                 int modelRowIndex = jobsTable.convertRowIndexToModel(i);
766                                 tableModel.deleteRecordJob(modelRowIndex, i);
767                         }
768                 } else {
769                         int[] selectedRows = jobsTable.getSelectedRows();
770                         for (int i = selectedRows.length - 1; i >= 0; i--) {
771                                 int modelRowIndex = jobsTable.convertRowIndexToModel(selectedRows[i]);
772                                 tableModel.deleteRecordJob(modelRowIndex, selectedRows[i]);
773                         }
774                 }
775         }
776         
777         private void deleteSelectedTemplates(boolean deleteAllTemplates) {
778                 RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) templatesTable.getModel();
779                 if (deleteAllTemplates) {
780                         int rowCount = templatesTable.getRowCount();
781                         for (int i = rowCount - 1; i >= 0; i--) {
782                                 int modelRowIndex = templatesTable.convertRowIndexToModel(i);
783                                 tableModel.deleteRecordJobTemplate(modelRowIndex, i);
784                         }
785                 } else {
786                         int[] selectedRows = templatesTable.getSelectedRows();
787                         for (int i = selectedRows.length - 1; i >= 0; i--) {
788                                 int modelRowIndex = templatesTable.convertRowIndexToModel(selectedRows[i]);
789                                 tableModel.deleteRecordJobTemplate(modelRowIndex, selectedRows[i]);
790                         }
791                 }
792                 //update the button state of buttons dealing with jobs
793                 this.configureTableButtons();
794         }
795         
796         /**
797          * Iterates through all RecordJob objects (or just the selected ones) and returns true
798          * if at least one of them has one or more has the given state(s).
799          * @param state
800          * @param justSelectedJobs
801          * @return
802          */
803         private boolean checkJobStates(RecordJob.State[] state, boolean justSelectedJobs) {
804                 boolean foundState = false;
805                 List<RecordJob> jobsToLookAt = null;
806                 if (!justSelectedJobs) {
807                         jobsToLookAt = this.appLayer.getRecordJobs();
808                 } else {
809                         jobsToLookAt = getSelectedRecordJobs(jobsTable);
810                 }
811                 
812                 for (RecordJob currentJob : jobsToLookAt) {
813                         for (int i = 0; i < state.length; i++) {
814                                 if (currentJob.getState() == state[i]) {
815                                         foundState = true;
816                                         break;
817                                 }
818                         }
819                 }
820                 return foundState;
821         }
822         
823         /**
824          * Returns the list of selected RecordJobs or RecordJobTemplates.
825          * @param table jobsTable or templatesTable
826          * @return list of selected RecordJobs or RecordJobTemplates
827          */
828         private List<RecordJob> getSelectedRecordJobs(JXTable table) {
829                 List<RecordJob> list = new ArrayList<RecordJob>();
830                 if (table.getSelectedRowCount() > 0) {
831                         int[] selectedRows = table.getSelectedRows();
832                         for (int i = 0; i < selectedRows.length; i++) {
833                                 int modelRowIndex = table.convertRowIndexToModel(selectedRows[i]);
834                                 if (table == jobsTable) {
835                                         RecordJobsTableModel tableModel = (RecordJobsTableModel) table.getModel();
836                                         RecordJob job = tableModel.getRecordJob(modelRowIndex);
837                                         if (job != null) {
838                                                 list.add(job);
839                                         }
840                                 } else {
841                                         RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) table.getModel();
842                                         RecordJobTemplate template = tableModel.getRecordJobTemplate(modelRowIndex);
843                                         if (template != null) {
844                                                 list.add(template);
845                                         }
846                                 }
847                         }
848                 }
849                 
850                 return list;
851         }
852         
853         private void configureTableButtons() {
854                 if (jobsTable != null) {
855                         if (jobsTable.getRowCount() == 0) {
856                                 jobs_clear.setEnabled(false);
857                                 jobs_delete.setEnabled(false);
858                         } else {
859                                 jobs_clear.setEnabled(true);
860                                 jobs_delete.setEnabled(true);
861                                 if (jobsTable.getSelectedRowCount() == 0) {
862                                         jobs_delete.setEnabled(false);
863                                 } else {
864                                         //go through all elements and check for attributes PROCESSING
865                                         RecordJob.State[] lookForState = {RecordJob.State.PROCESSING};
866                                         boolean foundState = checkJobStates(lookForState, false);
867                                         if (foundState) {
868                                                 //we have to disable the clear and delete button
869                                                 jobs_delete.setEnabled(false);
870                                         }
871                                 }
872                         }
873                         if (templatesTable.getSelectedRowCount() == 1) {
874                                 jobs_createFromTempl.setEnabled(true);
875                         } else {
876                                 jobs_createFromTempl.setEnabled(false);
877                         }
878                 }
879                 
880                 if (templatesTable != null) {
881                         templ_createFromJob.setEnabled(false);
882                         templ_delete.setEnabled(false);
883                         templ_clear.setEnabled(false);
884                         
885                         if (jobsTable != null && jobsTable.getSelectedRowCount() == 1) {
886                                 templ_createFromJob.setEnabled(true);
887                         }
888                         
889                         if (templatesTable.getSelectedRowCount() > 0) {
890                                 templ_delete.setEnabled(true);
891                         }
892                         
893                         if (templatesTable.getRowCount() > 0) {
894                                 templ_clear.setEnabled(true);
895                         }
896                 }
897         }
898         
899         private class JobsTableMouseListener implements MouseListener {
900
901                 public void mouseClicked(MouseEvent e) {
902                         if (e != null && e.getClickCount() == 2) {
903                                 List<RecordJob> selectedJobs = getSelectedRecordJobs(jobsTable);
904                                 if (selectedJobs.size() == 1) {
905                                         RecordJob selectedJob = selectedJobs.get(0);
906                                         if (selectedJob.getState() != RecordJob.State.PROCESSING) {
907                                                 JobDialog jobDialog = new JobDialog(SwingGUI.this, selectedJob, appLayer);
908                                                 jobDialog.showDialog();
909                                         }
910                                 }
911                         } else {
912                                 configureTableButtons();
913                         }
914                 }
915
916                 public void mouseEntered(MouseEvent e) {}
917
918                 public void mouseExited(MouseEvent e) {}
919
920                 public void mousePressed(MouseEvent e) {
921                         this.showPopupMenu(e);
922                 }
923
924                 public void mouseReleased(MouseEvent e) {
925                         this.showPopupMenu(e);
926                 }
927                 
928                 private void showPopupMenu(MouseEvent e) {
929                         if (e.isPopupTrigger()) {
930                                 JTable table = (JTable)(e.getSource());
931                                 Point p = e.getPoint();
932                                 int row = table.rowAtPoint(p);
933                                 int[] selectedRows = table.getSelectedRows();
934                                 //figure out whether we have to reselect the current row under the pointer,
935                                 //which is only the case if the already selected rows don't include the one under
936                                 //the pointer yet
937                                 boolean reSelect = true;
938                                 for (int i = 0; i < selectedRows.length; i++) {
939                                         if (row == selectedRows[i]) {
940                                                 reSelect = false;
941                                                 break;
942                                         }
943                                 }
944                                 
945                                 if (row != -1 && reSelect) {
946                                         table.setRowSelectionInterval(row, row);
947                                 }
948                                 
949                                 this.configurePopupMenu();
950                                 configureTableButtons();
951                                 jobsTablePopupMenu.show(e.getComponent(), e.getX(), e.getY());
952                         }
953                 }
954                 
955                 private void configurePopupMenu() {
956                         //Disable all buttons first
957                         jobs_contextmenu_edit.setEnabled(false);
958                         jobs_contextmenu_duplicate.setEnabled(false);
959                         jobs_contextmenu_applytempl.setEnabled(false);
960                         jobs_contextmenu_delete.setEnabled(false);
961                         jobs_contextmenu_resetstate_waiting.setEnabled(false);
962                         jobs_contextmenu_resetstate_done.setEnabled(false);
963                         jobs_contextmenu_showerror.setEnabled(false);
964                         jobs_contextmenu_start.setEnabled(false);
965                         for (JMenuItem pluginItem : jobs_contextmenu_runPluginMenuItems) {
966                                 pluginItem.setEnabled(false);
967                         }
968                         
969                         //edit, duplicate, and show error buttons
970                         if (jobsTable.getSelectedRowCount() == 1) {
971                                 jobs_contextmenu_edit.setEnabled(true);
972                                 
973                                 //Show error button
974                                 List<RecordJob> selectedJobs = getSelectedRecordJobs(jobsTable);
975                                 RecordJob selectedJob = selectedJobs.get(0);
976                                 if (selectedJob.getState() == RecordJob.State.ERROR || selectedJob.getState() == RecordJob.State.ERROR_PLUGIN) {
977                                         jobs_contextmenu_showerror.setEnabled(true);
978                                 }
979                         }
980                         
981                         if (jobsTable.getSelectedRowCount() > 0) {
982                                 jobs_contextmenu_duplicate.setEnabled(true);
983                                 //Delete button
984                                 RecordJob.State[] states = {RecordJob.State.PROCESSING};
985                                 if (!checkJobStates(states, false)) {
986                                         //none of the jobs is processing
987                                         jobs_contextmenu_delete.setEnabled(true);
988                                         jobs_contextmenu_resetstate_waiting.setEnabled(true);
989                                         
990                                         if (templatesTable.getSelectedRowCount() == 1) {
991                                                 jobs_contextmenu_applytempl.setEnabled(true);
992                                         }
993                                 }
994                                 
995                                 //Start button
996                                 RecordJob.State[] states2 = {RecordJob.State.ERROR, RecordJob.State.DONE, RecordJob.State.PROCESSING, RecordJob.State.ERROR_PLUGIN};
997                                 if (!checkJobStates(states2, true)) {
998                                         //only enable start if none of the selected jobs as any of the States above
999                                         //as the only job State that is not listed is "waiting", we only enable the button if all jobs are waiting
1000                                         jobs_contextmenu_start.setEnabled(true);
1001                                 }
1002                                 
1003                                 //reset to 'done' button
1004                                 RecordJob.State[] states3 = {RecordJob.State.ERROR, RecordJob.State.WAITING, RecordJob.State.PROCESSING};
1005                                 if (!checkJobStates(states3, true)) {
1006                                         //only enable the "reset to done" button when processes have the state DONE or ERROR_PLUGIN
1007                                         jobs_contextmenu_resetstate_done.setEnabled(true);
1008                                 }
1009                                 
1010                                 //plugin buttons, enable only when state of the job is DONE
1011                                 RecordJob.State[] states4 = {RecordJob.State.ERROR, RecordJob.State.WAITING, RecordJob.State.PROCESSING, RecordJob.State.ERROR_PLUGIN};
1012                                 if (!checkJobStates(states4, true)) {
1013                                         int counter = 0;
1014                                         for (JMenuItem pluginItem : jobs_contextmenu_runPluginMenuItems) {
1015                                                 if (appLayer.getEncoderPlugins().get(counter).isEnabled()) {
1016                                                         pluginItem.setEnabled(true);
1017                                                 }
1018                                                 counter++;
1019                                         }
1020                                 }
1021                         }
1022                 }
1023                 
1024         }
1025         
1026         private class TemplatesTableMouseListener implements MouseListener {
1027
1028                 public void mouseClicked(MouseEvent e) {
1029                         if (e != null && e.getClickCount() == 2) {
1030                                 List<RecordJob> selectedJobs = getSelectedRecordJobs(templatesTable);
1031                                 if (selectedJobs.size() == 1) {
1032                                         RecordJobTemplate selectedJob = (RecordJobTemplate) selectedJobs.get(0);
1033                                         JobDialog jobDialog = new JobDialog(SwingGUI.this, selectedJob, appLayer, JobDialog.EDIT_TEMPLATE);
1034                                         jobDialog.showDialog();
1035                                         configureTableButtons();
1036                                 }
1037                         } else {
1038                                 configureTableButtons();
1039                         }
1040                 }
1041
1042                 public void mouseEntered(MouseEvent e) {}
1043
1044                 public void mouseExited(MouseEvent e) {}
1045
1046                 public void mousePressed(MouseEvent e) {
1047                         this.showPopupMenu(e);
1048                 }
1049
1050                 public void mouseReleased(MouseEvent e) {
1051                         this.showPopupMenu(e);
1052                 }
1053                 
1054                 private void showPopupMenu(MouseEvent e) {
1055                         if (e.isPopupTrigger()) {
1056                                 JTable table = (JTable)(e.getSource());
1057                                 Point p = e.getPoint();
1058                                 int row = table.rowAtPoint(p);
1059                                 int[] selectedRows = table.getSelectedRows();
1060                                 //figure out whether we have to reselect the current row under the pointer,
1061                                 //which is only the case if the already selected rows don't include the one under
1062                                 //the pointer yet
1063                                 boolean reSelect = true;
1064                                 for (int i = 0; i < selectedRows.length; i++) {
1065                                         if (row == selectedRows[i]) {
1066                                                 reSelect = false;
1067                                                 break;
1068                                         }
1069                                 }
1070                                 
1071                                 if (row != -1 && reSelect) {
1072                                         table.setRowSelectionInterval(row, row);
1073                                 }
1074                                 
1075                                 this.configurePopupMenu();
1076                                 configureTableButtons();
1077                                 templatesTablePopupMenu.show(e.getComponent(), e.getX(), e.getY());
1078                         }
1079                 }
1080                 
1081                 private void configurePopupMenu() {
1082                         //Various buttons
1083                         templ_contextmenu_edit.setEnabled(false);
1084                         templ_contextmenu_duplicate.setEnabled(false);
1085                         templ_contextmenu_delete.setEnabled(false);
1086                         
1087                         //Edit button
1088                         if (templatesTable.getSelectedRowCount() == 1) {
1089                                 templ_contextmenu_edit.setEnabled(true);
1090                         }
1091                         
1092                         //Delete and duplicate button
1093                         if (templatesTable.getSelectedRowCount() > 0) {
1094                                 templ_contextmenu_delete.setEnabled(true);
1095                                 templ_contextmenu_duplicate.setEnabled(true);
1096                         }
1097                 }
1098         }
1099                 
1100         private void showAboutBox() {
1101         try {
1102             InputStream inStream = ClassLoader.getSystemResourceAsStream("about.html");
1103             StringBuffer out = new StringBuffer();
1104             byte[] b = new byte[4096];
1105             for (int n; (n = inStream.read(b)) != -1;) {
1106                 out.append(new String(b, 0, n));
1107             }
1108             String htmlString = out.toString();
1109             htmlString = htmlString.replaceAll("[\\r\\n]", "");
1110             JOptionPane.showMessageDialog(this, htmlString, "About", JOptionPane.PLAIN_MESSAGE);
1111         } catch (IOException ex) {
1112             ex.printStackTrace();
1113         }
1114     }
1115
1116         public void windowActivated(WindowEvent e) {}
1117         public void windowClosed(WindowEvent e) {}
1118         public void windowDeactivated(WindowEvent e) {}
1119         public void windowDeiconified(WindowEvent e) {}
1120         public void windowIconified(WindowEvent e) {}
1121         public void windowOpened(WindowEvent e) {}
1122
1123         public void windowClosing(WindowEvent e) {
1124                 this.shutDown();
1125         }
1126
1127         private void shutDown() {
1128                 if (this.appLayer.getState() == DemoRecorderApplication.STATE_WORKING) {
1129                         int result = JOptionPane.showConfirmDialog(this, "There are still jobs being recorded. Are you sure you want to exit?", "Confirm close", JOptionPane.YES_NO_OPTION);
1130                         if (result == JOptionPane.NO_OPTION) {
1131                                 return;
1132                         }
1133                 }
1134                 saveTableStates(jobsTable);
1135                 saveTableStates(templatesTable);
1136                 saveTemplateTableContent();
1137                 this.appLayer.shutDown();
1138                 this.dispose();
1139                 System.exit(0);
1140         }
1141         
1142         private void saveTemplateTableContent() {
1143                 File path = DemoRecorderUtils.computeLocalFile(DemoRecorderApplication.PREFERENCES_DIRNAME, TEMPLATE_TABLE_CONTENT_FILENAME);
1144                 RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) templatesTable.getModel();
1145                 tableModel.saveTemplateListToFile(path);
1146         }
1147         
1148         private Icon getIcon(String iconString) {
1149                 URL url = ClassLoader.getSystemResource("icons/" + iconString);
1150                 Icon i = new ImageIcon(url);
1151                 return i;
1152         }
1153
1154 }