diff --git a/Timeline/src/org/sleuthkit/autopsy/timeline/Bundle.properties b/Timeline/src/org/sleuthkit/autopsy/timeline/Bundle.properties index 8695a80f7c..65071f9662 100644 --- a/Timeline/src/org/sleuthkit/autopsy/timeline/Bundle.properties +++ b/Timeline/src/org/sleuthkit/autopsy/timeline/Bundle.properties @@ -1,2 +1,3 @@ OpenIDE-Module-Name=Timeline CTL_MakeTimeline="Make Timeline (Beta)" +TimelineProgressDialog.jLabel1.text=Computing timeline . . . diff --git a/Timeline/src/org/sleuthkit/autopsy/timeline/Simile2.java b/Timeline/src/org/sleuthkit/autopsy/timeline/Simile2.java index d479dde84b..48332bda45 100644 --- a/Timeline/src/org/sleuthkit/autopsy/timeline/Simile2.java +++ b/Timeline/src/org/sleuthkit/autopsy/timeline/Simile2.java @@ -68,6 +68,7 @@ import javax.swing.BoxLayout; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.JSplitPane; import javax.swing.SwingUtilities; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; @@ -137,6 +138,7 @@ public class Simile2 extends CallableSystemAction implements Presenter.Toolbar, private List data; private boolean listeningToAddImage = false; private long lastObjectId = -1; + private TimelineProgressDialog dialog; //Swing components and JavafX components don't play super well together //Swing components need to be initialized first, in the swing specific thread @@ -174,8 +176,10 @@ public class Simile2 extends CallableSystemAction implements Presenter.Toolbar, //ComboJPanel holds both of the above JPanels together, //aligned vertically (Y_AXIS) - final JPanel comboJPanel = new JPanel(); - comboJPanel.setLayout(new BoxLayout(comboJPanel, BoxLayout.Y_AXIS)); + + // create a horizontal split pane + final JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, chartJPanel, viewerJPanel); + splitPane.setDividerLocation(450); //JavaFX thread //JavaFX components MUST be run in the JavaFX thread, otherwise massive amounts of exceptions will be thrown and caught. Liable to freeze up and crash. @@ -288,17 +292,19 @@ public class Simile2 extends CallableSystemAction implements Presenter.Toolbar, viewerJPanel.add(dataContentPanel); chartJPanel.setAlignmentX(Component.LEFT_ALIGNMENT); viewerJPanel.setAlignmentX(Component.LEFT_ALIGNMENT); - comboJPanel.add(chartJPanel); - comboJPanel.add(viewerJPanel); chart_TopLevel = createYearChartWithDrill(data); chart_Events = chart_TopLevel; scroll_Events.setContent(chart_Events); - jf.add(comboJPanel); + + jf.add(splitPane); jf.setVisible(true); } finally { // stop the progress bar progress.finish(); + + // close the dialog + dialog.doClose(0); } } }); @@ -966,6 +972,11 @@ public class Simile2 extends CallableSystemAction implements Presenter.Toolbar, } else { logger.log(Level.INFO, "Beginning generation of timeline"); + // if the timeline window is already open, do nothing + if (jf != null && jf.isVisible()) { + return; + } + Platform.setImplicitExit(false); // listen for case changes (specifically images being added). @@ -975,6 +986,15 @@ public class Simile2 extends CallableSystemAction implements Presenter.Toolbar, listeningToAddImage = true; } + // create the modal dialog + SwingUtilities.invokeLater(new Runnable () { + @Override + public void run() { + dialog = new TimelineProgressDialog(jf, true); + dialog.setVisible(true); + } + }); + // initialize mactimeFileName mactimeFileName = Case.getCurrentCase().getName() + "-MACTIME.txt"; @@ -992,8 +1012,6 @@ public class Simile2 extends CallableSystemAction implements Presenter.Toolbar, } catch (TskCoreException ex) { Exceptions.printStackTrace(ex); } - - } @Override diff --git a/Timeline/src/org/sleuthkit/autopsy/timeline/TimelineProgressDialog.form b/Timeline/src/org/sleuthkit/autopsy/timeline/TimelineProgressDialog.form new file mode 100644 index 0000000000..0d37383f5a --- /dev/null +++ b/Timeline/src/org/sleuthkit/autopsy/timeline/TimelineProgressDialog.form @@ -0,0 +1,52 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Timeline/src/org/sleuthkit/autopsy/timeline/TimelineProgressDialog.java b/Timeline/src/org/sleuthkit/autopsy/timeline/TimelineProgressDialog.java new file mode 100644 index 0000000000..71983d603d --- /dev/null +++ b/Timeline/src/org/sleuthkit/autopsy/timeline/TimelineProgressDialog.java @@ -0,0 +1,114 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.timeline; + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import javax.swing.AbstractAction; +import javax.swing.ActionMap; +import javax.swing.InputMap; +import javax.swing.JComponent; +import javax.swing.KeyStroke; + +/** + * + * @author mciver + */ +public class TimelineProgressDialog extends javax.swing.JDialog { + + /** + * A return status code - returned if Cancel button has been pressed + */ + public static final int RET_CANCEL = 0; + /** + * A return status code - returned if OK button has been pressed + */ + public static final int RET_OK = 1; + + /** + * Creates new form TimelineProgressDialog + */ + public TimelineProgressDialog(java.awt.Frame parent, boolean modal) { + super(parent, modal); + initComponents(); + + setLocationRelativeTo(null); + + // Close the dialog when Esc is pressed + String cancelName = "cancel"; + InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName); + ActionMap actionMap = getRootPane().getActionMap(); + actionMap.put(cancelName, new AbstractAction() { + public void actionPerformed(ActionEvent e) { + doClose(RET_CANCEL); + } + }); + } + + /** + * @return the return status of this dialog - one of RET_OK or RET_CANCEL + */ + public int getReturnStatus() { + return returnStatus; + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jLabel1 = new javax.swing.JLabel(); + + addWindowListener(new java.awt.event.WindowAdapter() { + public void windowClosing(java.awt.event.WindowEvent evt) { + closeDialog(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(TimelineProgressDialog.class, "TimelineProgressDialog.jLabel1.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(51, 51, 51) + .addComponent(jLabel1) + .addContainerGap(121, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(37, 37, 37) + .addComponent(jLabel1) + .addContainerGap(64, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + + /** + * Closes the dialog + */ + private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog + doClose(RET_CANCEL); + }//GEN-LAST:event_closeDialog + + public void doClose(int retStatus) { + returnStatus = retStatus; + setVisible(false); + dispose(); + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel jLabel1; + // End of variables declaration//GEN-END:variables + private int returnStatus = RET_CANCEL; +}