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