View Javadoc

1   /*
2    * Copyright 2006 - 2012 Christina Bohk and Roland Ewald
3    *  
4    * Licensed under the Apache License, Version 2.0 (the "License"); 
5    * you may not use this file except in compliance with the License. 
6    * You may obtain a copy of the License at 
7    *  
8    *  http://www.apache.org/licenses/LICENSE-2.0
9    *  
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License. 
15   */
16  package p3j.gui;
17  
18  import java.awt.BorderLayout;
19  import java.awt.Dimension;
20  import java.awt.Image;
21  import java.awt.event.ActionEvent;
22  import java.awt.event.ActionListener;
23  import java.awt.event.KeyEvent;
24  import java.awt.event.WindowAdapter;
25  import java.awt.event.WindowEvent;
26  import java.io.File;
27  import java.io.IOException;
28  import java.lang.reflect.InvocationTargetException;
29  import java.net.URI;
30  import java.util.List;
31  import java.util.Locale;
32  import java.util.logging.Level;
33  
34  import javax.swing.JButton;
35  import javax.swing.JDesktopPane;
36  import javax.swing.JFileChooser;
37  import javax.swing.JFrame;
38  import javax.swing.JMenu;
39  import javax.swing.JMenuBar;
40  import javax.swing.JMenuItem;
41  import javax.swing.JPanel;
42  import javax.swing.JSeparator;
43  import javax.swing.JSplitPane;
44  import javax.swing.JTabbedPane;
45  import javax.swing.JToolBar;
46  import javax.swing.KeyStroke;
47  import javax.swing.SwingWorker;
48  import javax.swing.UIManager;
49  
50  import org.jamesii.SimSystem;
51  import org.jamesii.core.experiments.BaseExperiment;
52  import org.jamesii.core.experiments.RunInformation;
53  import org.jamesii.core.experiments.instrumentation.computation.plugintype.ComputationInstrumenterFactory;
54  import org.jamesii.core.experiments.taskrunner.parallel.ParallelComputationTaskRunnerFactory;
55  import org.jamesii.core.experiments.taskrunner.plugintype.TaskRunnerFactory;
56  import org.jamesii.core.experiments.tasks.stoppolicy.plugintype.ComputationTaskStopPolicyFactory;
57  import org.jamesii.core.parameters.ParameterBlock;
58  import org.jamesii.core.parameters.ParameterizedFactory;
59  import org.jamesii.core.processor.plugintype.ProcessorFactory;
60  import org.jamesii.core.simulationrun.stoppolicy.SimTimeStopFactory;
61  import org.jamesii.gui.application.SplashScreen;
62  import org.jamesii.gui.application.resource.IconManager;
63  import org.jamesii.gui.experiment.ExperimentExecutorThreadPool;
64  import org.jamesii.gui.experiment.execution.ExperimentThread;
65  import org.jamesii.gui.utils.BasicUtilities;
66  
67  import p3j.database.DatabaseFactory;
68  import p3j.database.DatabaseType;
69  import p3j.gui.dialogs.CopyGenerationsDialog;
70  import p3j.gui.dialogs.DatabaseTypeSelectionDialog;
71  import p3j.gui.dialogs.ExecutionPreferencesDialog;
72  import p3j.gui.dialogs.NewProjectionDialog;
73  import p3j.gui.dialogs.PreferencesDialog;
74  import p3j.gui.dialogs.execstatus.ExecProgressInstrFactory;
75  import p3j.gui.misc.NavigationTreeTab;
76  import p3j.gui.misc.P3JConfigFile;
77  import p3j.gui.panels.WelcomePanel;
78  import p3j.gui.panels.dboverview.DatabaseOverviewPanel;
79  import p3j.gui.panels.projections.ProjectionTreePanel;
80  import p3j.gui.panels.results.ResultTreePanel;
81  import p3j.misc.LoadedProjectionFormatException;
82  import p3j.misc.Misc;
83  import p3j.misc.Serializer;
84  import p3j.misc.gui.GUI;
85  import p3j.pppm.ProjectionModel;
86  import p3j.pppm.readerwriter.database.PPPModelDatabaseReaderFactory;
87  import p3j.simulation.ExecutionMode;
88  import p3j.simulation.PPPMProcessorFactory;
89  import p3j.simulation.assignments.plugintype.ParamAssignmentGenFactory;
90  
91  import com.jgoodies.looks.HeaderStyle;
92  import com.jgoodies.looks.LookUtils;
93  import com.jgoodies.looks.Options;
94  import com.jgoodies.looks.plastic.PlasticLookAndFeel;
95  
96  /**
97   * Main user interface to P3J (singleton).
98   * 
99   * Created on July 16, 2006
100  * 
101  * @author Christina Bohk
102  * @author Roland Ewald
103  */
104 public final class P3J extends JFrame {
105 
106   /** Serialization ID. */
107   private static final long serialVersionUID = -142244898041811667L;
108 
109   /** Initial window width. */
110   static final int INITIAL_WIDTH = 1024;
111 
112   /** Initial window height. */
113   static final int INITIAL_HEIGHT = 768;
114 
115   /** Initial width of the projection/result tree tab-pane. */
116   static final int INITIAL_TREE_WIDTH = 300;
117 
118   /** Reference to singleton. */
119   private static P3J instance;
120 
121   /** The splash screen to be shown at startup. */
122   private static SplashScreen splashScreen;
123 
124   /** Current projection to be edited. */
125   private static ProjectionModel currentProjection;
126 
127   /** Serialization tool. */
128   private final Serializer serializer = new Serializer();
129 
130   // GUI elements
131 
132   /** The button to run a calculation. */
133   private final JButton runButton = GUI.createIconButton("run.gif", "Run");
134   {
135     runButton.addActionListener(new ActionListener() {
136       @Override
137       public void actionPerformed(ActionEvent e) {
138         startExperiment();
139       }
140     });
141   }
142 
143   /** The button in the toolbar shown the replication configurations. */
144   private JButton execPrefsButton = new JButton();
145   {
146     execPrefsButton.addActionListener(new ActionListener() {
147       @Override
148       public void actionPerformed(ActionEvent e) {
149         editExecutionPreferences();
150       }
151     });
152   }
153 
154   /** Main toolbar. */
155   private final JToolBar toolBar = new JToolBar();
156   {
157     toolBar.add(runButton);
158     toolBar.putClientProperty(Options.HEADER_STYLE_KEY, HeaderStyle.BOTH);
159     toolBar.putClientProperty(PlasticLookAndFeel.IS_3D_KEY, Boolean.FALSE);
160     toolBar.add(execPrefsButton);
161   }
162 
163   /** The desktop. */
164   private final JDesktopPane desktop = new JDesktopPane();
165 
166   /** File chooser to save scenario files. */
167   private final JFileChooser scenarioFileChooser = new JFileChooser();
168 
169   // File menu
170 
171   /** Menu to create a new scenario. */
172   private final JMenuItem newProjectionMenu = new JMenuItem("New projection",
173       KeyEvent.VK_N);
174   {
175     newProjectionMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
176         ActionEvent.CTRL_MASK));
177     newProjectionMenu.addActionListener(new ActionListener() {
178       @Override
179       public void actionPerformed(ActionEvent e) {
180         newProjection();
181       }
182     });
183   }
184 
185   /** Menu to load a scenario. */
186   private final JMenuItem openProjectionMenu = new JMenuItem(
187       "Open projection...", KeyEvent.VK_O);
188   {
189     openProjectionMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
190         ActionEvent.CTRL_MASK));
191     openProjectionMenu.addActionListener(new ActionListener() {
192       @Override
193       public void actionPerformed(ActionEvent e) {
194         loadProjection();
195       }
196     });
197   }
198 
199   /** Menu to quick-save. */
200   private final JMenuItem quickSaveProjectionMenu = new JMenuItem(
201       "Save projection", KeyEvent.VK_S);
202   {
203     quickSaveProjectionMenu.setAccelerator(KeyStroke.getKeyStroke(
204         KeyEvent.VK_S, ActionEvent.CTRL_MASK));
205     quickSaveProjectionMenu.addActionListener(new ActionListener() {
206       @Override
207       public void actionPerformed(ActionEvent e) {
208         if (currentProjectionFile == null) {
209           saveProjection();
210         } else {
211           quickSaveProjection(currentProjectionFile);
212         }
213       }
214     });
215   }
216 
217   /** Menu to save scenario. */
218   private final JMenuItem saveProjectionMenu = new JMenuItem(
219       "Save projection as...");
220   {
221     saveProjectionMenu.addActionListener(new ActionListener() {
222       @Override
223       public void actionPerformed(ActionEvent e) {
224         saveProjection();
225       }
226     });
227   }
228 
229   /** Menu to load results. */
230   private final JMenuItem loadResultsMenu = new JMenuItem("Load results...");
231   {
232     loadResultsMenu.setVisible(false); // TODO
233   }
234 
235   /** Menu to save results. */
236   private final JMenuItem saveResultsMenu = new JMenuItem("Save results...");
237   {
238     saveResultsMenu.setVisible(false); // TODO
239   }
240 
241   /** Menu to quick-save results. */
242   private final JMenuItem quickSaveResultsMenu = new JMenuItem("Save results");
243   {
244     quickSaveResultsMenu.setVisible(false); // TODO
245   }
246 
247   /** Menu to open preferences dialog. */
248   private final JMenuItem preferencesMenu = new JMenuItem("Preferences...");
249   {
250     preferencesMenu.addActionListener(new ActionListener() {
251       @Override
252       public void actionPerformed(ActionEvent e) {
253         editPreferences();
254       }
255     });
256   }
257 
258   /** Menu to open execution preferences dialog. */
259   private final JMenuItem execPreferencesMenu = new JMenuItem(
260       "Execution preferences...");
261   {
262     execPreferencesMenu.addActionListener(new ActionListener() {
263       @Override
264       public void actionPerformed(ActionEvent e) {
265         execPrefsButton.doClick();
266       }
267     });
268   }
269 
270   /** Menu to quit. */
271   private final JMenuItem quitMenu = new JMenuItem("Quit", KeyEvent.VK_Q);
272   {
273     quitMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
274         ActionEvent.CTRL_MASK));
275     quitMenu.addActionListener(new ActionListener() {
276       @Override
277       public void actionPerformed(ActionEvent e) {
278         quitApplication();
279       }
280     });
281   }
282 
283   /** File menu. */
284   private final JMenu fileMenu = new JMenu("File");
285   {
286     fileMenu.add(newProjectionMenu);
287     fileMenu.add(openProjectionMenu);
288     fileMenu.add(quickSaveProjectionMenu);
289     fileMenu.add(saveProjectionMenu);
290     // TODO: Implement binary result storage.
291     // fileMenu.add(new JSeparator());
292     fileMenu.add(loadResultsMenu);
293     fileMenu.add(quickSaveResultsMenu);
294     fileMenu.add(saveResultsMenu);
295     fileMenu.add(new JSeparator());
296     fileMenu.add(preferencesMenu);
297     fileMenu.add(execPreferencesMenu);
298     fileMenu.add(new JSeparator());
299     fileMenu.add(quitMenu);
300     fileMenu.setMnemonic(KeyEvent.VK_F);
301   }
302 
303   // Parameter menu
304 
305   /** Menu to edit sets. */
306   private final JMenuItem editSetsMenu = new JMenuItem("Edit Sets...");
307   {
308     editSetsMenu.addActionListener(new ActionListener() {
309       @Override
310       public void actionPerformed(ActionEvent e) {
311         editSets();
312       }
313     });
314   }
315 
316   /** Menu to edit Settypes. */
317   private final JMenuItem editSetTypesMenu = new JMenuItem("Edit Settypes...");
318   {
319     editSetTypesMenu.addActionListener(new ActionListener() {
320       @Override
321       public void actionPerformed(ActionEvent e) {
322         editSetTypes();
323       }
324     });
325 
326   }
327 
328   /** Menu to input a matrix quickly. */
329   private final JMenuItem quickMatrixInput = new JMenuItem(
330       "Quick Matrix Input...");
331   {
332     quickMatrixInput.addActionListener(new ActionListener() {
333       @Override
334       public void actionPerformed(ActionEvent e) {
335         inputMatrixQuickly();
336       }
337     });
338   }
339 
340   /** Menu to input a matrix quickly. */
341   private final JMenuItem copyGenerations = new JMenuItem("Copy Generations...");
342   {
343     copyGenerations.addActionListener(new ActionListener() {
344       @Override
345       public void actionPerformed(ActionEvent e) {
346         copyGenerations();
347       }
348     });
349   }
350 
351   /** Parameter menu. */
352   private final JMenu parameterMenu = new JMenu("Parameters");
353   {
354     parameterMenu.add(new JSeparator());
355     parameterMenu.add(editSetTypesMenu);
356     parameterMenu.add(editSetsMenu);
357     parameterMenu.add(new JSeparator());
358     parameterMenu.add(quickMatrixInput);
359     parameterMenu.add(copyGenerations);
360   }
361 
362   /** Menu to open info panel. */
363   private final JMenuItem infoMenu = new JMenuItem("Info (Welcome Screen)");
364   {
365     infoMenu.addActionListener(new ActionListener() {
366       @Override
367       public void actionPerformed(ActionEvent e) {
368         contentPanel.removeAll();
369         contentPanel.add(new WelcomePanel(), BorderLayout.CENTER);
370         pack();
371         repaint();
372       }
373     });
374   }
375 
376   /** Help menu. */
377   private final JMenu helpMenu = new JMenu("Help");
378   {
379     helpMenu.add(infoMenu);
380   }
381 
382   /** Main menu bar. */
383   private final JMenuBar menuBar = new JMenuBar();
384   {
385     menuBar.add(fileMenu);
386     // TODO: Redesign and refactor old parameter dialogs
387     // menuBar.add(parameterMenu);
388     menuBar.add(helpMenu);
389     menuBar.putClientProperty(Options.HEADER_STYLE_KEY, HeaderStyle.BOTH);
390     menuBar.putClientProperty(PlasticLookAndFeel.IS_3D_KEY, Boolean.FALSE);
391   }
392 
393   // Dialogs to be used
394 
395   /** Stores name of the last saved projection. */
396   private String currentProjectionFile;
397 
398   /** Large panel for displaying the content of a selected element. */
399   private JPanel contentPanel = new JPanel(GUI.getStdBorderLayout());
400 
401   /**
402    * The tabbed pane for viewing the different levels (database overview,
403    * structure of a single projection, etc).
404    */
405   private JTabbedPane tabbedPane = new JTabbedPane();
406 
407   /** Panel that allows navigation through the current projection. */
408   private ProjectionTreePanel projTreePanel = new ProjectionTreePanel(
409       getCurrentProjection(), contentPanel);
410 
411   /**
412    * Panel that allows navigation through the results of the current projection.
413    */
414   private ResultTreePanel resultsPanel = new ResultTreePanel(
415       getCurrentProjection(), contentPanel);
416 
417   /**
418    * Panel that allows to navigate through the overall database and load
419    * projection models etc.
420    */
421   private DatabaseOverviewPanel dbOverviewPanel;
422 
423   /** The configuration file. */
424   private final P3JConfigFile configFile = new P3JConfigFile();
425 
426   /**
427    * Default constructor.
428    */
429   private P3J() {
430 
431     try {
432       getConfigFile().readFile("./" + Misc.CONFIG_FILE);
433     } catch (Exception ex) {
434       getConfigFile().setFileName("./" + Misc.CONFIG_FILE);
435       getConfigFile().setDefaults();
436       try {
437         getConfigFile().writeFile();
438       } catch (Exception e) {
439         GUI.printErrorMessage(this,
440             "Error while writing default configuration file.",
441             "An error occurred while attempting to write the file '"
442                 + Misc.CONFIG_FILE + "':" + ex, ex);
443       }
444       GUI.printErrorMessage(this, "Error while loading configuration file.",
445           "An error occurred while attempting to read the file '"
446               + Misc.CONFIG_FILE + "' from the working directory:" + ex, ex);
447     }
448 
449     updateFromExecConfig();
450     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
451   }
452 
453   /**
454    * Edits the preferences.
455    */
456   protected void editPreferences() {
457 
458     DatabaseTypeSelectionDialog dbTypeDialog = new DatabaseTypeSelectionDialog(
459         this, (DatabaseType) getConfigFile().get(Misc.PREF_DB_TYPE));
460     dbTypeDialog.setVisible(true);
461 
462     // Check whether user cancelled
463     if (dbTypeDialog.getDBType() == null)
464       return;
465 
466     PreferencesDialog prefsDialog = new PreferencesDialog(this,
467         getConfigFile(), dbTypeDialog.getDBType());
468     prefsDialog.setVisible(true);
469     try {
470       getConfigFile().writeFile();
471     } catch (Exception ex) {
472       SimSystem.report(ex);
473       GUI.printErrorMessage(this, "Error writing configuration file.",
474           "An error occurred while attempting to write to file '"
475               + getConfigFile().getFileName() + "' in the working directory:"
476               + ex);
477     }
478     updateFromConfig();
479   }
480 
481   /**
482    * Edits the execution preferences.
483    */
484   protected void editExecutionPreferences() {
485     ExecutionPreferencesDialog execPrefsDialog = new ExecutionPreferencesDialog(
486         this);
487     execPrefsDialog.setVisible(true);
488     try {
489       getConfigFile().writeFile();
490     } catch (Exception ex) {
491       SimSystem.report(Level.SEVERE, "Error writing configuration file.", ex);
492       GUI.printErrorMessage(this, "Error writing configuration file.",
493           "An error occurred while attempting to write to file '"
494               + getConfigFile().getFileName() + "' in the working directory:"
495               + ex);
496     }
497     updateFromExecConfig();
498   }
499 
500   /**
501    * Displays a dialog to edit sets.
502    */
503   protected void editSets() {
504     // (new EditSetsDialog(this,
505     // P3J.getCurrentProjection())).setVisible(true);
506   }
507 
508   /**
509    * Displays a dialog to edit Settypes.
510    */
511   protected void editSetTypes() {
512     // (new EditSetTypesDialog(this,
513     // getCurrentProjection())).setVisible(true);
514   }
515 
516   /**
517    * Opens dialog to copy generations.
518    */
519   protected void copyGenerations() {
520     CopyGenerationsDialog cgd = new CopyGenerationsDialog(
521         getCurrentProjection(), this);
522     cgd.setVisible(true);
523   }
524 
525   /**
526    * Create a new scenario in database.
527    */
528   protected void newProjection() {
529     NewProjectionDialog newProjectionDialog = new NewProjectionDialog(this,
530         DatabaseFactory.getDatabaseSingleton());
531     newProjectionDialog.setVisible(true);
532     if (newProjectionDialog.hasCreatedNewProjection()) {
533       currentProjection = newProjectionDialog.getNewProjection();
534       projTreePanel.setProjection(currentProjection);
535       switchNavigationTreeTab(NavigationTreeTab.PROJECTION_OVERVIEW);
536       dbOverviewPanel.totalRefresh();
537     }
538   }
539 
540   /**
541    * Retrieves user interface singleton.
542    * 
543    * @return instance of P3J
544    */
545   public static P3J getInstance() {
546     if (instance == null) {
547       instance = new P3J();
548       instance.initUI();
549     }
550     return instance;
551   }
552 
553   /**
554    * Initializes user interface.
555    */
556   private void initUI() {
557 
558     this.setTitle("P3J : Probabilistic Population Projection");
559     this.setPreferredSize(new Dimension(INITIAL_WIDTH, INITIAL_HEIGHT));
560 
561     this.setJMenuBar(menuBar);
562     this.getContentPane().setLayout(new BorderLayout());
563     this.getContentPane().add(toolBar, BorderLayout.NORTH);
564     this.getContentPane().add(desktop, BorderLayout.CENTER);
565 
566     DatabaseFactory.setDbConnData(getConfigFile().getDBConnectionData());
567     currentProjection = null;
568     dbOverviewPanel = new DatabaseOverviewPanel(contentPanel);
569     projTreePanel = new ProjectionTreePanel(getCurrentProjection(),
570         contentPanel);
571 
572     tabbedPane.removeAll();
573     tabbedPane.addTab("Database", dbOverviewPanel);
574     tabbedPane.addTab("Projection", projTreePanel);
575     tabbedPane.addTab("Results", resultsPanel);
576     contentPanel.removeAll();
577     contentPanel.add(new WelcomePanel(), BorderLayout.CENTER);
578 
579     JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
580     splitPane.add(tabbedPane);
581     splitPane.setDividerLocation(INITIAL_TREE_WIDTH);
582     splitPane.add(contentPanel);
583 
584     this.getContentPane().add(splitPane);
585 
586     // Action handler: close window
587     this.addWindowListener(new WindowAdapter() {
588       @Override
589       public void windowClosing(WindowEvent l) {
590         P3J.this.quitApplication();
591       }
592     });
593 
594     this.pack();
595     this.repaint();
596   }
597 
598   /**
599    * Retrieves current PPP model.
600    * 
601    * @return the PPP model that is currently edited
602    */
603   public static ProjectionModel getCurrentProjection() {
604     return currentProjection;
605   }
606 
607   /**
608    * Save current projection.
609    */
610   void saveProjection() {
611 
612     if (currentProjection == null) {
613       GUI.printMessage(this, "No projection to save.",
614           "In order to save a projection, you first have to load it from the database.");
615       return;
616     }
617 
618     int userReaction = this.scenarioFileChooser.showDialog(this, "Save");
619 
620     if (userReaction != JFileChooser.ERROR_OPTION
621         && userReaction != JFileChooser.CANCEL_OPTION) {
622       File projectionFile = this.scenarioFileChooser.getSelectedFile();
623 
624       String ending = Misc.getFileEnding(projectionFile);
625 
626       if (ending.compareToIgnoreCase("p3j") != 0) {
627         projectionFile = new File(projectionFile.getAbsolutePath() + ".p3j");
628       }
629 
630       if (projectionFile != null
631           && (!projectionFile.exists() || projectionFile.canWrite())) {
632         quickSaveProjection(projectionFile.getAbsolutePath());
633       }
634 
635     }
636   }
637 
638   /**
639    * Quick-save current scenario.
640    * 
641    * @param scenarioFile
642    *          the file to which the scenario shall be saved
643    */
644   void quickSaveProjection(final String scenarioFile) {
645     (new SwingWorker<Void, Void>() {
646       @Override
647       protected Void doInBackground() throws Exception {
648         try {
649           serializer.save(getCurrentProjection(), scenarioFile);
650           currentProjectionFile = scenarioFile;
651         } catch (Exception ex) {
652           SimSystem.report(Level.SEVERE, "Error while saving scenario file.",
653               ex);
654           GUI.printErrorMessage(P3J.getInstance(),
655               "Error while saving scenario file.",
656               "An error occurred while attempting to save file to '"
657                   + scenarioFile + "': " + ex);
658         }
659         return null;
660       }
661     }).execute();
662 
663   }
664 
665   /**
666    * Load a scenario.
667    */
668   void loadProjection() {
669 
670     int userReaction = this.scenarioFileChooser.showDialog(this, "Open");
671 
672     if (userReaction != JFileChooser.ERROR_OPTION
673         && userReaction != JFileChooser.CANCEL_OPTION) {
674       final File scenarioFile = this.scenarioFileChooser.getSelectedFile();
675       final P3J owner = this;
676       if (scenarioFile != null && scenarioFile.exists()) {
677         (new SwingWorker<Void, Void>() {
678           @Override
679           protected Void doInBackground() throws Exception {
680             try {
681               ProjectionModel loadedModel = serializer.loadProjection(
682                   scenarioFile.getAbsolutePath(),
683                   DatabaseFactory.getDatabaseSingleton());
684               currentProjectionFile = scenarioFile.getAbsolutePath();
685               setCurrentProjection(loadedModel);
686             } catch (IOException | ClassNotFoundException ex) {
687               GUI.printErrorMessage(
688                   owner,
689                   "Error while opening scenario file.",
690                   "An error occurred while attempting to load file from '"
691                       + scenarioFile.getAbsolutePath() + "': "
692                       + ex.getMessage(), ex);
693             } catch (LoadedProjectionFormatException ex) {
694               GUI.printErrorMessage(owner,
695                   "Error while loading projection into database.",
696                   "An error occurred while attempting to load the projection:"
697                       + ex.getMessage(), ex);
698             }
699             return null;
700           }
701         }).execute();
702       }
703     }
704   }
705 
706   // Event Handler
707 
708   /**
709    * Quit application.
710    */
711   public void quitApplication() {
712     if (GUI.printQuestion(this, "Quit?", "Do you really want to quit?")) {
713       System.exit(0);
714     }
715   }
716 
717   /**
718    * Switches to a new projection model for editing.
719    * 
720    * @param newProjModel
721    *          the new projection model to be edited
722    */
723   public void setCurrentProjection(ProjectionModel newProjModel) {
724 
725     if (currentProjection != null) {
726       DatabaseFactory.getDatabaseSingleton().saveProjection(currentProjection);
727     }
728 
729     currentProjection = newProjModel;
730     dbOverviewPanel.totalRefresh();
731 
732     if (currentProjection != null) {
733       projTreePanel.setProjection(currentProjection);
734       resultsPanel.setProjection(currentProjection);
735       switchNavigationTreeTab(NavigationTreeTab.PROJECTION_OVERVIEW);
736     }
737   }
738 
739   /**
740    * Input a matrix quickly.
741    */
742   protected void inputMatrixQuickly() {
743     // (new QuickInputDialog(this,
744     // getCurrentProjection())).setVisible(true);
745   }
746 
747   /**
748    * Executed to run a calculation.
749    */
750   protected void startExperiment() {
751     BaseExperiment baseExperiment = new BaseExperiment();
752     configureModelLocation(baseExperiment);
753     configureSimulator(baseExperiment);
754     configureMultiThreading(baseExperiment);
755     ExperimentExecutorThreadPool.getInstance().getExecutor()
756         .execute(new ExperimentThread(baseExperiment) {
757           @Override
758           protected List<List<RunInformation>> doInBackground() {
759             List<List<RunInformation>> results = null;
760             try {
761               results = super.doInBackground();
762             } catch (Throwable t) {
763               GUI.printErrorMessage("Error executing model", t);
764             }
765             return results;
766           }
767         });
768   }
769 
770   /**
771    * Configures the given experiment for multi-threading.
772    * 
773    * @param baseExperiment
774    *          the experiment to be configured
775    */
776   private void configureMultiThreading(BaseExperiment baseExperiment) {
777     int numOfTrials = (Integer) getConfigFile().get(Misc.PREF_NUM_TRIALS);
778     int numOfThreads = (Integer) getConfigFile().get(
779         Misc.PREF_NUM_PARALLEL_THREADS);
780     double stopTime = Math.ceil((double) numOfTrials / numOfThreads);
781 
782     baseExperiment.setRepeatRuns(numOfThreads);
783     baseExperiment
784         .setComputationTaskStopPolicyFactory(new ParameterizedFactory<ComputationTaskStopPolicyFactory>(
785             new SimTimeStopFactory(), new ParameterBlock(stopTime,
786                 SimTimeStopFactory.SIMEND)));
787     baseExperiment
788         .setComputationInstrumenterFactory(new ParameterizedFactory<ComputationInstrumenterFactory>(
789             new ExecProgressInstrFactory(), new ParameterBlock(numOfTrials,
790                 ExecProgressInstrFactory.NUM_OF_TRIALS)));
791 
792     if (numOfThreads > 1) {
793       baseExperiment
794           .setTaskRunnerFactory(new ParameterizedFactory<TaskRunnerFactory>(
795               new ParallelComputationTaskRunnerFactory(), new ParameterBlock(
796                   numOfThreads, ParallelComputationTaskRunnerFactory.NUM_CORES)));
797     }
798   }
799 
800   /**
801    * Configures experiment to use PPPM simulator.
802    * 
803    * @param baseExperiment
804    *          the experiment to be configured
805    */
806   private void configureSimulator(BaseExperiment baseExperiment) {
807     ParameterBlock processorParameters = baseExperiment
808         .getParameters()
809         .getParameterBlock()
810         .addSubBlock(ProcessorFactory.class.getName(),
811             PPPMProcessorFactory.class.getName());
812     processorParameters.addSubBl(ParamAssignmentGenFactory.class.getName(),
813         ((ExecutionMode) getConfigFile().get(Misc.PREF_EXECUTION_MODE))
814             .getFactoryName());
815   }
816 
817   /**
818    * Configures experiment regarding model location.
819    * 
820    * @param baseExperiment
821    *          the experiment to be configured
822    */
823   private void configureModelLocation(BaseExperiment baseExperiment) {
824     try {
825       baseExperiment.setModelLocation(new URI(
826           PPPModelDatabaseReaderFactory.DEFAULT_URI));
827       baseExperiment.setModelRWParameters(PPPModelDatabaseReaderFactory
828           .createReaderParams(DatabaseFactory.getDbConnData(),
829               currentProjection.getID()));
830     } catch (Exception ex) {
831       GUI.printErrorMessage(this, "Could not configure model location",
832           "Configuration of model reader failed.", ex);
833     }
834   }
835 
836   /**
837    * Main function.
838    * 
839    * @param argv
840    *          command line arguments
841    */
842   public static void main(String[] argv) {
843 
844     showSplashScreen();
845     configureEnglishAsUILanguage();
846 
847     processCmdLineArgs(argv);
848 
849     try {
850       String lf = LookUtils.IS_OS_WINDOWS ? Options
851           .getCrossPlatformLookAndFeelClassName() : Options
852           .getSystemLookAndFeelClassName();
853       UIManager.setLookAndFeel(lf);
854     } catch (Exception e) {
855       SimSystem.report(e);
856     }
857 
858     P3J p3j = P3J.getInstance();
859     splashScreen.setVisible(false);
860     GUI.centerOnScreen(p3j);
861     p3j.setVisible(true);
862   }
863 
864   /**
865    * Configures English as UI language. Settings for localized names of default
866    * buttons are overridden.
867    */
868   private static void configureEnglishAsUILanguage() {
869     Locale.setDefault(Locale.US);
870     UIManager.put("OptionPane.yesButtonText", "Yes");
871     UIManager.put("OptionPane.noButtonText", "No");
872     UIManager.put("OptionPane.okButtonText", "OK");
873     UIManager.put("OptionPane.cancelButtonText", "Cancel");
874   }
875 
876   /**
877    * Process cmd line arguments.
878    * 
879    * @param argv
880    *          the argv
881    */
882   private static void processCmdLineArgs(String[] argv) {
883     if (argv.length > 0) {
884       SimSystem
885           .report(Level.WARNING,
886               "No command line arguments are currently supported. Arguments will be ignored.");
887     }
888   }
889 
890   /**
891    * Shows splash screen.
892    */
893   private static void showSplashScreen() {
894     try {
895       BasicUtilities.invokeAndWaitOnEDT(new Runnable() {
896         @Override
897         public void run() {
898           Image image = null;
899           try {
900             image = IconManager.getImage("image:/p3j/splashscreen.png");
901           } catch (Exception ex) {
902             SimSystem.report(ex);
903           }
904           splashScreen = new SplashScreen(image, "", "Version 0.9.8", "", true);
905           splashScreen.setVisible(true);
906           splashScreen.pack();
907         }
908       });
909     } catch (InterruptedException e1) {
910       SimSystem.report(e1);
911     } catch (InvocationTargetException e1) {
912       SimSystem.report(e1);
913     }
914   }
915 
916   /**
917    * Has to be called to refresh GUI after a {@link ProjectionModel} has been
918    * deleted.
919    * 
920    * @param deletedModel
921    *          the model that has been deleted from the database
922    */
923   public void projectionDeleted(ProjectionModel deletedModel) {
924     dbOverviewPanel.totalRefresh();
925     if (currentProjection != deletedModel) {
926       setCurrentProjection(null);
927       switchNavigationTreeTab(NavigationTreeTab.DB_OVERVIEW);
928     }
929   }
930 
931   /**
932    * Switch the navigation tree tab.
933    * 
934    * @param targetTab
935    *          the desired tab of the navigation tree
936    */
937   public void switchNavigationTreeTab(NavigationTreeTab targetTab) {
938     tabbedPane.setSelectedIndex(targetTab.getTabIndex());
939   }
940 
941   /**
942    * Update UI in case configuration changed.
943    */
944   private void updateFromConfig() {
945     this.getContentPane().removeAll();
946     initUI();
947   }
948 
949   /**
950    * Updates the summary of the execution preferences displayed on the buttons
951    * that opens them.
952    */
953   private void updateFromExecConfig() {
954     execPrefsButton.setText("#Trials:"
955         + getConfigFile().get(Misc.PREF_NUM_TRIALS) + ", #Threads:"
956         + getConfigFile().get(Misc.PREF_NUM_PARALLEL_THREADS) + ", Mode:"
957         + getConfigFile().get(Misc.PREF_EXECUTION_MODE));
958   }
959 
960   /**
961    * Get the configuration file.
962    * 
963    * @return the configFile
964    */
965   public P3JConfigFile getConfigFile() {
966     return configFile;
967   }
968 
969   /**
970    * Refreshes the navigation tree and selects the root node in the currently
971    * selected tab, so that all relevant GUI elements are refreshed.
972    */
973   public void refreshNavigationTree() {
974     NavigationTreeTab currentTab = NavigationTreeTab.values()[tabbedPane
975         .getSelectedIndex()];
976     setCurrentProjection(currentProjection);
977     switchNavigationTreeTab(currentTab);
978     switch (currentTab) {
979     case PROJECTION_OVERVIEW:
980       projTreePanel.selectRoot();
981       break;
982     case RESULTS_OVERVIEW:
983       resultsPanel.selectRoot();
984       break;
985     case DB_OVERVIEW:
986       dbOverviewPanel.selectRoot();
987       break;
988     default:
989       break;
990     }
991 
992   }
993 }