1 package com.nexuiz.demorecorder.ui.swinggui;
3 import java.awt.Container;
4 import java.awt.Dimension;
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;
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;
20 import java.util.ArrayList;
21 import java.util.List;
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;
42 import net.miginfocom.swing.MigLayout;
44 import org.jdesktop.swingx.JXTable;
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;
60 public class SwingGUI extends JFrame implements WindowListener, DemoRecorderUI {
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";
67 private DemoRecorderApplication appLayer;
68 private PreferencesDialog preferencesDialog;
70 private JXTable jobsTable = null;
71 private JPopupMenu jobsTablePopupMenu;
72 private ActionListener jobButtonActionListener = new JobButtonActionListener();
73 private MouseListener jobsTableMouseListener = new JobsTableMouseListener();
75 private JXTable templatesTable = null;
76 private JPopupMenu templatesTablePopupMenu;
77 private ActionListener templateButtonActionListener = new TemplateButtonActionListener();
78 private MouseListener templatesTableMouseListener = new TemplatesTableMouseListener();
80 private ActionListener recordButtonActionListener = new RecordButtonActionListener();
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'";
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";
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();
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>();
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"));
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"));
141 private StatusBar statusBar = new StatusBar();
143 private static HelpBroker mainHelpBroker = null;
144 private static final String mainHelpSetName = "help/DemoRecorderHelp.hs";
146 public SwingGUI(DemoRecorderApplication appLayer) {
147 super("Nexuiz Demo Recorder v0.3.1");
148 addWindowListener(this);
150 this.appLayer = appLayer;
154 this.preferencesDialog = new PreferencesDialog(this, appLayer);
156 setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
157 // Display the window.
160 //now that we have the GUI we can set the parent window for the error dialog
161 ShowErrorDialogExceptionHandler.setParentWindow(this);
164 private void setupHelp() {
165 if (mainHelpBroker == null){
166 HelpSet mainHelpSet = null;
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);
175 if (mainHelpSet != null)
176 mainHelpBroker = mainHelpSet.createHelpBroker();
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());
186 this.setupTemplatePanel();
187 this.setupJobPanel();
188 this.setupRecordPanel();
190 contentPane.add(statusBar, "south,height 23::");
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);
199 this.setupTemplatesTable();
200 this.loadTableStates(this.templatesTable);
201 JScrollPane templateScrollPane = new JScrollPane(templatesTable);
202 templatePanel.add(templateScrollPane);
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);
209 this.templ_contextmenu_edit.addActionListener(this.templateButtonActionListener);
210 this.templ_contextmenu_duplicate.addActionListener(this.templateButtonActionListener);
211 this.templ_contextmenu_delete.addActionListener(this.templateButtonActionListener);
213 this.configureTableButtons();
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);
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);
229 this.setupJobsTable();
230 this.loadTableStates(this.jobsTable);
232 JScrollPane jobScrollPane = new JScrollPane(jobsTable);
233 jobPanel.add(jobScrollPane);
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);
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);
249 //initialize button states
250 configureTableButtons();
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);
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);
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);
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);
286 public static void setSystemLAF() {
289 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
290 } catch (Exception e) {
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) {
301 //add job at the end of the table:
302 int position = jobsTableModel.getRowCount() - 1;
303 jobsTableModel.fireTableRowsInserted(position, position);
305 //job already existed
306 jobIndex = this.jobsTable.convertRowIndexToView(jobIndex); //convert due to possible view sorting
307 jobsTableModel.fireTableRowsUpdated(jobIndex, jobIndex);
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);
319 private JMenuBar buildMenu() {
320 JMenuBar menuBar = new JMenuBar();
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);
331 fileLoadQueue.addActionListener(menuButtonActionListener);
332 fileSaveQueue.addActionListener(menuButtonActionListener);
333 fileLoadTemplates.addActionListener(menuButtonActionListener);
334 fileSaveTemplates.addActionListener(menuButtonActionListener);
335 filePreferences.addActionListener(menuButtonActionListener);
336 fileExit.addActionListener(menuButtonActionListener);
338 JMenu helpMenu = new JMenu("Help");
339 helpMenu.add(helpHelp);
340 helpMenu.add(helpAbout);
341 menuBar.add(helpMenu);
343 helpHelp.addActionListener(menuButtonActionListener);
344 helpAbout.addActionListener(menuButtonActionListener);
346 this.setupEncoderPluginButtons();
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);
358 this.jobsTablePopupMenu.add(jobs_contextmenu_showerror);
359 this.jobsTablePopupMenu.add(jobs_contextmenu_resetstate_waiting);
360 this.jobsTablePopupMenu.add(jobs_contextmenu_resetstate_done);
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);
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);
381 private void saveTableStates(JXTable table) {
383 if (table == jobsTable) {
384 fileName = JOB_TABLE_PREFERENCES_FILENAME;
386 fileName = TEMPLATE_TABLE_PREFERENCES_FILENAME;
388 String exceptionMessage = "An error occurred while trying to save the table state file " + fileName;
390 XProperties.XTableProperty t = new XProperties.XTableProperty();
391 XTableState tableState;
393 tableState = (XTableState) t.getSessionState(table);
394 } catch (Exception e) { //most likely ClassCastException
395 DemoRecorderUtils.showNonCriticalErrorDialog(exceptionMessage, e, true);
399 File tableStateFile = DemoRecorderUtils.computeLocalFile(DemoRecorderApplication.PREFERENCES_DIRNAME, fileName);
400 DemoRecorderUtils.attemptFileCreation(tableStateFile);
403 FileOutputStream fout = new FileOutputStream(tableStateFile);
404 ObjectOutputStream oos = new ObjectOutputStream(fout);
405 oos.writeObject(tableState);
407 } catch (Exception e) {
408 DemoRecorderUtils.showNonCriticalErrorDialog(exceptionMessage, e, true);
412 private void loadTableStates(JXTable table) {
414 if (table == jobsTable) {
415 fileName = JOB_TABLE_PREFERENCES_FILENAME;
417 fileName = TEMPLATE_TABLE_PREFERENCES_FILENAME;
420 XProperties.XTableProperty t = new XProperties.XTableProperty();
422 File tableStateFile = DemoRecorderUtils.computeLocalFile(DemoRecorderApplication.PREFERENCES_DIRNAME, fileName);
424 XTableState tableState;
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);
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);
461 private class MenuButtonActionListener implements ActionListener {
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();
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");
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) {
489 appLayer.saveJobQueue(selectedFile);
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();
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");
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) {
514 RecordJobTemplatesTableModel model = (RecordJobTemplatesTableModel) templatesTable.getModel();
515 model.saveTemplateListToFile(selectedFile);
517 } else if (e.getSource() == filePreferences) {
518 preferencesDialog.showDialog();
519 } else if (e.getSource() == fileExit) {
521 } else if (e.getSource() == helpHelp) {
522 if (mainHelpBroker != null) {
523 mainHelpBroker.setDisplayed(true);
525 } else if (e.getSource() == helpAbout) {
533 * Listens to the clicks on buttons that are in the job panel (next to the jobs table)
534 * or its context menu.
536 private class JobButtonActionListener implements ActionListener {
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();
546 else if (e.getSource() == jobs_createFromTempl) {
547 if (selectedTemplates.size() != 1) {
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();
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();
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();
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();
576 } else if (e.getSource() == jobs_contextmenu_showerror) {
577 if (selectedJobs.size() == 1) {
578 RecordJob selectedJob = selectedJobs.get(0);
579 DemoRecorderUtils.showNonCriticalErrorDialog(selectedJob.getLastException());
581 } else if (e.getSource() == jobs_contextmenu_resetstate_waiting) {
582 for (RecordJob job : selectedJobs) {
583 job.setState(RecordJob.State.WAITING);
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);
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);
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();
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();
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);
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);
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,
630 job.getEngineParameters(),
632 job.getRelativeDemoPath(),
633 job.getDpVideoPath(),
634 job.getVideoDestination(),
635 job.getExecuteBeforeCap(),
636 job.getExecuteAfterCap(),
637 job.getStartSecond(),
640 newJob.setEncoderPluginSettings(job.getEncoderPluginSettings());
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();
654 else if (e.getSource() == templ_createFromJob) {
655 this.createTemplateFromJob();
656 configureTableButtons();
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);
663 configureTableButtons();
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);
670 configureTableButtons();
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();
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();
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",
701 job.getEngineParameters(),
702 job.getDemoFile().getParentFile(),
703 job.getRelativeDemoPath(),
704 job.getDpVideoPath(),
705 job.getVideoDestination().getParentFile(),
706 job.getExecuteBeforeCap(),
707 job.getExecuteAfterCap()
709 templ.setEncoderPluginSettings(job.getEncoderPluginSettings());
711 RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) templatesTable.getModel();
712 tableModel.addRecordJobTemplate(templ);
716 private void duplicateTemplates(List<RecordJob> selectedTemplates) {
717 for (RecordJob job : selectedTemplates) {
718 RecordJobTemplate template = (RecordJobTemplate) job;
719 RecordJobTemplate templ = new RecordJobTemplate(
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()
732 templ.setEncoderPluginSettings(template.getEncoderPluginSettings());
734 RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) templatesTable.getModel();
735 tableModel.addRecordJobTemplate(templ);
740 private class RecordButtonActionListener implements ActionListener {
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);
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);
760 private void deleteSelectedJobs(boolean deleteAllJobs) {
761 RecordJobsTableModel tableModel = (RecordJobsTableModel) jobsTable.getModel();
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);
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]);
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);
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]);
792 //update the button state of buttons dealing with jobs
793 this.configureTableButtons();
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).
800 * @param justSelectedJobs
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();
809 jobsToLookAt = getSelectedRecordJobs(jobsTable);
812 for (RecordJob currentJob : jobsToLookAt) {
813 for (int i = 0; i < state.length; i++) {
814 if (currentJob.getState() == state[i]) {
824 * Returns the list of selected RecordJobs or RecordJobTemplates.
825 * @param table jobsTable or templatesTable
826 * @return list of selected RecordJobs or RecordJobTemplates
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);
841 RecordJobTemplatesTableModel tableModel = (RecordJobTemplatesTableModel) table.getModel();
842 RecordJobTemplate template = tableModel.getRecordJobTemplate(modelRowIndex);
843 if (template != null) {
853 private void configureTableButtons() {
854 if (jobsTable != null) {
855 if (jobsTable.getRowCount() == 0) {
856 jobs_clear.setEnabled(false);
857 jobs_delete.setEnabled(false);
859 jobs_clear.setEnabled(true);
860 jobs_delete.setEnabled(true);
861 if (jobsTable.getSelectedRowCount() == 0) {
862 jobs_delete.setEnabled(false);
864 //go through all elements and check for attributes PROCESSING
865 RecordJob.State[] lookForState = {RecordJob.State.PROCESSING};
866 boolean foundState = checkJobStates(lookForState, false);
868 //we have to disable the clear and delete button
869 jobs_delete.setEnabled(false);
873 if (templatesTable.getSelectedRowCount() == 1) {
874 jobs_createFromTempl.setEnabled(true);
876 jobs_createFromTempl.setEnabled(false);
880 if (templatesTable != null) {
881 templ_createFromJob.setEnabled(false);
882 templ_delete.setEnabled(false);
883 templ_clear.setEnabled(false);
885 if (jobsTable != null && jobsTable.getSelectedRowCount() == 1) {
886 templ_createFromJob.setEnabled(true);
889 if (templatesTable.getSelectedRowCount() > 0) {
890 templ_delete.setEnabled(true);
893 if (templatesTable.getRowCount() > 0) {
894 templ_clear.setEnabled(true);
899 private class JobsTableMouseListener implements MouseListener {
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();
912 configureTableButtons();
916 public void mouseEntered(MouseEvent e) {}
918 public void mouseExited(MouseEvent e) {}
920 public void mousePressed(MouseEvent e) {
921 this.showPopupMenu(e);
924 public void mouseReleased(MouseEvent e) {
925 this.showPopupMenu(e);
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
937 boolean reSelect = true;
938 for (int i = 0; i < selectedRows.length; i++) {
939 if (row == selectedRows[i]) {
945 if (row != -1 && reSelect) {
946 table.setRowSelectionInterval(row, row);
949 this.configurePopupMenu();
950 configureTableButtons();
951 jobsTablePopupMenu.show(e.getComponent(), e.getX(), e.getY());
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);
969 //edit, duplicate, and show error buttons
970 if (jobsTable.getSelectedRowCount() == 1) {
971 jobs_contextmenu_edit.setEnabled(true);
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);
981 if (jobsTable.getSelectedRowCount() > 0) {
982 jobs_contextmenu_duplicate.setEnabled(true);
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);
990 if (templatesTable.getSelectedRowCount() == 1) {
991 jobs_contextmenu_applytempl.setEnabled(true);
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);
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);
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)) {
1014 for (JMenuItem pluginItem : jobs_contextmenu_runPluginMenuItems) {
1015 if (appLayer.getEncoderPlugins().get(counter).isEnabled()) {
1016 pluginItem.setEnabled(true);
1026 private class TemplatesTableMouseListener implements MouseListener {
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();
1038 configureTableButtons();
1042 public void mouseEntered(MouseEvent e) {}
1044 public void mouseExited(MouseEvent e) {}
1046 public void mousePressed(MouseEvent e) {
1047 this.showPopupMenu(e);
1050 public void mouseReleased(MouseEvent e) {
1051 this.showPopupMenu(e);
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
1063 boolean reSelect = true;
1064 for (int i = 0; i < selectedRows.length; i++) {
1065 if (row == selectedRows[i]) {
1071 if (row != -1 && reSelect) {
1072 table.setRowSelectionInterval(row, row);
1075 this.configurePopupMenu();
1076 configureTableButtons();
1077 templatesTablePopupMenu.show(e.getComponent(), e.getX(), e.getY());
1081 private void configurePopupMenu() {
1083 templ_contextmenu_edit.setEnabled(false);
1084 templ_contextmenu_duplicate.setEnabled(false);
1085 templ_contextmenu_delete.setEnabled(false);
1088 if (templatesTable.getSelectedRowCount() == 1) {
1089 templ_contextmenu_edit.setEnabled(true);
1092 //Delete and duplicate button
1093 if (templatesTable.getSelectedRowCount() > 0) {
1094 templ_contextmenu_delete.setEnabled(true);
1095 templ_contextmenu_duplicate.setEnabled(true);
1100 private void showAboutBox() {
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));
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();
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) {}
1123 public void windowClosing(WindowEvent e) {
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) {
1134 saveTableStates(jobsTable);
1135 saveTableStates(templatesTable);
1136 saveTemplateTableContent();
1137 this.appLayer.shutDown();
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);
1148 private Icon getIcon(String iconString) {
1149 URL url = ClassLoader.getSystemResource("icons/" + iconString);
1150 Icon i = new ImageIcon(url);