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 james.SimSystem;
19  import james.core.experiments.BaseExperiment;
20  import james.core.experiments.RunInformation;
21  import james.core.experiments.taskrunner.parallel.ParallelComputationTaskRunnerFactory;
22  import james.core.experiments.taskrunner.plugintype.TaskRunnerFactory;
23  import james.core.parameters.ParameterBlock;
24  import james.core.parameters.ParameterizedFactory;
25  import james.core.processor.plugintype.ProcessorFactory;
26  import james.gui.application.SplashScreen;
27  import james.gui.application.resource.IconManager;
28  import james.gui.experiment.ExperimentExecutorThreadPool;
29  import james.gui.experiment.execution.ExperimentThread;
30  import james.gui.utils.BasicUtilities;
31  
32  import java.awt.BorderLayout;
33  import java.awt.Dimension;
34  import java.awt.Image;
35  import java.awt.event.ActionEvent;
36  import java.awt.event.ActionListener;
37  import java.awt.event.KeyEvent;
38  import java.awt.event.WindowAdapter;
39  import java.awt.event.WindowEvent;
40  import java.io.File;
41  import java.io.IOException;
42  import java.lang.reflect.InvocationTargetException;
43  import java.net.URI;
44  import java.util.List;
45  import java.util.Locale;
46  import java.util.logging.Level;
47  
48  import javax.swing.Icon;
49  import javax.swing.ImageIcon;
50  import javax.swing.JButton;
51  import javax.swing.JDesktopPane;
52  import javax.swing.JFileChooser;
53  import javax.swing.JFrame;
54  import javax.swing.JMenu;
55  import javax.swing.JMenuBar;
56  import javax.swing.JMenuItem;
57  import javax.swing.JPanel;
58  import javax.swing.JSeparator;
59  import javax.swing.JSplitPane;
60  import javax.swing.JTabbedPane;
61  import javax.swing.JToolBar;
62  import javax.swing.KeyStroke;
63  import javax.swing.SwingWorker;
64  import javax.swing.UIManager;
65  
66  import p3j.database.DatabaseFactory;
67  import p3j.database.DatabaseType;
68  import p3j.gui.dialogs.CopyGenerationsDialog;
69  import p3j.gui.dialogs.DatabaseTypeSelectionDialog;
70  import p3j.gui.dialogs.ExecutionPreferencesDialog;
71  import p3j.gui.dialogs.NewProjectionDialog;
72  import p3j.gui.dialogs.PreferencesDialog;
73  import p3j.gui.dialogs.execstatus.ExecProgressInstrFactory;
74  import p3j.gui.misc.NavigationTreeTab;
75  import p3j.gui.misc.P3JConfigFile;
76  import p3j.gui.panels.WelcomePanel;
77  import p3j.gui.panels.dboverview.DatabaseOverviewPanel;
78  import p3j.gui.panels.projections.ProjectionTreePanel;
79  import p3j.gui.panels.results.ResultTreePanel;
80  import p3j.misc.LoadedProjectionFormatException;
81  import p3j.misc.Misc;
82  import p3j.misc.Serializer;
83  import p3j.misc.gui.GUI;
84  import p3j.pppm.ProjectionModel;
85  import p3j.pppm.readerwriter.database.PPPModelDatabaseReaderFactory;
86  import p3j.simulation.ExecutionMode;
87  import p3j.simulation.PPPMProcessorFactory;
88  import p3j.simulation.assignments.plugintype.ParamAssignmentGenFactory;
89  
90  import com.jgoodies.looks.HeaderStyle;
91  import com.jgoodies.looks.LookUtils;
92  import com.jgoodies.looks.Options;
93  import com.jgoodies.looks.plastic.PlasticLookAndFeel;
94  
95  /**
96   * Main user interface to P3J (singleton).
97   * 
98   * Created on July 16, 2006
99   * 
100  * @author Christina Bohk
101  * @author Roland Ewald
102  */
103 public final class P3J extends JFrame {
104 
105   /** Serialization ID. */
106   private static final long serialVersionUID = -142244898041811667L;
107 
108   /** Initial window width. */
109   static final int INITIAL_WIDTH = 1024;
110 
111   /** Initial window height. */
112   static final int INITIAL_HEIGHT = 768;
113 
114   /** Initial width of the projection/result tree tab-pane. */
115   static final int INITIAL_TREE_WIDTH = 300;
116 
117   /** Reference to singleton. */
118   private static P3J instance;
119 
120   /** The splash screen to be shown at startup. */
121   private static SplashScreen splashScreen;
122 
123   /** Current projection to be edited. */
124   private static ProjectionModel currentProjection;
125 
126   /** Serialization tool. */
127   private final Serializer serializer = new Serializer();
128 
129   // GUI elements
130 
131   /** Icon for the run button. */
132   private final Icon runIcon = new ImageIcon(this.getClass().getResource(
133       "/p3j/icons/run.gif"));
134 
135   /** The button to run a calculation. */
136   private final JButton runButton = new JButton(runIcon);
137   {
138     runButton.addActionListener(new ActionListener() {
139       @Override
140       public void actionPerformed(ActionEvent e) {
141         startExperiment();
142       }
143     });
144   }
145 
146   /** The button in the toolbar shown the replication configurations. */
147   private JButton execPrefsButton = new JButton();
148   {
149     execPrefsButton.addActionListener(new ActionListener() {
150       @Override
151       public void actionPerformed(ActionEvent e) {
152         editExecutionPreferences();
153       }
154     });
155   }
156 
157   /** Main toolbar. */
158   private final JToolBar toolBar = new JToolBar();
159   {
160     toolBar.add(runButton);
161     toolBar.putClientProperty(Options.HEADER_STYLE_KEY, HeaderStyle.BOTH);
162     toolBar.putClientProperty(PlasticLookAndFeel.IS_3D_KEY, Boolean.FALSE);
163     toolBar.add(execPrefsButton);
164   }
165 
166   /** The desktop. */
167   private final JDesktopPane desktop = new JDesktopPane();
168 
169   /** File chooser to save scenario files. */
170   private final JFileChooser scenarioFileChooser = new JFileChooser();
171 
172   // File menu
173 
174   /** Menu to create a new scenario. */
175   private final JMenuItem newProjectionMenu = new JMenuItem("New projection",
176       KeyEvent.VK_N);
177   {
178     newProjectionMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
179         ActionEvent.CTRL_MASK));
180     newProjectionMenu.addActionListener(new ActionListener() {
181       @Override
182       public void actionPerformed(ActionEvent e) {
183         newProjection();
184       }
185     });
186   }
187 
188   /** Menu to load a scenario. */
189   private final JMenuItem openProjectionMenu = new JMenuItem(
190       "Open projection...", KeyEvent.VK_O);
191   {
192     openProjectionMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
193         ActionEvent.CTRL_MASK));
194     openProjectionMenu.addActionListener(new ActionListener() {
195       @Override
196       public void actionPerformed(ActionEvent e) {
197         loadProjection();
198       }
199     });
200   }
201 
202   /** Menu to quick-save. */
203   private final JMenuItem quickSaveProjectionMenu = new JMenuItem(
204       "Save projection", KeyEvent.VK_S);
205   {
206     quickSaveProjectionMenu.setAccelerator(KeyStroke.getKeyStroke(
207         KeyEvent.VK_S, ActionEvent.CTRL_MASK));
208     quickSaveProjectionMenu.addActionListener(new ActionListener() {
209       @Override
210       public void actionPerformed(ActionEvent e) {
211         if (currentProjectionFile == null) {
212           saveProjection();
213         } else {
214           quickSaveProjection(currentProjectionFile);
215         }
216       }
217     });
218   }
219 
220   /** Menu to save scenario. */
221   private final JMenuItem saveProjectionMenu = new JMenuItem(
222       "Save projection as...");
223   {
224     saveProjectionMenu.addActionListener(new ActionListener() {
225       @Override
226       public void actionPerformed(ActionEvent e) {
227         saveProjection();
228       }
229     });
230   }
231 
232   /** Menu to load results. */
233   private final JMenuItem loadResultsMenu = new JMenuItem("Load results...");
234   {
235     loadResultsMenu.setVisible(false); // TODO
236   }
237 
238   /** Menu to save results. */
239   private final JMenuItem saveResultsMenu = new JMenuItem("Save results...");
240   {
241     saveResultsMenu.setVisible(false); // TODO
242   }
243 
244   /** Menu to quick-save results. */
245   private final JMenuItem quickSaveResultsMenu = new JMenuItem("Save results");
246   {
247     quickSaveResultsMenu.setVisible(false); // TODO
248   }
249 
250   /** Menu to open preferences dialog. */
251   private final JMenuItem preferencesMenu = new JMenuItem("Preferences...");
252   {
253     preferencesMenu.addActionListener(new ActionListener() {
254       @Override
255       public void actionPerformed(ActionEvent e) {
256         editPreferences();
257       }
258     });
259   }
260 
261   /** Menu to open execution preferences dialog. */
262   private final JMenuItem execPreferencesMenu = new JMenuItem(
263       "Execution preferences...");
264   {
265     execPreferencesMenu.addActionListener(new ActionListener() {
266       @Override
267       public void actionPerformed(ActionEvent e) {
268         execPrefsButton.doClick();
269       }
270     });
271   }
272 
273   /** Menu to quit. */
274   private final JMenuItem quitMenu = new JMenuItem("Quit", KeyEvent.VK_Q);
275   {
276     quitMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
277         ActionEvent.CTRL_MASK));
278     quitMenu.addActionListener(new ActionListener() {
279       @Override
280       public void actionPerformed(ActionEvent e) {
281         quitApplication();
282       }
283     });
284   }
285 
286   /** File menu. */
287   private final JMenu fileMenu = new JMenu("File");
288   {
289     fileMenu.add(newProjectionMenu);
290     fileMenu.add(openProjectionMenu);
291     fileMenu.add(quickSaveProjectionMenu);
292     fileMenu.add(saveProjectionMenu);
293     // TODO: Implement binary result storage.
294     // fileMenu.add(new JSeparator());
295     fileMenu.add(loadResultsMenu);
296     fileMenu.add(quickSaveResultsMenu);
297     fileMenu.add(saveResultsMenu);
298     fileMenu.add(new JSeparator());
299     fileMenu.add(preferencesMenu);
300     fileMenu.add(execPreferencesMenu);
301     fileMenu.add(new JSeparator());
302     fileMenu.add(quitMenu);
303     fileMenu.setMnemonic(KeyEvent.VK_F);
304   }
305 
306   // Parameter menu
307 
308   /** Menu to edit sets. */
309   private final JMenuItem editSetsMenu = new JMenuItem("Edit Sets...");
310   {
311     editSetsMenu.addActionListener(new ActionListener() {
312       @Override
313       public void actionPerformed(ActionEvent e) {
314         editSets();
315       }
316     });
317   }
318 
319   /** Menu to edit Settypes. */
320   private final JMenuItem editSetTypesMenu = new JMenuItem("Edit Settypes...");
321   {
322     editSetTypesMenu.addActionListener(new ActionListener() {
323       @Override
324       public void actionPerformed(ActionEvent e) {
325         editSetTypes();
326       }
327     });
328 
329   }
330 
331   /** Menu to input a matrix quickly. */
332   private final JMenuItem quickMatrixInput = new JMenuItem(
333       "Quick Matrix Input...");
334   {
335     quickMatrixInput.addActionListener(new ActionListener() {
336       @Override
337       public void actionPerformed(ActionEvent e) {
338         inputMatrixQuickly();
339       }
340     });
341   }
342 
343   /** Menu to input a matrix quickly. */
344   private final JMenuItem copyGenerations = new JMenuItem("Copy Generations...");
345   {
346     copyGenerations.addActionListener(new ActionListener() {
347       @Override
348       public void actionPerformed(ActionEvent e) {
349         copyGenerations();
350       }
351     });
352   }
353 
354   /** Parameter menu. */
355   private final JMenu parameterMenu = new JMenu("Parameters");
356   {
357     parameterMenu.add(new JSeparator());
358     parameterMenu.add(editSetTypesMenu);
359     parameterMenu.add(editSetsMenu);
360     parameterMenu.add(new JSeparator());
361     parameterMenu.add(quickMatrixInput);
362     parameterMenu.add(copyGenerations);
363   }
364 
365   /** Menu to open info panel. */
366   private final JMenuItem infoMenu = new JMenuItem("Info (Welcome Screen)");
367   {
368     infoMenu.addActionListener(new ActionListener() {
369       @Override
370       public void actionPerformed(ActionEvent e) {
371         contentPanel.removeAll();
372         contentPanel.add(new WelcomePanel(), BorderLayout.CENTER);
373         pack();
374         repaint();
375       }
376     });
377   }
378 
379   /** Help menu. */
380   private final JMenu helpMenu = new JMenu("Help");
381   {
382     helpMenu.add(infoMenu);
383   }
384 
385   /** Main menu bar. */
386   private final JMenuBar menuBar = new JMenuBar();
387   {
388     menuBar.add(fileMenu);
389     // TODO: Redesign and refactor old parameter dialogs
390     // menuBar.add(parameterMenu);
391     menuBar.add(helpMenu);
392     menuBar.putClientProperty(Options.HEADER_STYLE_KEY, HeaderStyle.BOTH);
393     menuBar.putClientProperty(PlasticLookAndFeel.IS_3D_KEY, Boolean.FALSE);
394   }
395 
396   // Dialogs to be used
397 
398   /** Stores name of the last saved projection. */
399   private String currentProjectionFile;
400 
401   /** Large panel for displaying the content of a selected element. */
402   private JPanel contentPanel = new JPanel(GUI.getStdBorderLayout());
403 
404   /**
405    * The tabbed pane for viewing the different levels (database overview,
406    * structure of a single projection, etc).
407    */
408   private JTabbedPane tabbedPane = new JTabbedPane();
409 
410   /** Panel that allows navigation through the current projection. */
411   private ProjectionTreePanel projTreePanel = new ProjectionTreePanel(
412       getCurrentProjection(), contentPanel);
413 
414   /**
415    * Panel that allows navigation through the results of the current projection.
416    */
417   private ResultTreePanel resultsPanel = new ResultTreePanel(
418       getCurrentProjection(), contentPanel);
419 
420   /**
421    * Panel that allows to navigate through the overall database and load
422    * projection models etc.
423    */
424   private DatabaseOverviewPanel dbOverviewPanel;
425 
426   /** The configuration file. */
427   private final P3JConfigFile configFile = new P3JConfigFile();
428 
429   /**
430    * Default constructor.
431    */
432   private P3J() {
433 
434     try {
435       getConfigFile().readFile("./" + Misc.CONFIG_FILE);
436     } catch (Exception ex) {
437       getConfigFile().setFileName("./" + Misc.CONFIG_FILE);
438       getConfigFile().setDefaults();
439       try {
440         getConfigFile().writeFile();
441       } catch (Exception e) {
442         GUI.printErrorMessage(this,
443             "Error while writing default configuration file.",
444             "An error occurred while attempting to write the file '"
445                 + Misc.CONFIG_FILE + "':" + ex, ex);
446       }
447       GUI.printErrorMessage(this, "Error while loading configuration file.",
448           "An error occurred while attempting to read the file '"
449               + Misc.CONFIG_FILE + "' from the working directory:" + ex, ex);
450     }
451 
452     updateFromExecConfig();
453     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
454   }
455 
456   /**
457    * Edits the preferences.
458    */
459   protected void editPreferences() {
460     
461     DatabaseTypeSelectionDialog dbTypeDialog = new DatabaseTypeSelectionDialog(
462         this, (DatabaseType) getConfigFile().get(Misc.PREF_DB_TYPE));
463     dbTypeDialog.setVisible(true);
464     
465     // Check whether user cancelled
466     if (dbTypeDialog.getDBType() == null)
467       return;
468 
469     PreferencesDialog prefsDialog = new PreferencesDialog(this,
470         getConfigFile(), dbTypeDialog.getDBType());
471     prefsDialog.setVisible(true);
472     try {
473       getConfigFile().writeFile();
474     } catch (Exception ex) {
475       SimSystem.report(ex);
476       GUI.printErrorMessage(this, "Error writing configuration file.",
477           "An error occurred while attempting to write to file '"
478               + getConfigFile().getFileName() + "' in the working directory:"
479               + ex);
480     }
481     updateFromConfig();
482   }
483 
484   /**
485    * Edits the execution preferences.
486    */
487   protected void editExecutionPreferences() {
488     ExecutionPreferencesDialog execPrefsDialog = new ExecutionPreferencesDialog(
489         this);
490     execPrefsDialog.setVisible(true);
491     try {
492       getConfigFile().writeFile();
493     } catch (Exception ex) {
494       SimSystem.report(Level.SEVERE, "Error writing configuration file.", ex);
495       GUI.printErrorMessage(this, "Error writing configuration file.",
496           "An error occurred while attempting to write to file '"
497               + getConfigFile().getFileName() + "' in the working directory:"
498               + ex);
499     }
500     updateFromExecConfig();
501   }
502 
503   /**
504    * Displays a dialog to edit sets.
505    */
506   protected void editSets() {
507     // (new EditSetsDialog(this,
508     // P3J.getCurrentProjection())).setVisible(true);
509   }
510 
511   /**
512    * Displays a dialog to edit Settypes.
513    */
514   protected void editSetTypes() {
515     // (new EditSetTypesDialog(this,
516     // getCurrentProjection())).setVisible(true);
517   }
518 
519   /**
520    * Opens dialog to copy generations.
521    */
522   protected void copyGenerations() {
523     CopyGenerationsDialog cgd = new CopyGenerationsDialog(
524         getCurrentProjection(), this);
525     cgd.setVisible(true);
526   }
527 
528   /**
529    * Create a new scenario in database.
530    */
531   protected void newProjection() {
532     NewProjectionDialog newProjectionDialog = new NewProjectionDialog(this,
533         DatabaseFactory.getDatabaseSingleton());
534     newProjectionDialog.setVisible(true);
535     if (newProjectionDialog.hasCreatedNewProjection()) {
536       currentProjection = newProjectionDialog.getNewProjection();
537       projTreePanel.setProjection(currentProjection);
538       switchNavigationTreeTab(NavigationTreeTab.PROJECTION_OVERVIEW);
539       dbOverviewPanel.totalRefresh();
540     }
541   }
542 
543   /**
544    * Retrieves user interface singleton.
545    * 
546    * @return instance of P3J
547    */
548   public static P3J getInstance() {
549     if (instance == null) {
550       instance = new P3J();
551       instance.initUI();
552     }
553     return instance;
554   }
555 
556   /**
557    * Initializes user interface.
558    */
559   private void initUI() {
560 
561     this.setTitle("P3J : Probabilistic Population Projection");
562     this.setPreferredSize(new Dimension(INITIAL_WIDTH, INITIAL_HEIGHT));
563 
564     this.setJMenuBar(menuBar);
565     this.getContentPane().setLayout(new BorderLayout());
566     this.getContentPane().add(toolBar, BorderLayout.NORTH);
567     this.getContentPane().add(desktop, BorderLayout.CENTER);
568 
569     DatabaseFactory.setDbConnData(getConfigFile().getDBConnectionData());
570     currentProjection = null;
571     dbOverviewPanel = new DatabaseOverviewPanel(contentPanel);
572     projTreePanel = new ProjectionTreePanel(getCurrentProjection(),
573         contentPanel);
574 
575     tabbedPane.removeAll();
576     tabbedPane.addTab("Database", dbOverviewPanel);
577     tabbedPane.addTab("Projection", projTreePanel);
578     tabbedPane.addTab("Results", resultsPanel);
579     contentPanel.removeAll();
580     contentPanel.add(new WelcomePanel(), BorderLayout.CENTER);
581 
582     JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
583     splitPane.add(tabbedPane);
584     splitPane.setDividerLocation(INITIAL_TREE_WIDTH);
585     splitPane.add(contentPanel);
586 
587     this.getContentPane().add(splitPane);
588 
589     // Action handler: close window
590     this.addWindowListener(new WindowAdapter() {
591       @Override
592       public void windowClosing(WindowEvent l) {
593         P3J.this.quitApplication();
594       }
595     });
596 
597     this.pack();
598     this.repaint();
599   }
600 
601   /**
602    * Retrieves current PPP model.
603    * 
604    * @return the PPP model that is currently edited
605    */
606   public static ProjectionModel getCurrentProjection() {
607     return currentProjection;
608   }
609 
610   /**
611    * Save current projection.
612    */
613   void saveProjection() {
614 
615     if (currentProjection == null) {
616       GUI.printMessage(this, "No projection to save.",
617           "In order to save a projection, you first have to load it from the database.");
618       return;
619     }
620 
621     int userReaction = this.scenarioFileChooser.showDialog(this, "Save");
622 
623     if (userReaction != JFileChooser.ERROR_OPTION
624         && userReaction != JFileChooser.CANCEL_OPTION) {
625       File projectionFile = this.scenarioFileChooser.getSelectedFile();
626 
627       String ending = Misc.getFileEnding(projectionFile);
628 
629       if (ending.compareToIgnoreCase("p3j") != 0) {
630         projectionFile = new File(projectionFile.getAbsolutePath() + ".p3j");
631       }
632 
633       if (projectionFile != null
634           && (!projectionFile.exists() || projectionFile.canWrite())) {
635         quickSaveProjection(projectionFile.getAbsolutePath());
636       }
637 
638     }
639   }
640 
641   /**
642    * Quick-save current scenario.
643    * 
644    * @param scenarioFile
645    *          the file to which the scenario shall be saved
646    */
647   void quickSaveProjection(final String scenarioFile) {
648     (new SwingWorker<Void, Void>() {
649       @Override
650       protected Void doInBackground() throws Exception {
651         try {
652           serializer.save(getCurrentProjection(), scenarioFile);
653           currentProjectionFile = scenarioFile;
654         } catch (Exception ex) {
655           SimSystem.report(Level.SEVERE, "Error while saving scenario file.",
656               ex);
657           GUI.printErrorMessage(P3J.getInstance(),
658               "Error while saving scenario file.",
659               "An error occurred while attempting to save file to '"
660                   + scenarioFile + "': " + ex);
661         }
662         return null;
663       }
664     }).execute();
665 
666   }
667 
668   /**
669    * Load a scenario.
670    */
671   void loadProjection() {
672 
673     int userReaction = this.scenarioFileChooser.showDialog(this, "Open");
674 
675     if (userReaction != JFileChooser.ERROR_OPTION
676         && userReaction != JFileChooser.CANCEL_OPTION) {
677       final File scenarioFile = this.scenarioFileChooser.getSelectedFile();
678       final P3J owner = this;
679       if (scenarioFile != null && scenarioFile.exists()) {
680         (new SwingWorker<Void, Void>() {
681           @Override
682           protected Void doInBackground() throws Exception {
683             try {
684               ProjectionModel loadedModel = serializer.loadProjection(
685                   scenarioFile.getAbsolutePath(),
686                   DatabaseFactory.getDatabaseSingleton());
687               currentProjectionFile = scenarioFile.getAbsolutePath();
688               setCurrentProjection(loadedModel);
689             } catch (IOException | ClassNotFoundException ex) {
690               GUI.printErrorMessage(
691                   owner,
692                   "Error while opening scenario file.",
693                   "An error occurred while attempting to load file from '"
694                       + scenarioFile.getAbsolutePath() + "': "
695                       + ex.getMessage(), ex);
696             } catch (LoadedProjectionFormatException ex) {
697               GUI.printErrorMessage(owner,
698                   "Error while loading projection into database.",
699                   "An error occurred while attempting to load the projection:"
700                       + ex.getMessage(), ex);
701             }
702             return null;
703           }
704         }).execute();
705       }
706     }
707   }
708 
709   // Event Handler
710 
711   /**
712    * Quit application.
713    */
714   public void quitApplication() {
715     if (GUI.printQuestion(this, "Quit?", "Do you really want to quit?")) {
716       System.exit(0);
717     }
718   }
719 
720   /**
721    * Switches to a new projection model for editing.
722    * 
723    * @param newProjModel
724    *          the new projection model to be edited
725    */
726   public void setCurrentProjection(ProjectionModel newProjModel) {
727 
728     if (currentProjection != null) {
729       DatabaseFactory.getDatabaseSingleton().saveProjection(currentProjection);
730     }
731 
732     currentProjection = newProjModel;
733     dbOverviewPanel.totalRefresh();
734 
735     if (currentProjection != null) {
736       projTreePanel.setProjection(currentProjection);
737       resultsPanel.setProjection(currentProjection);
738       switchNavigationTreeTab(NavigationTreeTab.PROJECTION_OVERVIEW);
739     }
740   }
741 
742   /**
743    * Input a matrix quickly.
744    */
745   protected void inputMatrixQuickly() {
746     // (new QuickInputDialog(this,
747     // getCurrentProjection())).setVisible(true);
748   }
749 
750   /**
751    * Executed to run a calculation.
752    */
753   protected void startExperiment() {
754     BaseExperiment baseExperiment = new BaseExperiment();
755     configureModelLocation(baseExperiment);
756     configureSimulator(baseExperiment);
757     configureMultiThreading(baseExperiment);
758     ExperimentExecutorThreadPool.getInstance().getExecutor()
759         .execute(new ExperimentThread(baseExperiment) {
760           @Override
761           protected List<List<RunInformation>> doInBackground() {
762             List<List<RunInformation>> results = null;
763             try {
764               results = super.doInBackground();
765             } catch (Throwable t) {
766               GUI.printErrorMessage("Error executing model", t);
767             }
768             return results;
769           }
770         });
771   }
772 
773   /**
774    * Configures the given experiment for multi-threading.
775    * 
776    * @param baseExperiment
777    *          the experiment to be configured
778    */
779   private void configureMultiThreading(BaseExperiment baseExperiment) {
780     int numOfTrials = (Integer) getConfigFile().get(Misc.PREF_NUM_TRIALS);
781     int numOfThreads = (Integer) getConfigFile().get(
782         Misc.PREF_NUM_PARALLEL_THREADS);
783     double stopTime = Math.ceil((double) numOfTrials / numOfThreads);
784 
785     baseExperiment.setDefaultSimStopTime(stopTime);
786     baseExperiment.setRepeatRuns(numOfThreads);
787     baseExperiment
788         .setComputationInstrumenterFactory(new ExecProgressInstrFactory());
789     baseExperiment.setComputationInstrumenterParameters(new ParameterBlock(
790         numOfTrials, 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.7", "", 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 }