mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-13 16:36:15 +00:00
don't block while rebuilding repo, use JFX dialogs WIP
This commit is contained in:
parent
11213a2da2
commit
1b48afa811
@ -31,6 +31,7 @@ import org.openide.windows.WindowManager;
|
|||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.core.Installer;
|
import org.sleuthkit.autopsy.core.Installer;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||||
|
|
||||||
@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.timeline.Timeline")
|
@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.timeline.Timeline")
|
||||||
@ActionRegistration(displayName = "#CTL_MakeTimeline", lazy = false)
|
@ActionRegistration(displayName = "#CTL_MakeTimeline", lazy = false)
|
||||||
@ -58,8 +59,8 @@ public class OpenTimelineAction extends CallableSystemAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||||
public void performAction() {
|
public void performAction() {
|
||||||
|
|
||||||
//check case
|
//check case
|
||||||
if (!Case.isCaseOpen()) {
|
if (!Case.isCaseOpen()) {
|
||||||
return;
|
return;
|
||||||
@ -72,14 +73,12 @@ public class OpenTimelineAction extends CallableSystemAction {
|
|||||||
LOGGER.log(Level.INFO, "Could not create timeline, there are no data sources.");// NON-NLS
|
LOGGER.log(Level.INFO, "Could not create timeline, there are no data sources.");// NON-NLS
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
synchronized (OpenTimelineAction.class) {
|
|
||||||
if (timeLineController == null) {
|
if (timeLineController == null) {
|
||||||
timeLineController = new TimeLineController(currentCase);
|
timeLineController = new TimeLineController(currentCase);
|
||||||
} else if (timeLineController.getAutopsyCase() != currentCase) {
|
} else if (timeLineController.getAutopsyCase() != currentCase) {
|
||||||
timeLineController.closeTimeLine();
|
timeLineController.closeTimeLine();
|
||||||
timeLineController = new TimeLineController(currentCase);
|
timeLineController = new TimeLineController(currentCase);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
timeLineController.openTimeLine();
|
timeLineController.openTimeLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
48
Core/src/org/sleuthkit/autopsy/timeline/ProgressUpdate.java
Normal file
48
Core/src/org/sleuthkit/autopsy/timeline/ProgressUpdate.java
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sleuthkit.autopsy.timeline;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bundles up progress information to be shown in the progress dialog
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
public class ProgressUpdate {
|
||||||
|
private final int progress;
|
||||||
|
private final int total;
|
||||||
|
private final String headerMessage;
|
||||||
|
private final String detailMessage;
|
||||||
|
|
||||||
|
public int getProgress() {
|
||||||
|
return progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTotal() {
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHeaderMessage() {
|
||||||
|
return headerMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDetailMessage() {
|
||||||
|
return detailMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProgressUpdate(int progress, int total, String headerMessage, String detailMessage) {
|
||||||
|
this.progress = progress;
|
||||||
|
this.total = total;
|
||||||
|
this.headerMessage = headerMessage;
|
||||||
|
this.detailMessage = detailMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProgressUpdate(int progress, int total, String headerMessage) {
|
||||||
|
this(progress, total, headerMessage, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,65 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
|
|
||||||
<Form version="1.5" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
|
|
||||||
<SyntheticProperties>
|
|
||||||
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
|
|
||||||
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
|
|
||||||
</SyntheticProperties>
|
|
||||||
<Events>
|
|
||||||
<EventHandler event="windowClosing" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="closeDialog"/>
|
|
||||||
</Events>
|
|
||||||
<AuxValues>
|
|
||||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
|
||||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
|
||||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
|
||||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
|
|
||||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
|
|
||||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
|
||||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
|
||||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
|
||||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
|
||||||
</AuxValues>
|
|
||||||
|
|
||||||
<Layout>
|
|
||||||
<DimensionLayout dim="0">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" attributes="0">
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Component id="progressBar" pref="504" max="32767" attributes="0"/>
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<Component id="progressHeader" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
<DimensionLayout dim="1">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="progressHeader" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="progressBar" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
</Layout>
|
|
||||||
<SubComponents>
|
|
||||||
<Component class="javax.swing.JProgressBar" name="progressBar">
|
|
||||||
</Component>
|
|
||||||
<Component class="javax.swing.JLabel" name="progressHeader">
|
|
||||||
<Properties>
|
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/timeline/Bundle.properties" key="ProgressWindow.progressHeader.text" replaceFormat="NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
|
||||||
<Dimension value="[10, 14]"/>
|
|
||||||
</Property>
|
|
||||||
</Properties>
|
|
||||||
</Component>
|
|
||||||
</SubComponents>
|
|
||||||
</Form>
|
|
@ -1,217 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2013 Basis Technology Corp.
|
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.sleuthkit.autopsy.timeline;
|
|
||||||
|
|
||||||
import java.awt.Component;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.KeyEvent;
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
|
||||||
import javax.swing.AbstractAction;
|
|
||||||
import javax.swing.ActionMap;
|
|
||||||
import javax.swing.InputMap;
|
|
||||||
import javax.swing.JComponent;
|
|
||||||
import javax.swing.JFrame;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.KeyStroke;
|
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
import javax.swing.SwingWorker;
|
|
||||||
import org.openide.util.NbBundle;
|
|
||||||
import org.openide.windows.WindowManager;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dialog with progress bar that pops up when timeline is being generated
|
|
||||||
*/
|
|
||||||
public class ProgressWindow extends JFrame {
|
|
||||||
|
|
||||||
private final SwingWorker<?, ?> worker;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates new form TimelineProgressDialog
|
|
||||||
*/
|
|
||||||
@NbBundle.Messages({"Timeline.progressWindow.name=Timeline",
|
|
||||||
"Timeline.progressWindow.title=Generating Timeline data"})
|
|
||||||
public ProgressWindow(Component parent, boolean modal, SwingWorker<?, ?> worker) {
|
|
||||||
super();
|
|
||||||
initComponents();
|
|
||||||
|
|
||||||
setLocationRelativeTo(parent);
|
|
||||||
|
|
||||||
setAlwaysOnTop(modal);
|
|
||||||
|
|
||||||
//set icon the same as main app
|
|
||||||
SwingUtilities.invokeLater(() -> {
|
|
||||||
setIconImage(WindowManager.getDefault().getMainWindow().getIconImage());
|
|
||||||
});
|
|
||||||
|
|
||||||
setName(Bundle.Timeline_progressWindow_name());
|
|
||||||
setTitle(Bundle.Timeline_progressWindow_title());
|
|
||||||
// Close the dialog when Esc is pressed
|
|
||||||
String cancelName = "cancel"; // NON-NLS
|
|
||||||
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() {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
cancel();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.worker = worker;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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")
|
|
||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
|
||||||
private void initComponents() {
|
|
||||||
|
|
||||||
progressBar = new javax.swing.JProgressBar();
|
|
||||||
progressHeader = 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(progressHeader, NbBundle.getMessage(ProgressWindow.class, "ProgressWindow.progressHeader.text")); // NOI18N
|
|
||||||
progressHeader.setMinimumSize(new java.awt.Dimension(10, 14));
|
|
||||||
|
|
||||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
|
||||||
getContentPane().setLayout(layout);
|
|
||||||
layout.setHorizontalGroup(
|
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addContainerGap()
|
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addComponent(progressBar, javax.swing.GroupLayout.DEFAULT_SIZE, 504, Short.MAX_VALUE)
|
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addComponent(progressHeader, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addGap(0, 0, Short.MAX_VALUE)))
|
|
||||||
.addContainerGap())
|
|
||||||
);
|
|
||||||
layout.setVerticalGroup(
|
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addContainerGap()
|
|
||||||
.addComponent(progressHeader, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
|
||||||
);
|
|
||||||
|
|
||||||
pack();
|
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes the dialog
|
|
||||||
*/
|
|
||||||
private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog
|
|
||||||
cancel();
|
|
||||||
}//GEN-LAST:event_closeDialog
|
|
||||||
|
|
||||||
@NbBundle.Messages({"Timeline.ProgressWindow.cancel.confdlg.msg=Do you want to cancel timeline creation?",
|
|
||||||
"Timeline.ProgressWindow.cancel.confdlg.detail=Cancel timeline creation?"})
|
|
||||||
public void cancel() {
|
|
||||||
SwingUtilities.invokeLater(() -> {
|
|
||||||
if (isVisible()) {
|
|
||||||
int showConfirmDialog = JOptionPane.showConfirmDialog(ProgressWindow.this,
|
|
||||||
Bundle.Timeline_ProgressWindow_cancel_confdlg_msg(),
|
|
||||||
Bundle.Timeline_ProgressWindow_cancel_confdlg_detail(),
|
|
||||||
JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
|
|
||||||
if (showConfirmDialog == JOptionPane.YES_OPTION) {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
worker.cancel(false);
|
|
||||||
setVisible(false);
|
|
||||||
dispose();
|
|
||||||
}
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
|
||||||
private javax.swing.JProgressBar progressBar;
|
|
||||||
private javax.swing.JLabel progressHeader;
|
|
||||||
// End of variables declaration//GEN-END:variables
|
|
||||||
|
|
||||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
|
||||||
public void update(ProgressUpdate chunk) {
|
|
||||||
progressHeader.setText(chunk.getHeaderMessage());
|
|
||||||
if (chunk.getTotal() >= 0) {
|
|
||||||
progressBar.setIndeterminate(false);
|
|
||||||
progressBar.setMaximum(chunk.getTotal());
|
|
||||||
progressBar.setStringPainted(true);
|
|
||||||
progressBar.setValue(chunk.getProgress());
|
|
||||||
progressBar.setString(chunk.getDetailMessage());
|
|
||||||
} else {
|
|
||||||
progressBar.setIndeterminate(true);
|
|
||||||
progressBar.setStringPainted(true);
|
|
||||||
progressBar.setString(chunk.getDetailMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bundles up progress information to be shown in the progress dialog
|
|
||||||
*/
|
|
||||||
@Immutable
|
|
||||||
public static class ProgressUpdate {
|
|
||||||
|
|
||||||
private final int progress;
|
|
||||||
private final int total;
|
|
||||||
private final String headerMessage;
|
|
||||||
private final String detailMessage;
|
|
||||||
|
|
||||||
public int getProgress() {
|
|
||||||
return progress;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getTotal() {
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getHeaderMessage() {
|
|
||||||
return headerMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDetailMessage() {
|
|
||||||
return detailMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProgressUpdate(int progress, int total, String headerMessage, String detailMessage) {
|
|
||||||
this.progress = progress;
|
|
||||||
this.total = total;
|
|
||||||
this.headerMessage = headerMessage;
|
|
||||||
this.detailMessage = detailMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProgressUpdate(int progress, int total, String headerMessage) {
|
|
||||||
this(progress, total, headerMessage, "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.timeline;
|
|||||||
import java.awt.HeadlessException;
|
import java.awt.HeadlessException;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
@ -28,6 +30,7 @@ import java.time.ZoneId;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.MissingResourceException;
|
import java.util.MissingResourceException;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
@ -49,10 +52,18 @@ import javafx.beans.property.ReadOnlyStringWrapper;
|
|||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.concurrent.Task;
|
import javafx.concurrent.Task;
|
||||||
|
import javafx.concurrent.WorkerStateEvent;
|
||||||
|
import javafx.scene.control.Alert;
|
||||||
|
import javafx.scene.control.ButtonType;
|
||||||
|
import javafx.scene.control.DialogEvent;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
|
import javafx.stage.Modality;
|
||||||
|
import javafx.stage.Stage;
|
||||||
import javax.annotation.concurrent.GuardedBy;
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
import org.controlsfx.dialog.ProgressDialog;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.joda.time.DateTimeZone;
|
import org.joda.time.DateTimeZone;
|
||||||
import org.joda.time.Interval;
|
import org.joda.time.Interval;
|
||||||
@ -136,6 +147,9 @@ public class TimeLineController {
|
|||||||
|
|
||||||
private final ReadOnlyStringWrapper status = new ReadOnlyStringWrapper();
|
private final ReadOnlyStringWrapper status = new ReadOnlyStringWrapper();
|
||||||
|
|
||||||
|
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||||
|
private ProgressDialog taskProgressDialog;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* status is a string that will be displayed in the status bar as a kind of
|
* status is a string that will be displayed in the status bar as a kind of
|
||||||
* user hint/information when it is not empty
|
* user hint/information when it is not empty
|
||||||
@ -202,7 +216,6 @@ public class TimeLineController {
|
|||||||
@GuardedBy("filteredEvents")
|
@GuardedBy("filteredEvents")
|
||||||
private final FilteredEventsModel filteredEvents;
|
private final FilteredEventsModel filteredEvents;
|
||||||
|
|
||||||
@GuardedBy("eventsRepository")
|
|
||||||
private final EventsRepository eventsRepository;
|
private final EventsRepository eventsRepository;
|
||||||
|
|
||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
@ -305,6 +318,7 @@ public class TimeLineController {
|
|||||||
* the user aborted after prompt about ingest running. True if the
|
* the user aborted after prompt about ingest running. True if the
|
||||||
* repo was rebuilt.
|
* repo was rebuilt.
|
||||||
*/
|
*/
|
||||||
|
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||||
boolean rebuildRepo() {
|
boolean rebuildRepo() {
|
||||||
if (IngestManager.getInstance().isIngestRunning()) {
|
if (IngestManager.getInstance().isIngestRunning()) {
|
||||||
//confirm timeline during ingest
|
//confirm timeline during ingest
|
||||||
@ -314,40 +328,29 @@ public class TimeLineController {
|
|||||||
}
|
}
|
||||||
LOGGER.log(Level.INFO, "Beginning generation of timeline"); // NON-NLS
|
LOGGER.log(Level.INFO, "Beginning generation of timeline"); // NON-NLS
|
||||||
try {
|
try {
|
||||||
SwingUtilities.invokeLater(() -> {
|
closeTimelineWindow();
|
||||||
synchronized (TimeLineController.this) {
|
|
||||||
if (isWindowOpen()) {
|
|
||||||
mainFrame.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
final SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase();
|
final SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase();
|
||||||
final long lastObjId = sleuthkitCase.getLastObjectId();
|
final long lastObjId = sleuthkitCase.getLastObjectId();
|
||||||
final long lastArtfID = getCaseLastArtifactID(sleuthkitCase);
|
final long lastArtfID = getCaseLastArtifactID(sleuthkitCase);
|
||||||
final Boolean injestRunning = IngestManager.getInstance().isIngestRunning();
|
final Boolean injestRunning = IngestManager.getInstance().isIngestRunning();
|
||||||
//TODO: verify this locking is correct? -jm
|
final Task<Void> rebuildRepository = eventsRepository.rebuildRepository(lastObjId, lastArtfID, injestRunning);
|
||||||
synchronized (eventsRepository) {
|
Platform.runLater(() -> {
|
||||||
eventsRepository.rebuildRepository(() -> {
|
rebuildRepository.setOnSucceeded((WorkerStateEvent event) -> {
|
||||||
synchronized (eventsRepository) {
|
//this is run on jfx thread
|
||||||
eventsRepository.recordLastObjID(lastObjId);
|
|
||||||
eventsRepository.recordLastArtifactID(lastArtfID);
|
|
||||||
eventsRepository.recordWasIngestRunning(injestRunning);
|
|
||||||
}
|
|
||||||
synchronized (TimeLineController.this) {
|
|
||||||
//TODO: this looks hacky. what is going on? should this be an event?
|
//TODO: this looks hacky. what is going on? should this be an event?
|
||||||
needsHistogramRebuild.set(true);
|
needsHistogramRebuild.set(true);
|
||||||
needsHistogramRebuild.set(false);
|
needsHistogramRebuild.set(false);
|
||||||
showWindow();
|
SwingUtilities.invokeLater(TimeLineController.this::showWindow);
|
||||||
}
|
|
||||||
|
|
||||||
Platform.runLater(() -> {
|
|
||||||
//TODO: should this be an event?
|
//TODO: should this be an event?
|
||||||
newEventsFlag.set(false);
|
newEventsFlag.set(false);
|
||||||
historyManager.reset(filteredEvents.zoomParametersProperty().get());
|
historyManager.reset(filteredEvents.zoomParametersProperty().get());
|
||||||
TimeLineController.this.showFullRange();
|
TimeLineController.this.showFullRange();
|
||||||
});
|
});
|
||||||
|
taskProgressDialog = showProgressDialogForTask(rebuildRepository);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
LOGGER.log(Level.SEVERE, "Error when generating timeline, ", ex); // NON-NLS
|
LOGGER.log(Level.SEVERE, "Error when generating timeline, ", ex); // NON-NLS
|
||||||
return false;
|
return false;
|
||||||
@ -360,23 +363,60 @@ public class TimeLineController {
|
|||||||
* tags table and rebuild it by querying for all the tags and inserting them
|
* tags table and rebuild it by querying for all the tags and inserting them
|
||||||
* in to the TimeLine DB.
|
* in to the TimeLine DB.
|
||||||
*/
|
*/
|
||||||
|
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||||
void rebuildTagsTable() {
|
void rebuildTagsTable() {
|
||||||
LOGGER.log(Level.INFO, "starting to rebuild tags table"); // NON-NLS
|
LOGGER.log(Level.INFO, "starting to rebuild tags table"); // NON-NLS
|
||||||
SwingUtilities.invokeLater(() -> {
|
closeTimelineWindow();
|
||||||
synchronized (TimeLineController.this) {
|
Task<Void> rebuildTags = eventsRepository.rebuildTags();
|
||||||
|
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
rebuildTags.setOnSucceeded((WorkerStateEvent event) -> {
|
||||||
|
SwingUtilities.invokeLater(TimeLineController.this::showWindow);
|
||||||
|
showFullRange();;
|
||||||
|
});
|
||||||
|
taskProgressDialog = showProgressDialogForTask(rebuildTags);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeTimelineWindow() {
|
||||||
if (isWindowOpen()) {
|
if (isWindowOpen()) {
|
||||||
mainFrame.close();
|
mainFrame.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
synchronized (eventsRepository) {
|
@NbBundle.Messages({"Timeline.progressWindow.title=Populating Timeline data",
|
||||||
eventsRepository.rebuildTags(() -> {
|
"Timeline.ProgressWindow.cancel.confdlg.msg=Not all events will be present of accurate if you cancel the timeline population. Do you want to cancel?",
|
||||||
showWindow();
|
"Timeline.ProgressWindow.cancel.confdlg.detail=Cancel timeline population?"})
|
||||||
Platform.runLater(() -> {
|
private ProgressDialog showProgressDialogForTask(Task<Void> task) {
|
||||||
showFullRange();
|
ProgressDialog progressDialog = new ProgressDialog(task);
|
||||||
});
|
progressDialog.getDialogPane().getButtonTypes().add(ButtonType.CANCEL);
|
||||||
});
|
|
||||||
|
progressDialog.setTitle(Bundle.Timeline_progressWindow_title());
|
||||||
|
progressDialog.getDialogPane().headerTextProperty().bind(task.titleProperty());
|
||||||
|
try {
|
||||||
|
Image image = new Image(new URL("nbresloc:/org/netbeans/core/startup/frame.gif").openStream());
|
||||||
|
((Stage) progressDialog.getDialogPane().getScene().getWindow()).getIcons().setAll(image);
|
||||||
|
} catch (IOException iOException) {
|
||||||
|
LOGGER.log(Level.WARNING, "Failed to laod branded icon for progress dialog.", iOException);
|
||||||
}
|
}
|
||||||
|
progressDialog.setOnCloseRequest((DialogEvent event) -> {
|
||||||
|
Alert confirmation = new Alert(Alert.AlertType.CONFIRMATION, Bundle.Timeline_ProgressWindow_cancel_confdlg_msg(), ButtonType.YES, ButtonType.NO);
|
||||||
|
confirmation.setHeaderText(null);
|
||||||
|
confirmation.setTitle(Bundle.Timeline_ProgressWindow_cancel_confdlg_detail());
|
||||||
|
confirmation.initOwner(progressDialog.getDialogPane().getScene().getWindow());
|
||||||
|
confirmation.initModality(Modality.WINDOW_MODAL);
|
||||||
|
Optional<ButtonType> showAndWait = confirmation.showAndWait();
|
||||||
|
|
||||||
|
showAndWait.ifPresent(buttonType -> {
|
||||||
|
if (buttonType == ButtonType.YES) {
|
||||||
|
task.cancel(true);
|
||||||
|
} else {
|
||||||
|
event.consume();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return progressDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showFullRange() {
|
public void showFullRange() {
|
||||||
@ -403,6 +443,7 @@ public class TimeLineController {
|
|||||||
/**
|
/**
|
||||||
* show the timeline window and prompt for rebuilding database if necessary.
|
* show the timeline window and prompt for rebuilding database if necessary.
|
||||||
*/
|
*/
|
||||||
|
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||||
void openTimeLine() {
|
void openTimeLine() {
|
||||||
// listen for case changes (specifically images being added, and case changes).
|
// listen for case changes (specifically images being added, and case changes).
|
||||||
if (Case.isCaseOpen() && !listeningToAutopsy) {
|
if (Case.isCaseOpen() && !listeningToAutopsy) {
|
||||||
@ -413,6 +454,16 @@ public class TimeLineController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if (eventsRepository.isRebuilding()) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
if (taskProgressDialog != null) {
|
||||||
|
((Stage) taskProgressDialog.getDialogPane().getScene().getWindow()).toFront();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
boolean repoRebuilt = false; //has the repo been rebuilt
|
boolean repoRebuilt = false; //has the repo been rebuilt
|
||||||
long timeLineLastObjectId = eventsRepository.getLastObjID();
|
long timeLineLastObjectId = eventsRepository.getLastObjID();
|
||||||
|
|
||||||
@ -545,17 +596,14 @@ public class TimeLineController {
|
|||||||
/**
|
/**
|
||||||
* private method to build gui if necessary and make it visible.
|
* private method to build gui if necessary and make it visible.
|
||||||
*/
|
*/
|
||||||
|
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||||
synchronized private void showWindow() {
|
synchronized private void showWindow() {
|
||||||
SwingUtilities.invokeLater(() -> {
|
|
||||||
synchronized (TimeLineController.this) {
|
|
||||||
if (mainFrame == null) {
|
if (mainFrame == null) {
|
||||||
mainFrame = new TimeLineTopComponent(this);
|
mainFrame = new TimeLineTopComponent(this);
|
||||||
}
|
}
|
||||||
mainFrame.open();
|
mainFrame.open();
|
||||||
mainFrame.toFront();
|
mainFrame.toFront();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized public void pushEventTypeZoom(EventTypeZoomLevel typeZoomeLevel) {
|
synchronized public void pushEventTypeZoom(EventTypeZoomLevel typeZoomeLevel) {
|
||||||
ZoomParams currentZoom = filteredEvents.zoomParametersProperty().get();
|
ZoomParams currentZoom = filteredEvents.zoomParametersProperty().get();
|
||||||
@ -575,8 +623,7 @@ public class TimeLineController {
|
|||||||
} else if (currentZoom.hasTimeRange(timeRange) == false) {
|
} else if (currentZoom.hasTimeRange(timeRange) == false) {
|
||||||
advance(currentZoom.withTimeRange(timeRange));
|
advance(currentZoom.withTimeRange(timeRange));
|
||||||
return true;
|
return true;
|
||||||
}
|
} else {
|
||||||
else{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -590,7 +637,7 @@ public class TimeLineController {
|
|||||||
final Long count = eventCounts.values().stream().reduce(0l, Long::sum);
|
final Long count = eventCounts.values().stream().reduce(0l, Long::sum);
|
||||||
|
|
||||||
boolean shouldContinue = true;
|
boolean shouldContinue = true;
|
||||||
if ((newLOD == DescriptionLoD.FULL|| newLOD ==DescriptionLoD.MEDIUM )&& count > 10_000) {
|
if ((newLOD == DescriptionLoD.FULL || newLOD == DescriptionLoD.MEDIUM) && count > 10_000) {
|
||||||
String format = NumberFormat.getInstance().format(count);
|
String format = NumberFormat.getInstance().format(count);
|
||||||
|
|
||||||
int showConfirmDialog = JOptionPane.showConfirmDialog(mainFrame,
|
int showConfirmDialog = JOptionPane.showConfirmDialog(mainFrame,
|
||||||
@ -748,7 +795,8 @@ public class TimeLineController {
|
|||||||
*
|
*
|
||||||
* @return true if the timeline window is open
|
* @return true if the timeline window is open
|
||||||
*/
|
*/
|
||||||
synchronized private boolean isWindowOpen() {
|
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||||
|
private boolean isWindowOpen() {
|
||||||
return mainFrame != null && mainFrame.isOpened() && mainFrame.isVisible();
|
return mainFrame != null && mainFrame.isOpened() && mainFrame.isVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.timeline.db;
|
|||||||
import com.google.common.cache.CacheBuilder;
|
import com.google.common.cache.CacheBuilder;
|
||||||
import com.google.common.cache.CacheLoader;
|
import com.google.common.cache.CacheLoader;
|
||||||
import com.google.common.cache.LoadingCache;
|
import com.google.common.cache.LoadingCache;
|
||||||
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -30,6 +31,8 @@ import java.util.Map;
|
|||||||
import static java.util.Objects.isNull;
|
import static java.util.Objects.isNull;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CancellationException;
|
import java.util.concurrent.CancellationException;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -37,10 +40,8 @@ import javafx.beans.property.ReadOnlyObjectProperty;
|
|||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.collections.ObservableMap;
|
import javafx.collections.ObservableMap;
|
||||||
import javax.annotation.concurrent.GuardedBy;
|
import javafx.concurrent.Task;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
import javax.swing.SwingWorker;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.controlsfx.dialog.ProgressDialog;
|
import org.controlsfx.dialog.ProgressDialog;
|
||||||
import org.joda.time.Interval;
|
import org.joda.time.Interval;
|
||||||
@ -50,7 +51,8 @@ import org.openide.util.NbBundle;
|
|||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.timeline.ProgressWindow;
|
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||||
|
import org.sleuthkit.autopsy.timeline.ProgressUpdate;
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.EventCluster;
|
import org.sleuthkit.autopsy.timeline.datamodel.EventCluster;
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.TimeLineEvent;
|
import org.sleuthkit.autopsy.timeline.datamodel.TimeLineEvent;
|
||||||
@ -93,8 +95,7 @@ public class EventsRepository {
|
|||||||
|
|
||||||
private final EventDB eventDB;
|
private final EventDB eventDB;
|
||||||
|
|
||||||
@GuardedBy("this")
|
private Task<Void> dbPopulationWorker;
|
||||||
private SwingWorker<Void, ProgressWindow.ProgressUpdate> dbPopulationWorker;
|
|
||||||
|
|
||||||
private final LoadingCache<Object, Long> maxCache;
|
private final LoadingCache<Object, Long> maxCache;
|
||||||
|
|
||||||
@ -177,15 +178,15 @@ public class EventsRepository {
|
|||||||
// return eventDB.getMinTime();
|
// return eventDB.getMinTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void recordLastArtifactID(long lastArtfID) {
|
private void recordLastArtifactID(long lastArtfID) {
|
||||||
eventDB.recordLastArtifactID(lastArtfID);
|
eventDB.recordLastArtifactID(lastArtfID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void recordWasIngestRunning(Boolean wasIngestRunning) {
|
private void recordWasIngestRunning(Boolean wasIngestRunning) {
|
||||||
eventDB.recordWasIngestRunning(wasIngestRunning);
|
eventDB.recordWasIngestRunning(wasIngestRunning);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void recordLastObjID(Long lastObjID) {
|
private void recordLastObjID(Long lastObjID) {
|
||||||
eventDB.recordLastObjID(lastObjID);
|
eventDB.recordLastObjID(lastObjID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,22 +325,48 @@ public class EventsRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized public void rebuildRepository(Runnable r) {
|
Executor workerExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("eventrepository-worker-%d").build());
|
||||||
|
|
||||||
|
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||||
|
public Task<Void> rebuildRepository(long lastObjId, long lastArtfID, Boolean injestRunning) {
|
||||||
if (dbPopulationWorker != null) {
|
if (dbPopulationWorker != null) {
|
||||||
dbPopulationWorker.cancel(true);
|
dbPopulationWorker.cancel(true);
|
||||||
|
LOGGER.log(Level.INFO, "cancelling previous db worker");
|
||||||
}
|
}
|
||||||
dbPopulationWorker = new DBPopulationWorker(r);
|
LOGGER.log(Level.INFO, "rebuilding repo");
|
||||||
dbPopulationWorker.execute();
|
dbPopulationWorker = new DBPopulationWorker(lastObjId, lastArtfID, injestRunning);
|
||||||
|
workerExecutor.execute(dbPopulationWorker);
|
||||||
|
return dbPopulationWorker;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized public void rebuildTags(Runnable r) {
|
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||||
|
public Task<Void> rebuildTags() {
|
||||||
if (dbPopulationWorker != null) {
|
if (dbPopulationWorker != null) {
|
||||||
dbPopulationWorker.cancel(true);
|
dbPopulationWorker.cancel(true);
|
||||||
|
LOGGER.log(Level.INFO, "cancelling previous db worker");
|
||||||
}
|
}
|
||||||
dbPopulationWorker = new RebuildTagsWorker(r);
|
LOGGER.log(Level.INFO, "rebuilding tags");
|
||||||
dbPopulationWorker.execute();
|
dbPopulationWorker = new RebuildTagsWorker();
|
||||||
|
workerExecutor.execute(dbPopulationWorker);
|
||||||
|
return dbPopulationWorker;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param lastObjId the value of lastObjId
|
||||||
|
* @param lastArtfID the value of lastArtfID
|
||||||
|
* @param injestRunning the value of injestRunning
|
||||||
|
* @param timeLineController the value of timeLineController
|
||||||
|
*/
|
||||||
|
public void recordDBPopulationState(final long lastObjId, final long lastArtfID, final Boolean injestRunning) {
|
||||||
|
recordLastObjID(lastObjId);
|
||||||
|
recordLastArtifactID(lastArtfID);
|
||||||
|
recordWasIngestRunning(injestRunning);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||||
|
public boolean isRebuilding() {
|
||||||
|
return dbPopulationWorker != null && dbPopulationWorker.isDone() == false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -352,26 +379,19 @@ public class EventsRepository {
|
|||||||
* these to a JavaFX implementation,and replace {@link ProgressWindow} with
|
* these to a JavaFX implementation,and replace {@link ProgressWindow} with
|
||||||
* {@link ProgressDialog}
|
* {@link ProgressDialog}
|
||||||
*/
|
*/
|
||||||
private abstract class DBProgressWorker extends SwingWorker<Void, ProgressWindow.ProgressUpdate> {
|
private abstract class DBProgressWorker extends Task<Void> {
|
||||||
|
|
||||||
//TODO: can we avoid this with a state listener? does it amount to the same thing?
|
|
||||||
//post population operation to execute
|
|
||||||
final Runnable postPopulationOperation;
|
|
||||||
|
|
||||||
final SleuthkitCase skCase;
|
final SleuthkitCase skCase;
|
||||||
final TagsManager tagsManager;
|
final TagsManager tagsManager;
|
||||||
|
|
||||||
final ProgressWindow progressDialog;
|
|
||||||
volatile ProgressHandle progressHandle;
|
volatile ProgressHandle progressHandle;
|
||||||
|
|
||||||
DBProgressWorker(Runnable postPopulationOperation, String initialProgressDisplayName) {
|
DBProgressWorker(String initialProgressDisplayName) {
|
||||||
progressDialog = new ProgressWindow(null, false, this);
|
|
||||||
progressDialog.setVisible(true);
|
|
||||||
progressHandle = ProgressHandleFactory.createHandle(initialProgressDisplayName, () -> cancel(true));
|
progressHandle = ProgressHandleFactory.createHandle(initialProgressDisplayName, () -> cancel(true));
|
||||||
|
|
||||||
skCase = autoCase.getSleuthkitCase();
|
skCase = autoCase.getSleuthkitCase();
|
||||||
tagsManager = autoCase.getServices().getTagsManager();
|
tagsManager = autoCase.getServices().getTagsManager();
|
||||||
this.postPopulationOperation = postPopulationOperation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -379,10 +399,11 @@ public class EventsRepository {
|
|||||||
*
|
*
|
||||||
* @param chunk
|
* @param chunk
|
||||||
*/
|
*/
|
||||||
final protected void update(ProgressWindow.ProgressUpdate chunk) {
|
final protected void update(ProgressUpdate chunk) {
|
||||||
SwingUtilities.invokeLater(() -> {
|
updateProgress(chunk.getProgress(), chunk.getTotal());
|
||||||
progressDialog.update(chunk);
|
updateMessage(chunk.getDetailMessage());
|
||||||
});
|
updateTitle(chunk.getHeaderMessage());
|
||||||
|
|
||||||
if (chunk.getTotal() >= 0) {
|
if (chunk.getTotal() >= 0) {
|
||||||
progressHandle.progress(chunk.getProgress());
|
progressHandle.progress(chunk.getProgress());
|
||||||
}
|
}
|
||||||
@ -390,12 +411,6 @@ public class EventsRepository {
|
|||||||
progressHandle.progress(chunk.getDetailMessage());
|
progressHandle.progress(chunk.getDetailMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void done() {
|
|
||||||
super.done();
|
|
||||||
progressDialog.close();
|
|
||||||
postPopulationOperation.run(); //execute post db population operation
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean areFiltersEquivalent(RootFilter f1, RootFilter f2) {
|
public boolean areFiltersEquivalent(RootFilter f1, RootFilter f2) {
|
||||||
@ -405,15 +420,15 @@ public class EventsRepository {
|
|||||||
private class RebuildTagsWorker extends DBProgressWorker {
|
private class RebuildTagsWorker extends DBProgressWorker {
|
||||||
|
|
||||||
@NbBundle.Messages("RebuildTagsWorker.task.displayName=refreshing tags")
|
@NbBundle.Messages("RebuildTagsWorker.task.displayName=refreshing tags")
|
||||||
RebuildTagsWorker(Runnable postPopulationOperation) {
|
RebuildTagsWorker() {
|
||||||
super(postPopulationOperation, Bundle.RebuildTagsWorker_task_displayName());
|
super(Bundle.RebuildTagsWorker_task_displayName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NbBundle.Messages({"progressWindow.msg.refreshingFileTags=refreshing file tags",
|
@NbBundle.Messages({"progressWindow.msg.refreshingFileTags=refreshing file tags",
|
||||||
"progressWindow.msg.refreshingResultTags=refreshing result tags",
|
"progressWindow.msg.refreshingResultTags=refreshing result tags",
|
||||||
"progressWindow.msg.commitingTags=committing tag changes"})
|
"progressWindow.msg.commitingTags=committing tag changes"})
|
||||||
protected Void doInBackground() throws Exception {
|
protected Void call() throws Exception {
|
||||||
int currentWorkTotal;
|
int currentWorkTotal;
|
||||||
|
|
||||||
progressHandle.start();
|
progressHandle.start();
|
||||||
@ -432,7 +447,7 @@ public class EventsRepository {
|
|||||||
if (isCancelled()) {
|
if (isCancelled()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
update(new ProgressWindow.ProgressUpdate(i, currentWorkTotal, Bundle.progressWindow_msg_refreshingFileTags()));
|
update(new ProgressUpdate(i, currentWorkTotal, Bundle.progressWindow_msg_refreshingFileTags()));
|
||||||
ContentTag contentTag = contentTags.get(i);
|
ContentTag contentTag = contentTags.get(i);
|
||||||
eventDB.addTag(contentTag.getContent().getId(), null, contentTag);
|
eventDB.addTag(contentTag.getContent().getId(), null, contentTag);
|
||||||
}
|
}
|
||||||
@ -448,7 +463,7 @@ public class EventsRepository {
|
|||||||
if (isCancelled()) {
|
if (isCancelled()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
update(new ProgressWindow.ProgressUpdate(i, currentWorkTotal, Bundle.progressWindow_msg_refreshingResultTags()));
|
update(new ProgressUpdate(i, currentWorkTotal, Bundle.progressWindow_msg_refreshingResultTags()));
|
||||||
BlackboardArtifactTag artifactTag = artifactTags.get(i);
|
BlackboardArtifactTag artifactTag = artifactTags.get(i);
|
||||||
eventDB.addTag(artifactTag.getContent().getId(), artifactTag.getArtifact().getArtifactID(), artifactTag);
|
eventDB.addTag(artifactTag.getContent().getId(), artifactTag.getArtifact().getArtifactID(), artifactTag);
|
||||||
}
|
}
|
||||||
@ -457,7 +472,7 @@ public class EventsRepository {
|
|||||||
progressHandle.finish();
|
progressHandle.finish();
|
||||||
progressHandle = ProgressHandleFactory.createHandle(Bundle.progressWindow_msg_commitingTags());
|
progressHandle = ProgressHandleFactory.createHandle(Bundle.progressWindow_msg_commitingTags());
|
||||||
progressHandle.start();
|
progressHandle.start();
|
||||||
update(new ProgressWindow.ProgressUpdate(0, -1, Bundle.progressWindow_msg_commitingTags()));
|
update(new ProgressUpdate(0, -1, Bundle.progressWindow_msg_commitingTags()));
|
||||||
|
|
||||||
if (isCancelled()) {
|
if (isCancelled()) {
|
||||||
eventDB.rollBackTransaction(trans);
|
eventDB.rollBackTransaction(trans);
|
||||||
@ -491,18 +506,25 @@ public class EventsRepository {
|
|||||||
|
|
||||||
private class DBPopulationWorker extends DBProgressWorker {
|
private class DBPopulationWorker extends DBProgressWorker {
|
||||||
|
|
||||||
|
private final long lastObjId;
|
||||||
|
private final long lastArtfID;
|
||||||
|
private final boolean injestRunning;
|
||||||
|
|
||||||
@NbBundle.Messages("DBPopulationWorker.task.displayName=(re)initializing events database")
|
@NbBundle.Messages("DBPopulationWorker.task.displayName=(re)initializing events database")
|
||||||
public DBPopulationWorker(Runnable postPopulationOperation) {
|
DBPopulationWorker(long lastObjId, long lastArtfID, Boolean injestRunning) {
|
||||||
super(postPopulationOperation, Bundle.DBPopulationWorker_task_displayName());
|
super(Bundle.DBPopulationWorker_task_displayName());
|
||||||
|
this.lastObjId = lastObjId;
|
||||||
|
this.lastArtfID = lastArtfID;
|
||||||
|
this.injestRunning = injestRunning;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NbBundle.Messages({"progressWindow.msg.populateMacEventsFiles=Populating MAC time events for files:",
|
@NbBundle.Messages({"progressWindow.msg.populateMacEventsFiles=Populating MAC time events for files:",
|
||||||
"progressWindow.msg.reinit_db=(re)initializing events database",
|
"progressWindow.msg.reinit_db=(re)initializing events database",
|
||||||
"progressWindow.msg.commitingDb=committing events db"})
|
"progressWindow.msg.commitingDb=committing events db"})
|
||||||
protected Void doInBackground() throws Exception {
|
protected Void call() throws Exception {
|
||||||
progressHandle.start();
|
progressHandle.start();
|
||||||
update(new ProgressWindow.ProgressUpdate(0, -1, Bundle.progressWindow_msg_reinit_db()));
|
update(new ProgressUpdate(0, -1, Bundle.progressWindow_msg_reinit_db()));
|
||||||
//reset database //TODO: can we do more incremental updates? -jm
|
//reset database //TODO: can we do more incremental updates? -jm
|
||||||
eventDB.reInitializeDB();
|
eventDB.reInitializeDB();
|
||||||
|
|
||||||
@ -510,7 +532,7 @@ public class EventsRepository {
|
|||||||
List<Long> fileIDs = skCase.findAllFileIdsWhere("name != '.' AND name != '..'");
|
List<Long> fileIDs = skCase.findAllFileIdsWhere("name != '.' AND name != '..'");
|
||||||
final int numFiles = fileIDs.size();
|
final int numFiles = fileIDs.size();
|
||||||
progressHandle.switchToDeterminate(numFiles);
|
progressHandle.switchToDeterminate(numFiles);
|
||||||
update(new ProgressWindow.ProgressUpdate(0, numFiles, Bundle.progressWindow_msg_populateMacEventsFiles()));
|
update(new ProgressUpdate(0, numFiles, Bundle.progressWindow_msg_populateMacEventsFiles()));
|
||||||
|
|
||||||
//insert file events into db
|
//insert file events into db
|
||||||
EventDB.EventTransaction trans = eventDB.beginTransaction();
|
EventDB.EventTransaction trans = eventDB.beginTransaction();
|
||||||
@ -526,7 +548,7 @@ public class EventsRepository {
|
|||||||
LOGGER.log(Level.WARNING, "Failed to get data for file : {0}", fID); // NON-NLS
|
LOGGER.log(Level.WARNING, "Failed to get data for file : {0}", fID); // NON-NLS
|
||||||
} else {
|
} else {
|
||||||
insertEventsForFile(f, trans);
|
insertEventsForFile(f, trans);
|
||||||
update(new ProgressWindow.ProgressUpdate(i, numFiles,
|
update(new ProgressUpdate(i, numFiles,
|
||||||
Bundle.progressWindow_msg_populateMacEventsFiles(), f.getName()));
|
Bundle.progressWindow_msg_populateMacEventsFiles(), f.getName()));
|
||||||
}
|
}
|
||||||
} catch (TskCoreException tskCoreException) {
|
} catch (TskCoreException tskCoreException) {
|
||||||
@ -550,7 +572,7 @@ public class EventsRepository {
|
|||||||
progressHandle.finish();
|
progressHandle.finish();
|
||||||
progressHandle = ProgressHandleFactory.createHandle(Bundle.progressWindow_msg_commitingDb());
|
progressHandle = ProgressHandleFactory.createHandle(Bundle.progressWindow_msg_commitingDb());
|
||||||
progressHandle.start();
|
progressHandle.start();
|
||||||
update(new ProgressWindow.ProgressUpdate(0, -1, Bundle.progressWindow_msg_commitingDb()));
|
update(new ProgressUpdate(0, -1, Bundle.progressWindow_msg_commitingDb()));
|
||||||
|
|
||||||
if (isCancelled()) {
|
if (isCancelled()) {
|
||||||
eventDB.rollBackTransaction(trans);
|
eventDB.rollBackTransaction(trans);
|
||||||
@ -561,6 +583,7 @@ public class EventsRepository {
|
|||||||
populateFilterData(skCase);
|
populateFilterData(skCase);
|
||||||
invalidateCaches();
|
invalidateCaches();
|
||||||
|
|
||||||
|
recordDBPopulationState(lastObjId, lastArtfID, injestRunning);
|
||||||
progressHandle.finish();
|
progressHandle.finish();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -573,10 +596,12 @@ public class EventsRepository {
|
|||||||
timeMap.put(FileSystemTypes.FILE_CHANGED, f.getCtime());
|
timeMap.put(FileSystemTypes.FILE_CHANGED, f.getCtime());
|
||||||
timeMap.put(FileSystemTypes.FILE_MODIFIED, f.getMtime());
|
timeMap.put(FileSystemTypes.FILE_MODIFIED, f.getMtime());
|
||||||
|
|
||||||
/* if there are no legitimate ( greater tan zero ) time stamps ( eg,
|
/*
|
||||||
|
* if there are no legitimate ( greater tan zero ) time stamps ( eg,
|
||||||
* logical/local files) skip the rest of the event generation: this
|
* logical/local files) skip the rest of the event generation: this
|
||||||
* should result in droping logical files, since they do not have
|
* should result in droping logical files, since they do not have
|
||||||
* legitimate time stamps. */
|
* legitimate time stamps.
|
||||||
|
*/
|
||||||
if (Collections.max(timeMap.values()) > 0) {
|
if (Collections.max(timeMap.values()) > 0) {
|
||||||
final String uniquePath = f.getUniquePath();
|
final String uniquePath = f.getUniquePath();
|
||||||
final String parentPath = f.getParentPath();
|
final String parentPath = f.getParentPath();
|
||||||
@ -593,8 +618,10 @@ public class EventsRepository {
|
|||||||
List<ContentTag> tags = tagsManager.getContentTagsByContent(f);
|
List<ContentTag> tags = tagsManager.getContentTagsByContent(f);
|
||||||
|
|
||||||
for (Map.Entry<FileSystemTypes, Long> timeEntry : timeMap.entrySet()) {
|
for (Map.Entry<FileSystemTypes, Long> timeEntry : timeMap.entrySet()) {
|
||||||
/* if the time is legitimate ( greater than zero ) insert it
|
/*
|
||||||
* into the db */
|
* if the time is legitimate ( greater than zero ) insert it
|
||||||
|
* into the db
|
||||||
|
*/
|
||||||
if (timeEntry.getValue() > 0) {
|
if (timeEntry.getValue() > 0) {
|
||||||
eventDB.insertEvent(timeEntry.getValue(), timeEntry.getKey(),
|
eventDB.insertEvent(timeEntry.getValue(), timeEntry.getKey(),
|
||||||
datasourceID, f.getId(), null, uniquePath, medDesc,
|
datasourceID, f.getId(), null, uniquePath, medDesc,
|
||||||
@ -640,7 +667,7 @@ public class EventsRepository {
|
|||||||
try {
|
try {
|
||||||
//for each artifact, extract the relevant information for the descriptions
|
//for each artifact, extract the relevant information for the descriptions
|
||||||
insertEventForArtifact(type, blackboardArtifacts.get(i), trans);
|
insertEventForArtifact(type, blackboardArtifacts.get(i), trans);
|
||||||
update(new ProgressWindow.ProgressUpdate(i, numArtifacts,
|
update(new ProgressUpdate(i, numArtifacts,
|
||||||
Bundle.progressWindow_populatingXevents(type.getDisplayName())));
|
Bundle.progressWindow_populatingXevents(type.getDisplayName())));
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
LOGGER.log(Level.SEVERE, "There was a problem inserting event for artifact: " + blackboardArtifacts.get(i).getArtifactID(), ex); // NON-NLS
|
LOGGER.log(Level.SEVERE, "There was a problem inserting event for artifact: " + blackboardArtifacts.get(i).getArtifactID(), ex); // NON-NLS
|
||||||
@ -653,8 +680,10 @@ public class EventsRepository {
|
|||||||
|
|
||||||
private void insertEventForArtifact(final ArtifactEventType type, BlackboardArtifact bbart, EventDB.EventTransaction trans) throws TskCoreException {
|
private void insertEventForArtifact(final ArtifactEventType type, BlackboardArtifact bbart, EventDB.EventTransaction trans) throws TskCoreException {
|
||||||
ArtifactEventType.AttributeEventDescription eventDescription = ArtifactEventType.buildEventDescription(type, bbart);
|
ArtifactEventType.AttributeEventDescription eventDescription = ArtifactEventType.buildEventDescription(type, bbart);
|
||||||
/* if the time is legitimate ( greater than zero ) insert it into
|
/*
|
||||||
* the db */
|
* if the time is legitimate ( greater than zero ) insert it into
|
||||||
|
* the db
|
||||||
|
*/
|
||||||
if (eventDescription != null && eventDescription.getTime() > 0) {
|
if (eventDescription != null && eventDescription.getTime() > 0) {
|
||||||
long objectID = bbart.getObjectID();
|
long objectID = bbart.getObjectID();
|
||||||
AbstractFile f = skCase.getAbstractFileById(objectID);
|
AbstractFile f = skCase.getAbstractFileById(objectID);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user