mirror of
https://github.com/elisspace/autopsy.git
synced 2026-09-29 13:59:52 +00:00
package rearrangements, bubble exceptions up
This commit is contained in:
@@ -29,6 +29,7 @@ import org.openide.awt.ActionID;
|
||||
import org.openide.awt.ActionReference;
|
||||
import org.openide.awt.ActionReferences;
|
||||
import org.openide.awt.ActionRegistration;
|
||||
import org.openide.util.Exceptions;
|
||||
import org.openide.util.HelpCtx;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.actions.CallableSystemAction;
|
||||
@@ -50,7 +51,8 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.timeline.Timeline")
|
||||
@ActionRegistration(displayName = "#CTL_MakeTimeline", lazy = false)
|
||||
@ActionReferences(value = {
|
||||
@ActionReference(path = "Menu/Tools", position = 102),
|
||||
@ActionReference(path = "Menu/Tools", position = 102)
|
||||
,
|
||||
@ActionReference(path = "Toolbars/Case", position = 102)})
|
||||
public final class OpenTimelineAction extends CallableSystemAction {
|
||||
|
||||
@@ -99,18 +101,23 @@ public final class OpenTimelineAction extends CallableSystemAction {
|
||||
}
|
||||
}
|
||||
setEnabled(false);
|
||||
}else if("false".equals(ModuleSettings.getConfigSetting("timeline", "enable_timeline"))) {
|
||||
} else if ("false".equals(ModuleSettings.getConfigSetting("timeline", "enable_timeline"))) {
|
||||
Platform.runLater(PromptDialogManager::showTimeLineDisabledMessage);
|
||||
setEnabled(false);
|
||||
}else {
|
||||
showTimeline();
|
||||
} else {
|
||||
try {
|
||||
showTimeline();
|
||||
} catch (TskCoreException ex) {
|
||||
MessageNotifyUtil.Message.error(Bundle.OpenTimelineAction_settingsErrorMessage());
|
||||
logger.log(Level.SEVERE, "Error showingtimeline.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NbBundle.Messages({
|
||||
"OpenTimelineAction.settingsErrorMessage=Failed to initialize timeline settings.",
|
||||
"OpenTimeLineAction.msgdlg.text=Could not create timeline, there are no data sources."})
|
||||
synchronized private void showTimeline(AbstractFile file, BlackboardArtifact artifact) {
|
||||
synchronized private void showTimeline(AbstractFile file, BlackboardArtifact artifact) throws TskCoreException {
|
||||
try {
|
||||
Case currentCase = Case.getOpenCase();
|
||||
if (currentCase.hasData() == false) {
|
||||
@@ -118,20 +125,13 @@ public final class OpenTimelineAction extends CallableSystemAction {
|
||||
logger.log(Level.INFO, "Could not create timeline, there are no data sources.");// NON-NLS
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (timeLineController == null) {
|
||||
timeLineController = new TimeLineController(currentCase);
|
||||
} else if (timeLineController.getAutopsyCase() != currentCase) {
|
||||
timeLineController.shutDownTimeLine();
|
||||
timeLineController = new TimeLineController(currentCase);
|
||||
}
|
||||
|
||||
timeLineController.showTimeLine(file, artifact);
|
||||
|
||||
} catch (IOException iOException) {
|
||||
MessageNotifyUtil.Message.error(Bundle.OpenTimelineAction_settingsErrorMessage());
|
||||
logger.log(Level.SEVERE, "Failed to initialize per case timeline settings.", iOException);
|
||||
if (timeLineController == null) {
|
||||
timeLineController = new TimeLineController(currentCase);
|
||||
} else if (timeLineController.getAutopsyCase() != currentCase) {
|
||||
timeLineController.shutDownTimeLine();
|
||||
timeLineController = new TimeLineController(currentCase);
|
||||
}
|
||||
timeLineController.showTimeLine(file, artifact);
|
||||
} catch (NoCurrentCaseException e) {
|
||||
//there is no case... Do nothing.
|
||||
}
|
||||
@@ -141,7 +141,7 @@ public final class OpenTimelineAction extends CallableSystemAction {
|
||||
* Open the Timeline window with the default initial view.
|
||||
*/
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||
public void showTimeline() {
|
||||
public void showTimeline() throws TskCoreException {
|
||||
showTimeline(null, null);
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ public final class OpenTimelineAction extends CallableSystemAction {
|
||||
* @param file The AbstractFile to show in the Timeline.
|
||||
*/
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||
public void showFileInTimeline(AbstractFile file) {
|
||||
public void showFileInTimeline(AbstractFile file) throws TskCoreException {
|
||||
showTimeline(file, null);
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ public final class OpenTimelineAction extends CallableSystemAction {
|
||||
* @param artifact The BlackboardArtifact to show in the Timeline.
|
||||
*/
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||
public void showArtifactInTimeline(BlackboardArtifact artifact) {
|
||||
public void showArtifactInTimeline(BlackboardArtifact artifact) throws TskCoreException {
|
||||
showTimeline(null, artifact);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Provides access to per-case timeline properties (key-value store).
|
||||
@@ -54,18 +55,20 @@ class PerCaseTimelineProperties {
|
||||
*
|
||||
* @throws IOException if there is a problem reading the state from disk
|
||||
*/
|
||||
public synchronized boolean isDBStale() throws IOException {
|
||||
|
||||
String stale = getProperty(STALE_KEY);
|
||||
return StringUtils.isBlank(stale) ? true : Boolean.valueOf(stale);
|
||||
|
||||
public synchronized boolean isDBStale() throws TskCoreException {
|
||||
try {
|
||||
String stale = getProperty(STALE_KEY);
|
||||
return StringUtils.isBlank(stale) ? true : Boolean.valueOf(stale);
|
||||
} catch (IOException iOException) {
|
||||
throw new TskCoreException("Error reading staleness of timeline DB", iOException);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* record the state of the events db as stale(true) or not stale(false).
|
||||
*
|
||||
* @param stale the new state of the event db. true for stale, false for not
|
||||
* stale.
|
||||
* stale.
|
||||
*
|
||||
* @throws IOException if there was a problem writing the state to disk.
|
||||
*/
|
||||
@@ -131,7 +134,7 @@ class PerCaseTimelineProperties {
|
||||
/**
|
||||
* Sets the given property to the given value.
|
||||
*
|
||||
* @param propertyKey - The key of the property to be modified.
|
||||
* @param propertyKey - The key of the property to be modified.
|
||||
* @param propertyValue - the value to set the property to.
|
||||
*
|
||||
* @throws IOException if there was a problem writing the property to disk
|
||||
|
||||
@@ -206,7 +206,7 @@ final class ShowInTimelineDialog extends Dialog<ViewInTimelineRequestedEvent> {
|
||||
* @param artifact The BlackboardArtifact to configure this dialog for.
|
||||
*/
|
||||
@NbBundle.Messages({"ShowInTimelineDialog.artifactTitle=View Result in Timeline."})
|
||||
ShowInTimelineDialog(TimeLineController controller, BlackboardArtifact artifact) {
|
||||
ShowInTimelineDialog(TimeLineController controller, BlackboardArtifact artifact) throws TskCoreException {
|
||||
//get events IDs from artifact
|
||||
this(controller, controller.getEventsModel().getEventIDsForArtifact(artifact));
|
||||
|
||||
@@ -236,7 +236,7 @@ final class ShowInTimelineDialog extends Dialog<ViewInTimelineRequestedEvent> {
|
||||
@NbBundle.Messages({"# {0} - file path",
|
||||
"ShowInTimelineDialog.fileTitle=View {0} in timeline.",
|
||||
"ShowInTimelineDialog.eventSelectionValidator.message=You must select an event."})
|
||||
ShowInTimelineDialog(TimeLineController controller, AbstractFile file) {
|
||||
ShowInTimelineDialog(TimeLineController controller, AbstractFile file) throws TskCoreException {
|
||||
this(controller, controller.getEventsModel().getEventIDsForFile(file, false));
|
||||
|
||||
/*
|
||||
|
||||
@@ -54,6 +54,7 @@ import javafx.concurrent.Task;
|
||||
import javafx.concurrent.Worker;
|
||||
import static javafx.concurrent.Worker.State.FAILED;
|
||||
import static javafx.concurrent.Worker.State.SUCCEEDED;
|
||||
import javafx.scene.control.Alert;
|
||||
import javax.annotation.concurrent.GuardedBy;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import javax.swing.SwingUtilities;
|
||||
@@ -63,6 +64,7 @@ import org.joda.time.Interval;
|
||||
import org.joda.time.ReadablePeriod;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.openide.util.Exceptions;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import static org.sleuthkit.autopsy.casemodule.Case.Events.CURRENT_CASE;
|
||||
@@ -81,7 +83,7 @@ import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import static org.sleuthkit.autopsy.ingest.IngestManager.IngestJobEvent.CANCELLED;
|
||||
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
||||
import org.sleuthkit.autopsy.timeline.db.EventsRepository;
|
||||
import org.sleuthkit.autopsy.timeline.datamodel.EventsRepository;
|
||||
import org.sleuthkit.autopsy.timeline.events.ViewInTimelineRequestedEvent;
|
||||
import org.sleuthkit.datamodel.timeline.filters.DescriptionFilter;
|
||||
import org.sleuthkit.datamodel.timeline.filters.RootFilter;
|
||||
@@ -90,6 +92,7 @@ import org.sleuthkit.datamodel.timeline.DescriptionLoD;
|
||||
import org.sleuthkit.datamodel.timeline.ZoomParams;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.timeline.EventType;
|
||||
import org.sleuthkit.datamodel.timeline.EventTypeZoomLevel;
|
||||
import org.sleuthkit.datamodel.timeline.IntervalUtils;
|
||||
@@ -116,7 +119,7 @@ import org.sleuthkit.datamodel.timeline.TimeUnits;
|
||||
"TimeLinecontroller.updateNowQuestion=Do you want to update the events database now?"})
|
||||
public class TimeLineController {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(TimeLineController.class.getName());
|
||||
private static final Logger logger = Logger.getLogger(TimeLineController.class.getName());
|
||||
|
||||
private static final ReadOnlyObjectWrapper<TimeZone> timeZone = new ReadOnlyObjectWrapper<>(TimeZone.getDefault());
|
||||
|
||||
@@ -292,7 +295,7 @@ public class TimeLineController {
|
||||
MessageNotifyUtil.Notify.error(Bundle.Timeline_dialogs_title(),
|
||||
stale ? Bundle.TimeLineController_setEventsDBStale_errMsgStale()
|
||||
: Bundle.TimeLineController_setEventsDBStale_errMsgNotStale());
|
||||
LOGGER.log(Level.SEVERE, "Error marking the timeline db as stale.", ex); //NON-NLS
|
||||
logger.log(Level.SEVERE, "Error marking the timeline db as stale.", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,7 +331,7 @@ public class TimeLineController {
|
||||
return viewMode.get();
|
||||
}
|
||||
|
||||
public TimeLineController(Case autoCase) throws IOException {
|
||||
public TimeLineController(Case autoCase) throws TskCoreException {
|
||||
this.autoCase = autoCase;
|
||||
this.perCaseTimelineProperties = new PerCaseTimelineProperties(autoCase);
|
||||
eventsDBStale.set(perCaseTimelineProperties.isDBStale());
|
||||
@@ -354,7 +357,13 @@ public class TimeLineController {
|
||||
historyManager.advance(InitialZoomState);
|
||||
|
||||
//clear the selected events when the view mode changes
|
||||
viewMode.addListener(observable -> selectEventIDs(Collections.emptySet()));
|
||||
viewMode.addListener(observable -> {
|
||||
try {
|
||||
selectEventIDs(Collections.emptySet());
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error clearing the timeline selection.", ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -368,7 +377,7 @@ public class TimeLineController {
|
||||
pushFilters(filteredEvents.getDefaultFilter());
|
||||
}
|
||||
|
||||
public void zoomOutToActivity() {
|
||||
public void zoomOutToActivity() throws TskCoreException {
|
||||
Interval boundingEventsInterval = filteredEvents.getBoundingEventsInterval(getJodaTimeZone());
|
||||
advance(filteredEvents.zoomParametersProperty().get().withTimeRange(boundingEventsInterval));
|
||||
}
|
||||
@@ -395,18 +404,16 @@ public class TimeLineController {
|
||||
* either file or artifact is not null the user will be prompted to choose a
|
||||
* derived event and time range to show in the Timeline List View.
|
||||
*
|
||||
* @param repoBuilder A Function from Consumer<Worker.State> to
|
||||
* CancellationProgressTask<?>. Ie a function that
|
||||
* given a worker state listener, produces a task with
|
||||
* that listener attached. Expected to be a method
|
||||
* reference to either
|
||||
* EventsRepository.rebuildRepository() or
|
||||
* EventsRepository.rebuildTags()
|
||||
* @param repoBuilder A Function from Consumer<Worker.State> to
|
||||
* CancellationProgressTask<?>. Ie a function that given a worker state
|
||||
* listener, produces a task with that listener attached. Expected to be a
|
||||
* method reference to either EventsRepository.rebuildRepository() or
|
||||
* EventsRepository.rebuildTags()
|
||||
* @param markDBNotStale After the repo is rebuilt should it be marked not
|
||||
* stale
|
||||
* @param file The AbstractFile from which to choose an event to
|
||||
* show in the List View.
|
||||
* @param artifact The BlackboardArtifact to show in the List View.
|
||||
* stale
|
||||
* @param file The AbstractFile from which to choose an event to show in the
|
||||
* List View.
|
||||
* @param artifact The BlackboardArtifact to show in the List View.
|
||||
*/
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||
@NbBundle.Messages({
|
||||
@@ -443,7 +450,7 @@ public class TimeLineController {
|
||||
MessageNotifyUtil.Notify.error(Bundle.Timeline_dialogs_title(),
|
||||
ingestRunning ? Bundle.TimeLineController_setIngestRunning_errMsgRunning()
|
||||
: Bundle.TimeLinecontroller_setIngestRunning_errMsgNotRunning());
|
||||
LOGGER.log(Level.SEVERE, "Error marking the ingest state while the timeline db was populated.", ex); //NON-NLS
|
||||
logger.log(Level.SEVERE, "Error marking the ingest state while the timeline db was populated.", ex); //NON-NLS
|
||||
}
|
||||
if (markDBNotStale) {
|
||||
setEventsDBStale(false);
|
||||
@@ -453,16 +460,27 @@ public class TimeLineController {
|
||||
SwingUtilities.invokeLater(TimeLineController.this::showWindow);
|
||||
TimeLineController.this.showFullRange();
|
||||
} else {
|
||||
//prompt user to pick specific event and time range
|
||||
ShowInTimelineDialog showInTimelineDilaog =
|
||||
(file == null)
|
||||
? new ShowInTimelineDialog(TimeLineController.this, artifact)
|
||||
: new ShowInTimelineDialog(TimeLineController.this, file);
|
||||
Optional<ViewInTimelineRequestedEvent> dialogResult = showInTimelineDilaog.showAndWait();
|
||||
dialogResult.ifPresent(viewInTimelineRequestedEvent -> {
|
||||
SwingUtilities.invokeLater(TimeLineController.this::showWindow);
|
||||
showInListView(viewInTimelineRequestedEvent); //show requested event in list view
|
||||
});
|
||||
|
||||
try {
|
||||
//prompt user to pick specific event and time range
|
||||
ShowInTimelineDialog showInTimelineDilaog = (file == null)
|
||||
? new ShowInTimelineDialog(TimeLineController.this, artifact)
|
||||
: new ShowInTimelineDialog(TimeLineController.this, file);
|
||||
Optional<ViewInTimelineRequestedEvent> dialogResult = showInTimelineDilaog.showAndWait();
|
||||
dialogResult.ifPresent(viewInTimelineRequestedEvent -> {
|
||||
SwingUtilities.invokeLater(TimeLineController.this::showWindow);
|
||||
try {
|
||||
showInListView(viewInTimelineRequestedEvent); //show requested event in list view
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error showing requested events in listview: " + viewInTimelineRequestedEvent, ex);
|
||||
new Alert(Alert.AlertType.ERROR, "There was an error opening Timeline.").showAndWait();
|
||||
}
|
||||
});
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
logger.log(Level.SEVERE, "Error showing Timeline " , tskCoreException);
|
||||
new Alert(Alert.AlertType.ERROR, "There was an error opening Timeline.").showAndWait();
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case FAILED:
|
||||
@@ -493,8 +511,8 @@ public class TimeLineController {
|
||||
* Rebuild the entire repo in the background, and show the timeline when
|
||||
* done.
|
||||
*
|
||||
* @param file The AbstractFile from which to choose an event to show in
|
||||
* the List View.
|
||||
* @param file The AbstractFile from which to choose an event to show in the
|
||||
* List View.
|
||||
* @param artifact The BlackboardArtifact to show in the List View.
|
||||
*/
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||
@@ -506,8 +524,8 @@ public class TimeLineController {
|
||||
* Drop the tags table and rebuild it in the background, and show the
|
||||
* timeline when done.
|
||||
*
|
||||
* @param file The AbstractFile from which to choose an event to show in
|
||||
* the List View.
|
||||
* @param file The AbstractFile from which to choose an event to show in the
|
||||
* List View.
|
||||
* @param artifact The BlackboardArtifact to show in the List View.
|
||||
*/
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||
@@ -529,10 +547,10 @@ public class TimeLineController {
|
||||
* ViewInTimelineRequestedEvent in the List View.
|
||||
*
|
||||
* @param requestEvent Contains the ID of the requested events and the
|
||||
* timerange to show.
|
||||
* timerange to show.
|
||||
*/
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||
private void showInListView(ViewInTimelineRequestedEvent requestEvent) {
|
||||
private void showInListView(ViewInTimelineRequestedEvent requestEvent) throws TskCoreException {
|
||||
synchronized (filteredEvents) {
|
||||
setViewMode(ViewMode.LIST);
|
||||
selectEventIDs(requestEvent.getEventIDs());
|
||||
@@ -563,8 +581,8 @@ public class TimeLineController {
|
||||
* Add the case and ingest listeners, prompt for rebuilding the database if
|
||||
* necessary, and show the timeline window.
|
||||
*
|
||||
* @param file The AbstractFile from which to choose an event to show in
|
||||
* the List View.
|
||||
* @param file The AbstractFile from which to choose an event to show in the
|
||||
* List View.
|
||||
* @param artifact The BlackboardArtifact to show in the List View.
|
||||
*/
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||
@@ -576,7 +594,14 @@ public class TimeLineController {
|
||||
Case.addPropertyChangeListener(caseListener);
|
||||
listeningToAutopsy = true;
|
||||
}
|
||||
Platform.runLater(() -> promptForRebuild(file, artifact));
|
||||
Platform.runLater(() -> {
|
||||
try {
|
||||
promptForRebuild(file, artifact);
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error prompting for timeline rebuild.", ex);
|
||||
new Alert(Alert.AlertType.ERROR, "There was an error opening Timeline.").showAndWait();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -585,12 +610,12 @@ public class TimeLineController {
|
||||
* confirms, rebuilds the database. Shows the timeline window when the
|
||||
* rebuild is done, or immediately if the rebuild is not confirmed.
|
||||
*
|
||||
* @param file The AbstractFile from which to choose an event to show in
|
||||
* the List View.
|
||||
* @param file The AbstractFile from which to choose an event to show in the
|
||||
* List View.
|
||||
* @param artifact The BlackboardArtifact to show in the List View.
|
||||
*/
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||
private void promptForRebuild(AbstractFile file, BlackboardArtifact artifact) {
|
||||
private void promptForRebuild(AbstractFile file, BlackboardArtifact artifact) throws TskCoreException {
|
||||
//if there is an existing prompt or progressdialog, just show that
|
||||
if (promptDialogManager.bringCurrentDialogToFront()) {
|
||||
return;
|
||||
@@ -626,7 +651,7 @@ public class TimeLineController {
|
||||
* The potential reasons are not necessarily orthogonal to each other.
|
||||
*
|
||||
* @return A list of reasons why the user might won't to rebuild the
|
||||
* database.
|
||||
* database.
|
||||
*/
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.ANY)
|
||||
@NbBundle.Messages({"TimeLineController.errorTitle=Timeline error.",
|
||||
@@ -635,7 +660,7 @@ public class TimeLineController {
|
||||
"TimeLineController.rebuildReasons.outOfDate=The event data is out of date: Not all events will be visible.",
|
||||
"TimeLineController.rebuildReasons.ingestWasRunning=The Timeline events database was previously populated while ingest was running: Some events may be missing, incomplete, or inaccurate.",
|
||||
"TimeLineController.rebuildReasons.incompleteOldSchema=The Timeline events database was previously populated without incomplete information: Some features may be unavailable or non-functional unless you update the events database."})
|
||||
private List<String> getRebuildReasons() {
|
||||
private List<String> getRebuildReasons() throws TskCoreException {
|
||||
ArrayList<String> rebuildReasons = new ArrayList<>();
|
||||
|
||||
try {
|
||||
@@ -645,7 +670,7 @@ public class TimeLineController {
|
||||
}
|
||||
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error determing the state of the timeline db. We will assume the it is out of date.", ex); //NON-NLS
|
||||
logger.log(Level.SEVERE, "Error determing the state of the timeline db. We will assume the it is out of date.", ex); //NON-NLS
|
||||
MessageNotifyUtil.Notify.error(Bundle.TimeLineController_errorTitle(),
|
||||
Bundle.TimeLineController_outOfDate_errorMessage());
|
||||
rebuildReasons.add(Bundle.TimeLineController_rebuildReasons_outOfDateError());
|
||||
@@ -666,7 +691,7 @@ public class TimeLineController {
|
||||
* around the middle of the currently viewed time range.
|
||||
*
|
||||
* @param period The period of time to show around the current center of the
|
||||
* view.
|
||||
* view.
|
||||
*/
|
||||
synchronized public void pushPeriod(ReadablePeriod period) {
|
||||
synchronized (filteredEvents) {
|
||||
@@ -726,7 +751,7 @@ public class TimeLineController {
|
||||
* @param timeRange The Interval to view.
|
||||
*
|
||||
* @return True if the interval was changed. False if the interval was the
|
||||
* same as the existing one and no change happened.
|
||||
* same as the existing one and no change happened.
|
||||
*/
|
||||
synchronized public boolean pushTimeRange(Interval timeRange) {
|
||||
//clamp timerange to case
|
||||
@@ -821,7 +846,7 @@ public class TimeLineController {
|
||||
*
|
||||
* @param eventIDs The eventIDs to select
|
||||
*/
|
||||
synchronized public void selectEventIDs(Collection<Long> eventIDs) {
|
||||
synchronized public void selectEventIDs(Collection<Long> eventIDs) throws TskCoreException {
|
||||
selectedTimeRange.set(filteredEvents.getSpanningInterval(eventIDs));
|
||||
selectedEventIDs.setAll(eventIDs);
|
||||
}
|
||||
@@ -847,7 +872,7 @@ public class TimeLineController {
|
||||
|
||||
}
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
LOGGER.log(Level.SEVERE, getTitle() + " Unexpected error", ex); //NON-NLS
|
||||
logger.log(Level.SEVERE, getTitle() + " Unexpected error", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -915,7 +940,7 @@ public class TimeLineController {
|
||||
* Register the given object to receive events.
|
||||
*
|
||||
* @param o The object to register. Must implement public methods annotated
|
||||
* with Subscribe.
|
||||
* with Subscribe.
|
||||
*/
|
||||
synchronized public void registerForEvents(Object o) {
|
||||
eventbus.register(o);
|
||||
|
||||
@@ -20,10 +20,14 @@ package org.sleuthkit.autopsy.timeline.actions;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.swing.AbstractAction;
|
||||
import org.openide.util.Exceptions;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.actions.SystemAction;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.timeline.OpenTimelineAction;
|
||||
import org.sleuthkit.datamodel.timeline.ArtifactEventType;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
@@ -37,12 +41,13 @@ import org.sleuthkit.datamodel.timeline.EventType;
|
||||
public final class ViewArtifactInTimelineAction extends AbstractAction {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger logger = Logger.getLogger(ViewFileInTimelineAction.class.getName());
|
||||
|
||||
private static final Set<ArtifactEventType> ARTIFACT_EVENT_TYPES =
|
||||
EventType.allTypes.stream()
|
||||
.filter((EventType t) -> t instanceof ArtifactEventType)
|
||||
.map(ArtifactEventType.class::cast)
|
||||
.collect(Collectors.toSet());
|
||||
private static final Set<ArtifactEventType> ARTIFACT_EVENT_TYPES
|
||||
= EventType.allTypes.stream()
|
||||
.filter((EventType t) -> t instanceof ArtifactEventType)
|
||||
.map(ArtifactEventType.class::cast)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
private final BlackboardArtifact artifact;
|
||||
|
||||
@@ -54,7 +59,12 @@ public final class ViewArtifactInTimelineAction extends AbstractAction {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
SystemAction.get(OpenTimelineAction.class).showArtifactInTimeline(artifact);
|
||||
try {
|
||||
SystemAction.get(OpenTimelineAction.class).showArtifactInTimeline(artifact);
|
||||
} catch (TskCoreException ex) {
|
||||
MessageNotifyUtil.Message.error("Error opening Timeline");
|
||||
logger.log(Level.SEVERE, "Error showing timeline.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,11 +19,15 @@
|
||||
package org.sleuthkit.autopsy.timeline.actions;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.AbstractAction;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.actions.SystemAction;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.timeline.OpenTimelineAction;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
/**
|
||||
@@ -34,6 +38,8 @@ public final class ViewFileInTimelineAction extends AbstractAction {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ViewFileInTimelineAction.class.getName());
|
||||
|
||||
private final AbstractFile file;
|
||||
|
||||
private ViewFileInTimelineAction(AbstractFile file, String displayName) {
|
||||
@@ -62,6 +68,11 @@ public final class ViewFileInTimelineAction extends AbstractAction {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
SystemAction.get(OpenTimelineAction.class).showFileInTimeline(file);
|
||||
try {
|
||||
SystemAction.get(OpenTimelineAction.class).showFileInTimeline(file);
|
||||
} catch (TskCoreException ex) {
|
||||
MessageNotifyUtil.Message.error("Error opening Timeline");
|
||||
logger.log(Level.SEVERE, "Error showing timeline.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,19 +18,24 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.timeline.actions;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import org.controlsfx.control.action.Action;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
||||
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class ZoomToEvents extends Action {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ZoomToEvents.class.getName());
|
||||
private static final Image MAGNIFIER_OUT = new Image("/org/sleuthkit/autopsy/timeline/images/magnifier-zoom-out-red.png", 16, 16, true, true); //NOI18N NON-NLS
|
||||
|
||||
@NbBundle.Messages({"ZoomToEvents.action.text=Zoom to events",
|
||||
@@ -40,7 +45,12 @@ public class ZoomToEvents extends Action {
|
||||
setLongText(Bundle.ZoomToEvents_longText());
|
||||
setGraphic(new ImageView(MAGNIFIER_OUT));
|
||||
setEventHandler(actionEvent -> {
|
||||
controller.zoomOutToActivity();
|
||||
try {
|
||||
controller.zoomOutToActivity();
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error invoking ZoomToEvents action", ex);
|
||||
new Alert(Alert.AlertType.ERROR, "Error zomming").showAndWait();
|
||||
}
|
||||
});
|
||||
|
||||
//disable action when the current time range already encompases the entire case.
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
msgdlg.problem.text=\u30bf\u30a4\u30e0\u30e9\u30a4\u30f3\u306b\u5165\u529b\u3059\u308b\u969b\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u5168\u3066\u306e\u30a4\u30d9\u30f3\u30c8\u304c\u5b58\u5728\u3057\u306a\u3044\u304b\u6b63\u78ba\u3067\u306f\u306a\u3044\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002
|
||||
progressWindow.msg.commitingDb=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b\u30a4\u30d9\u30f3\u30c8\u3092\u30b3\u30df\u30c3\u30c8\u3057\u3066\u3044\u307e\u3059\u3002
|
||||
progressWindow.msg.gatheringData=\u30a4\u30d9\u30f3\u30c8\u30c7\u30fc\u30bf\u3092\u53ce\u96c6\u4e2d
|
||||
progressWindow.msg.populateMacEventsFiles=\u30d5\u30a1\u30a4\u30eb\u306eMAC\u30bf\u30a4\u30e0\u3092\u5165\u529b\u4e2d
|
||||
progressWindow.msg.refreshingFileTags=\u30d5\u30a1\u30a4\u30eb\u30bf\u30b0\u3092\u30ea\u30d5\u30ec\u30c3\u30b7\u30e5\u4e2d
|
||||
progressWindow.msg.refreshingResultTags=\u7d50\u679c\u30bf\u30b0\u3092\u30ea\u30d5\u30ec\u30c3\u30b7\u30e5\u4e2d
|
||||
progressWindow.populatingXevents={0}\u30a4\u30d9\u30f3\u30c8\u3092\u5165\u529b\u4e2d
|
||||
BaseTypes.fileSystem.name=\u30d5\u30a1\u30a4\u30eb\u30b7\u30b9\u30c6\u30e0
|
||||
BaseTypes.miscTypes.name=\u305d\u306e\u4ed6\u30bf\u30a4\u30d7
|
||||
BaseTypes.webActivity.name=\u30a6\u30a7\u30d6\u30a2\u30af\u30c6\u30a3\u30d3\u30c6\u30a3
|
||||
FileSystemTypes.fileAccessed.name=\u30a2\u30af\u30bb\u30b9\u3055\u308c\u305f\u30d5\u30a1\u30a4\u30eb
|
||||
FileSystemTypes.fileChanged.name=\u5909\u66f4\u3055\u308c\u305f\u30d5\u30a1\u30a4\u30eb
|
||||
FileSystemTypes.fileCreated.name=\u4f5c\u6210\u3055\u308c\u305f\u30d5\u30a1\u30a4\u30eb
|
||||
FileSystemTypes.fileModified.name=\u4fee\u6b63\u3055\u308c\u305f\u30d5\u30a1\u30a4\u30eb
|
||||
MiscTypes.Calls.name=\u30b3\u30fc\u30eb
|
||||
MiscTypes.devicesAttached.name=\u63a5\u7d9a\u3055\u308c\u3066\u3044\u308b\u6a5f\u5668
|
||||
MiscTypes.Email.name=Email
|
||||
MiscTypes.exif.name=Exif
|
||||
MiscTypes.GPSRoutes.name=GPS\u30eb\u30fc\u30c8
|
||||
MiscTypes.GPSTrackpoint.name=\u4f4d\u7f6e\u60c5\u5831\u5c65\u6b74
|
||||
MiscTypes.installedPrograms.name=\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3055\u308c\u3066\u3044\u308b\u30d7\u30ed\u30b0\u30e9\u30e0
|
||||
MiscTypes.message.name=\u30e1\u30c3\u30bb\u30fc\u30b8
|
||||
MiscTypes.recentDocuments.name=\u6700\u8fd1\u306e\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8
|
||||
RootEventType.eventTypes.name=\u30a4\u30d9\u30f3\u30c8\u30bf\u30a4\u30d7
|
||||
WebTypes.webBookmarks.name=\u30a6\u30a7\u30d6\u30d6\u30c3\u30af\u30de\u30fc\u30af
|
||||
WebTypes.webCookies.name=\u30a6\u30a7\u30d6\u30af\u30c3\u30ad\u30fc
|
||||
WebTypes.webDownloads.name=\u30a6\u30a7\u30d6\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9
|
||||
WebTypes.webHistory.name=\u30a6\u30a7\u30d6\u5c65\u6b74
|
||||
WebTypes.webSearch.name=\u30a6\u30a7\u30d6\u691c\u7d22
|
||||
+107
-92
@@ -16,8 +16,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.timeline.db;
|
||||
package org.sleuthkit.autopsy.timeline.datamodel;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
@@ -59,16 +61,15 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||
import org.sleuthkit.autopsy.timeline.CancellationProgressTask;
|
||||
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
||||
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
||||
import org.sleuthkit.datamodel.timeline.ArtifactEventType;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||
import org.sleuthkit.datamodel.ContentTag;
|
||||
import org.sleuthkit.datamodel.EventDB;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.Tag;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.TimelineManager;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
import org.sleuthkit.datamodel.timeline.CombinedEvent;
|
||||
@@ -103,12 +104,12 @@ public class EventsRepository {
|
||||
|
||||
private final Executor workerExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("eventrepository-worker-%d").build()); //NON-NLS
|
||||
private DBPopulationWorker dbWorker;
|
||||
private final EventDB eventDB;
|
||||
private final TimelineManager eventManager;
|
||||
private final Case autoCase;
|
||||
private final FilteredEventsModel modelInstance;
|
||||
|
||||
private final LoadingCache<Object, Long> maxCache;
|
||||
private final LoadingCache<Object, Long> minCache;
|
||||
private final LoadingCache<Void, Long> maxCache;
|
||||
private final LoadingCache<Void, Long> minCache;
|
||||
private final LoadingCache<Long, SingleEvent> idToEventCache;
|
||||
private final LoadingCache<ZoomParams, Map<EventType, Long>> eventCountsCache;
|
||||
private final LoadingCache<ZoomParams, List<EventStripe>> eventStripeCache;
|
||||
@@ -133,37 +134,56 @@ public class EventsRepository {
|
||||
return hashSetMap;
|
||||
}
|
||||
|
||||
public Interval getBoundingEventsInterval(Interval timeRange, RootFilter filter, DateTimeZone tz) {
|
||||
return eventDB.getBoundingEventsInterval(timeRange, filter,tz );
|
||||
public Interval getBoundingEventsInterval(Interval timeRange, RootFilter filter, DateTimeZone tz) throws TskCoreException {
|
||||
return eventManager.getBoundingEventsInterval(timeRange, filter, tz);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a FilteredEvetns object with this repository as underlying source
|
||||
* of events
|
||||
* of events
|
||||
*/
|
||||
public FilteredEventsModel getEventsModel() {
|
||||
return modelInstance;
|
||||
}
|
||||
|
||||
public EventsRepository(Case autoCase, ReadOnlyObjectProperty<ZoomParams> currentStateProperty) {
|
||||
public EventsRepository(Case autoCase, ReadOnlyObjectProperty<ZoomParams> currentStateProperty) throws TskCoreException {
|
||||
this.autoCase = autoCase;
|
||||
//TODO: we should check that case is open, or get passed a case object/directory -jm
|
||||
this.eventDB = EventDB.getEventDB(autoCase.getSleuthkitCase());
|
||||
this.eventManager = autoCase.getSleuthkitCase().getTimelineManager();
|
||||
populateFilterData(autoCase.getSleuthkitCase());
|
||||
idToEventCache = CacheBuilder.newBuilder()
|
||||
.maximumSize(5000L)
|
||||
.expireAfterAccess(10, TimeUnit.MINUTES)
|
||||
.build(CacheLoader.from(eventDB::getEventById));
|
||||
.build(new CacheLoader<Long, SingleEvent>() {
|
||||
@Override
|
||||
public SingleEvent load(Long eventID) throws Exception {
|
||||
return eventManager.getEventById(eventID);
|
||||
}
|
||||
});
|
||||
eventCountsCache = CacheBuilder.newBuilder()
|
||||
.maximumSize(1000L)
|
||||
.expireAfterAccess(10, TimeUnit.MINUTES)
|
||||
.build(CacheLoader.from(eventDB::countEventsByType));
|
||||
.build(CacheLoader.from(eventManager::countEventsByType));
|
||||
eventStripeCache = CacheBuilder.newBuilder()
|
||||
.maximumSize(1000L)
|
||||
.expireAfterAccess(10, TimeUnit.MINUTES
|
||||
).build(CacheLoader.from((params) -> eventDB.getEventStripes(params,TimeLineController.getJodaTimeZone())));
|
||||
maxCache = CacheBuilder.newBuilder().build(CacheLoader.from(eventDB::getMaxTime));
|
||||
minCache = CacheBuilder.newBuilder().build(CacheLoader.from(eventDB::getMinTime));
|
||||
).build(new CacheLoader<ZoomParams, List<EventStripe>>() {
|
||||
@Override
|
||||
public List<EventStripe> load(ZoomParams params) throws Exception {
|
||||
return eventManager.getEventStripes(params, TimeLineController.getJodaTimeZone());
|
||||
}
|
||||
});
|
||||
maxCache = CacheBuilder.newBuilder().build(new CacheLoader<Void, Long>() {
|
||||
@Override
|
||||
public Long load(Void nil) throws TskCoreException {
|
||||
return eventManager.getMaxTime();
|
||||
}
|
||||
});
|
||||
minCache = CacheBuilder.newBuilder().build(new CacheLoader<Void, Long>() {
|
||||
@Override
|
||||
public Long load(Void nil) throws TskCoreException {
|
||||
return eventManager.getMinTime();
|
||||
}
|
||||
});
|
||||
this.modelInstance = new FilteredEventsModel(this, currentStateProperty);
|
||||
}
|
||||
|
||||
@@ -171,7 +191,7 @@ public class EventsRepository {
|
||||
* @return min time (in seconds from unix epoch)
|
||||
*/
|
||||
public Long getMaxTime() {
|
||||
return maxCache.getUnchecked("max"); // NON-NLS
|
||||
return maxCache.getUnchecked(null); // NON-NLS
|
||||
|
||||
}
|
||||
|
||||
@@ -179,7 +199,7 @@ public class EventsRepository {
|
||||
* @return max tie (in seconds from unix epoch)
|
||||
*/
|
||||
public Long getMinTime() {
|
||||
return minCache.getUnchecked("min"); // NON-NLS
|
||||
return minCache.getUnchecked(null); // NON-NLS
|
||||
|
||||
}
|
||||
|
||||
@@ -208,26 +228,23 @@ public class EventsRepository {
|
||||
}
|
||||
|
||||
synchronized public int countAllEvents() {
|
||||
return eventDB.countAllEvents();
|
||||
return eventManager.countAllEvents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a List of event IDs for the events that are derived from the given
|
||||
* file.
|
||||
*
|
||||
* @param file The AbstractFile to get derived event IDs
|
||||
* for.
|
||||
* @param file The AbstractFile to get derived event IDs for.
|
||||
* @param includeDerivedArtifacts If true, also get event IDs for events
|
||||
* derived from artifacts derived form this
|
||||
* file. If false, only gets events derived
|
||||
* directly from this file (file system
|
||||
* timestamps).
|
||||
* derived from artifacts derived form this file. If false, only gets events
|
||||
* derived directly from this file (file system timestamps).
|
||||
*
|
||||
* @return A List of event IDs for the events that are derived from the
|
||||
* given file.
|
||||
* given file.
|
||||
*/
|
||||
public List<Long> getEventIDsForFile(AbstractFile file, boolean includeDerivedArtifacts) {
|
||||
return eventDB.getEventIDsForFile(file, includeDerivedArtifacts);
|
||||
public List<Long> getEventIDsForFile(AbstractFile file, boolean includeDerivedArtifacts) throws TskCoreException {
|
||||
return eventManager.getEventIDsForFile(file, includeDerivedArtifacts);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -237,10 +254,10 @@ public class EventsRepository {
|
||||
* @param artifact The BlackboardArtifact to get derived event IDs for.
|
||||
*
|
||||
* @return A List of event IDs for the events that are derived from the
|
||||
* given artifact.
|
||||
* given artifact.
|
||||
*/
|
||||
public List<Long> getEventIDsForArtifact(BlackboardArtifact artifact) {
|
||||
return eventDB.getEventIDsForArtifact(artifact);
|
||||
public List<Long> getEventIDsForArtifact(BlackboardArtifact artifact) throws TskCoreException {
|
||||
return eventManager.getEventIDsForArtifact(artifact);
|
||||
}
|
||||
|
||||
private void invalidateCaches() {
|
||||
@@ -251,8 +268,8 @@ public class EventsRepository {
|
||||
idToEventCache.invalidateAll();
|
||||
}
|
||||
|
||||
public List<Long> getEventIDs(Interval timeRange, RootFilter filter) {
|
||||
return eventDB.getEventIDs(timeRange, filter);
|
||||
public List<Long> getEventIDs(Interval timeRange, RootFilter filter) throws TskCoreException {
|
||||
return eventManager.getEventIDs(timeRange, filter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -262,20 +279,20 @@ public class EventsRepository {
|
||||
* together.
|
||||
*
|
||||
* @param timeRange The Interval that all returned events must be within.
|
||||
* @param filter The Filter that all returned events must pass.
|
||||
* @param filter The Filter that all returned events must pass.
|
||||
*
|
||||
* @return A List of combined events, sorted by timestamp.
|
||||
*/
|
||||
public List<CombinedEvent> getCombinedEvents(Interval timeRange, RootFilter filter) {
|
||||
return eventDB.getCombinedEvents(timeRange, filter);
|
||||
public List<CombinedEvent> getCombinedEvents(Interval timeRange, RootFilter filter) throws TskCoreException {
|
||||
return eventManager.getCombinedEvents(timeRange, filter);
|
||||
}
|
||||
|
||||
public Interval getSpanningInterval(Collection<Long> eventIDs) {
|
||||
return eventDB.getSpanningInterval(eventIDs);
|
||||
public Interval getSpanningInterval(Collection<Long> eventIDs) throws TskCoreException {
|
||||
return eventManager.getSpanningInterval(eventIDs);
|
||||
}
|
||||
|
||||
public boolean hasNewColumns() {
|
||||
return eventDB.hasNewColumns();
|
||||
public boolean hasNewColumns() throws TskCoreException {
|
||||
return eventManager.hasNewColumns();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -286,8 +303,8 @@ public class EventsRepository {
|
||||
*
|
||||
* @return a map from tagname displayname to count of applications
|
||||
*/
|
||||
public Map<String, Long> getTagCountsByTagName(Set<Long> eventIDsWithTags) {
|
||||
return eventDB.getTagCountsByTagName(eventIDsWithTags);
|
||||
public Map<String, Long> getTagCountsByTagName(Set<Long> eventIDsWithTags) throws TskCoreException {
|
||||
return eventManager.getTagCountsByTagName(eventIDsWithTags);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -296,13 +313,13 @@ public class EventsRepository {
|
||||
*
|
||||
* @param skCase
|
||||
*/
|
||||
synchronized private void populateFilterData(SleuthkitCase skCase) {
|
||||
synchronized private void populateFilterData(SleuthkitCase skCase) throws TskCoreException {
|
||||
|
||||
for (Map.Entry<Long, String> hashSet : eventDB.getHashSetNames().entrySet()) {
|
||||
for (Map.Entry<Long, String> hashSet : eventManager.getHashSetNames().entrySet()) {
|
||||
hashSetMap.putIfAbsent(hashSet.getKey(), hashSet.getValue());
|
||||
}
|
||||
//because there is no way to remove a datasource we only add to this map.
|
||||
for (Long id : eventDB.getDataSourceIDs()) {
|
||||
for (Long id : eventManager.getDataSourceIDs()) {
|
||||
try {
|
||||
datasourcesMap.putIfAbsent(id, skCase.getContentById(id).getDataSource().getName());
|
||||
} catch (TskCoreException ex) {
|
||||
@@ -318,16 +335,16 @@ public class EventsRepository {
|
||||
}
|
||||
}
|
||||
|
||||
synchronized public Set<Long> addTag(long objID, Long artifactID, Tag tag, EventDB.EventTransaction trans) {
|
||||
Set<Long> updatedEventIDs = eventDB.addTag(objID, artifactID, tag, trans);
|
||||
synchronized public Set<Long> addTag(long objID, Long artifactID, Tag tag) throws TskCoreException {
|
||||
Set<Long> updatedEventIDs = eventManager.addTag(objID, artifactID, tag);
|
||||
if (!updatedEventIDs.isEmpty()) {
|
||||
invalidateCaches(updatedEventIDs);
|
||||
}
|
||||
return updatedEventIDs;
|
||||
}
|
||||
|
||||
synchronized public Set<Long> deleteTag(long objID, Long artifactID, long tagID, boolean tagged) {
|
||||
Set<Long> updatedEventIDs = eventDB.deleteTag(objID, artifactID, tagID, tagged);
|
||||
synchronized public Set<Long> deleteTag(long objID, Long artifactID, long tagID, boolean tagged) throws TskCoreException {
|
||||
Set<Long> updatedEventIDs = eventManager.deleteTag(objID, artifactID, tagID, tagged);
|
||||
if (!updatedEventIDs.isEmpty()) {
|
||||
invalidateCaches(updatedEventIDs);
|
||||
}
|
||||
@@ -351,7 +368,7 @@ public class EventsRepository {
|
||||
* that don't have them. New filters are selected by default.
|
||||
*
|
||||
* @param tagsFilter the tags filter to modify so it is consistent with the
|
||||
* tags in use in the case
|
||||
* tags in use in the case
|
||||
*/
|
||||
public void syncTagsFilter(TagsFilter tagsFilter) {
|
||||
for (TagName t : tagNames) {
|
||||
@@ -363,7 +380,7 @@ public class EventsRepository {
|
||||
}
|
||||
|
||||
public boolean areFiltersEquivalent(RootFilter f1, RootFilter f2) {
|
||||
return eventDB.getSQLWhere(f1).equals(eventDB.getSQLWhere(f2));
|
||||
return eventManager.getSQLWhere(f1).equals(eventManager.getSQLWhere(f2));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -371,11 +388,11 @@ public class EventsRepository {
|
||||
* rebuild the entire repo.
|
||||
*
|
||||
* @param onStateChange called when he background task changes state.
|
||||
* Clients can use this to handle failure, or cleanup
|
||||
* operations for example.
|
||||
* Clients can use this to handle failure, or cleanup operations for
|
||||
* example.
|
||||
*
|
||||
* @return the task that will rebuild the repo in a background thread. The
|
||||
* task has already been started.
|
||||
* task has already been started.
|
||||
*/
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||
public CancellationProgressTask<Void> rebuildRepository(Consumer<Worker.State> onStateChange) {
|
||||
@@ -387,11 +404,11 @@ public class EventsRepository {
|
||||
* drop and rebuild the tags in the repo.
|
||||
*
|
||||
* @param onStateChange called when he background task changes state.
|
||||
* Clients can use this to handle failure, or cleanup
|
||||
* operations for example.
|
||||
* Clients can use this to handle failure, or cleanup operations for
|
||||
* example.
|
||||
*
|
||||
* @return the task that will rebuild the repo in a background thread. The
|
||||
* task has already been started.
|
||||
* task has already been started.
|
||||
*/
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||
public CancellationProgressTask<Void> rebuildTags(Consumer<Worker.State> onStateChange) {
|
||||
@@ -401,13 +418,13 @@ public class EventsRepository {
|
||||
/**
|
||||
* rebuild the repo.
|
||||
*
|
||||
* @param mode the rebuild mode to use.
|
||||
* @param mode the rebuild mode to use.
|
||||
* @param onStateChange called when he background task changes state.
|
||||
* Clients can use this to handle failure, or cleanup
|
||||
* operations for example.
|
||||
* Clients can use this to handle failure, or cleanup operations for
|
||||
* example.
|
||||
*
|
||||
* @return the task that will rebuild the repo in a background thread. The
|
||||
* task has already been started.
|
||||
* task has already been started.
|
||||
*/
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||
private CancellationProgressTask<Void> rebuildRepository(final DBPopulationMode mode, Consumer<Worker.State> onStateChange) {
|
||||
@@ -512,49 +529,47 @@ public class EventsRepository {
|
||||
"progressWindow.msg.gatheringData=Gathering event data",
|
||||
"progressWindow.msg.commitingDb=Committing events database"})
|
||||
protected Void call() throws Exception {
|
||||
EventDB.EventTransaction trans = null;
|
||||
|
||||
SleuthkitCase.CaseDbTransaction trans = eventManager.beginTransaction();
|
||||
if (dbPopulationMode == DBPopulationMode.FULL) {
|
||||
//drop old db, and add back MAC and artifact events
|
||||
logger.log(Level.INFO, "Beginning population of timeline db."); // NON-NLS
|
||||
restartProgressHandle(Bundle.progressWindow_msg_gatheringData(), "", -1D, 1, true);
|
||||
//reset database //TODO: can we do more incremental updates? -jm
|
||||
eventDB.reInitializeDB();
|
||||
eventManager.reInitializeDB();
|
||||
//grab ids of all files
|
||||
List<Long> fileIDs = skCase.findAllFileIdsWhere("name != '.' AND name != '..'" +
|
||||
" AND type != " + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()); //NON-NLS
|
||||
List<Long> fileIDs = skCase.findAllFileIdsWhere("name != '.' AND name != '..'"
|
||||
+ " AND type != " + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()); //NON-NLS
|
||||
final int numFiles = fileIDs.size();
|
||||
|
||||
trans = eventDB.beginTransaction();
|
||||
insertMACTimeEvents(numFiles, fileIDs, trans);
|
||||
insertArtifactDerivedEvents(trans);
|
||||
insertMACTimeEvents(numFiles, fileIDs);
|
||||
insertArtifactDerivedEvents();
|
||||
}
|
||||
|
||||
//tags
|
||||
if (dbPopulationMode == DBPopulationMode.TAGS_ONLY) {
|
||||
trans = eventDB.beginTransaction();
|
||||
trans = eventManager.beginTransaction();
|
||||
logger.log(Level.INFO, "dropping old tags"); // NON-NLS
|
||||
eventDB.reInitializeTags();
|
||||
eventManager.reInitializeTags();
|
||||
}
|
||||
|
||||
logger.log(Level.INFO, "updating content tags"); // NON-NLS
|
||||
List<ContentTag> contentTags = tagsManager.getAllContentTags();
|
||||
int currentWorkTotal = contentTags.size();
|
||||
restartProgressHandle(Bundle.progressWindow_msg_refreshingFileTags(), "", 0D, currentWorkTotal, true);
|
||||
insertContentTags(currentWorkTotal, contentTags, trans);
|
||||
insertContentTags(currentWorkTotal, contentTags);
|
||||
|
||||
logger.log(Level.INFO, "updating artifact tags"); // NON-NLS
|
||||
List<BlackboardArtifactTag> artifactTags = tagsManager.getAllBlackboardArtifactTags();
|
||||
currentWorkTotal = artifactTags.size();
|
||||
restartProgressHandle(Bundle.progressWindow_msg_refreshingResultTags(), "", 0D, currentWorkTotal, true);
|
||||
insertArtifactTags(currentWorkTotal, artifactTags, trans);
|
||||
insertArtifactTags(currentWorkTotal, artifactTags);
|
||||
|
||||
logger.log(Level.INFO, "committing db"); // NON-NLS
|
||||
Platform.runLater(() -> cancellable.set(false));
|
||||
restartProgressHandle(Bundle.progressWindow_msg_commitingDb(), "", -1D, 1, false);
|
||||
eventDB.commitTransaction(trans);
|
||||
eventManager.commitTransaction(trans);
|
||||
|
||||
eventDB.analyze();
|
||||
eventManager.analyze();
|
||||
populateFilterData(skCase);
|
||||
invalidateCaches();
|
||||
|
||||
@@ -565,29 +580,29 @@ public class EventsRepository {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void insertArtifactTags(int currentWorkTotal, List<BlackboardArtifactTag> artifactTags, EventDB.EventTransaction trans) {
|
||||
private void insertArtifactTags(int currentWorkTotal, List<BlackboardArtifactTag> artifactTags) throws TskCoreException {
|
||||
for (int i = 0; i < currentWorkTotal; i++) {
|
||||
if (isCancelRequested()) {
|
||||
break;
|
||||
}
|
||||
updateProgress(i, currentWorkTotal);
|
||||
BlackboardArtifactTag artifactTag = artifactTags.get(i);
|
||||
eventDB.addTag(artifactTag.getContent().getId(), artifactTag.getArtifact().getArtifactID(), artifactTag, trans);
|
||||
eventManager.addTag(artifactTag.getContent().getId(), artifactTag.getArtifact().getArtifactID(), artifactTag);
|
||||
}
|
||||
}
|
||||
|
||||
private void insertContentTags(int currentWorkTotal, List<ContentTag> contentTags, EventDB.EventTransaction trans) {
|
||||
private void insertContentTags(int currentWorkTotal, List<ContentTag> contentTags) throws TskCoreException {
|
||||
for (int i = 0; i < currentWorkTotal; i++) {
|
||||
if (isCancelRequested()) {
|
||||
break;
|
||||
}
|
||||
updateProgress(i, currentWorkTotal);
|
||||
ContentTag contentTag = contentTags.get(i);
|
||||
eventDB.addTag(contentTag.getContent().getId(), null, contentTag, trans);
|
||||
eventManager.addTag(contentTag.getContent().getId(), null, contentTag);
|
||||
}
|
||||
}
|
||||
|
||||
private void insertArtifactDerivedEvents(EventDB.EventTransaction trans) {
|
||||
private void insertArtifactDerivedEvents() {
|
||||
//insert artifact based events
|
||||
//TODO: use (not-yet existing api) to grab all artifacts with timestamps, rather than the hardcoded lists in EventType -jm
|
||||
for (EventType type : RootEventType.allTypes) {
|
||||
@@ -596,13 +611,13 @@ public class EventsRepository {
|
||||
}
|
||||
//skip file_system events, they are already handled above.
|
||||
if (type instanceof ArtifactEventType) {
|
||||
populateEventType((ArtifactEventType) type, trans);
|
||||
populateEventType((ArtifactEventType) type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NbBundle.Messages("progressWindow.msg.populateMacEventsFiles=Populating MAC time events for files")
|
||||
private void insertMACTimeEvents(final int numFiles, List<Long> fileIDs, EventDB.EventTransaction trans) {
|
||||
private void insertMACTimeEvents(final int numFiles, List<Long> fileIDs) {
|
||||
restartProgressHandle(Bundle.progressWindow_msg_populateMacEventsFiles(), "", 0D, numFiles, true);
|
||||
for (int i = 0; i < numFiles; i++) {
|
||||
if (isCancelRequested()) {
|
||||
@@ -615,7 +630,7 @@ public class EventsRepository {
|
||||
if (isNull(f)) {
|
||||
logger.log(Level.WARNING, "Failed to get data for file : {0}", fID); // NON-NLS
|
||||
} else {
|
||||
insertEventsForFile(f, trans);
|
||||
insertEventsForFile(f);
|
||||
updateProgress(i, numFiles);
|
||||
updateMessage(f.getName());
|
||||
}
|
||||
@@ -625,7 +640,7 @@ public class EventsRepository {
|
||||
}
|
||||
}
|
||||
|
||||
private void insertEventsForFile(AbstractFile f, EventDB.EventTransaction trans) throws TskCoreException {
|
||||
private void insertEventsForFile(AbstractFile f) throws TskCoreException {
|
||||
//gather time stamps into map
|
||||
EnumMap<FileSystemTypes, Long> timeMap = new EnumMap<>(FileSystemTypes.class);
|
||||
timeMap.put(FileSystemTypes.FILE_CREATED, f.getCrtime());
|
||||
@@ -657,9 +672,9 @@ public class EventsRepository {
|
||||
for (Map.Entry<FileSystemTypes, Long> timeEntry : timeMap.entrySet()) {
|
||||
if (timeEntry.getValue() > 0) {
|
||||
// if the time is legitimate ( greater than zero ) insert it
|
||||
eventDB.insertEvent(timeEntry.getValue(), timeEntry.getKey(),
|
||||
eventManager.insertEvent(timeEntry.getValue(), timeEntry.getKey(),
|
||||
datasourceID, f.getId(), null, uniquePath, medDesc,
|
||||
shortDesc, known, hashSets, tags, trans);
|
||||
shortDesc, known, hashSets, tags);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -685,10 +700,10 @@ public class EventsRepository {
|
||||
* populate all the events of one type
|
||||
*
|
||||
* @param type the type to populate
|
||||
* @param trans the db transaction to use
|
||||
* @param trans the db transaction to use
|
||||
*/
|
||||
@NbBundle.Messages({"# {0} - event type ", "progressWindow.populatingXevents=Populating {0} events"})
|
||||
private void populateEventType(final ArtifactEventType type, EventDB.EventTransaction trans) {
|
||||
private void populateEventType(final ArtifactEventType type) {
|
||||
try {
|
||||
//get all the blackboard artifacts corresponding to the given event sub_type
|
||||
final ArrayList<BlackboardArtifact> blackboardArtifacts = skCase.getBlackboardArtifacts(type.getArtifactTypeID());
|
||||
@@ -697,7 +712,7 @@ public class EventsRepository {
|
||||
for (int i = 0; i < numArtifacts; i++) {
|
||||
try {
|
||||
//for each artifact, extract the relevant information for the descriptions
|
||||
insertEventForArtifact(type, blackboardArtifacts.get(i), trans);
|
||||
insertEventForArtifact(type, blackboardArtifacts.get(i));
|
||||
updateProgress(i, numArtifacts);
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "There was a problem inserting event for artifact: " + blackboardArtifacts.get(i).getArtifactID(), ex); // NON-NLS
|
||||
@@ -708,7 +723,7 @@ public class EventsRepository {
|
||||
}
|
||||
}
|
||||
|
||||
private void insertEventForArtifact(final ArtifactEventType type, BlackboardArtifact bbart, EventDB.EventTransaction trans) throws TskCoreException {
|
||||
private void insertEventForArtifact(final ArtifactEventType type, BlackboardArtifact bbart) throws TskCoreException {
|
||||
ArtifactEventType.AttributeEventDescription eventDescription = ArtifactEventType.buildEventDescription(type, bbart);
|
||||
|
||||
// if the time is legitimate ( greater than zero ) insert it into the db
|
||||
@@ -722,7 +737,7 @@ public class EventsRepository {
|
||||
String fullDescription = eventDescription.getFullDescription();
|
||||
String medDescription = eventDescription.getMedDescription();
|
||||
String shortDescription = eventDescription.getShortDescription();
|
||||
eventDB.insertEvent(eventDescription.getTime(), type, datasourceID, objectID, artifactID, fullDescription, medDescription, shortDescription, null, hashSets, tags, trans);
|
||||
eventManager.insertEvent(eventDescription.getTime(), type, datasourceID, objectID, artifactID, fullDescription, medDescription, shortDescription, null, hashSets, tags);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,6 @@ import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent.DeletedContentTagInfo;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||
import org.sleuthkit.autopsy.timeline.db.EventsRepository;
|
||||
import org.sleuthkit.autopsy.timeline.events.DBUpdatedEvent;
|
||||
import org.sleuthkit.autopsy.timeline.events.RefreshRequestedEvent;
|
||||
import org.sleuthkit.autopsy.timeline.events.TagsAddedEvent;
|
||||
@@ -260,7 +259,7 @@ public final class FilteredEventsModel {
|
||||
return new RootFilter(new HideKnownFilter(), tagsFilter, hashHitsFilter, new TextFilter(), new TypeFilter(RootEventType.getInstance()), dataSourcesFilter, Collections.emptySet());
|
||||
}
|
||||
|
||||
public Interval getBoundingEventsInterval(DateTimeZone tz) {
|
||||
public Interval getBoundingEventsInterval(DateTimeZone tz) throws TskCoreException {
|
||||
return repo.getBoundingEventsInterval(zoomParametersProperty().get().getTimeRange(), zoomParametersProperty().get().getFilter(), tz);
|
||||
}
|
||||
|
||||
@@ -280,11 +279,11 @@ public final class FilteredEventsModel {
|
||||
*
|
||||
* @return a map from tagname displayname to count of applications
|
||||
*/
|
||||
public Map<String, Long> getTagCountsByTagName(Set<Long> eventIDsWithTags) {
|
||||
public Map<String, Long> getTagCountsByTagName(Set<Long> eventIDsWithTags) throws TskCoreException {
|
||||
return repo.getTagCountsByTagName(eventIDsWithTags);
|
||||
}
|
||||
|
||||
public List<Long> getEventIDs(Interval timeRange, Filter filter) {
|
||||
public List<Long> getEventIDs(Interval timeRange, Filter filter) throws TskCoreException {
|
||||
final Interval overlap;
|
||||
final RootFilter intersect;
|
||||
synchronized (this) {
|
||||
@@ -303,7 +302,7 @@ public final class FilteredEventsModel {
|
||||
*
|
||||
* @return A List of combined events, sorted by timestamp.
|
||||
*/
|
||||
public List<CombinedEvent> getCombinedEvents() {
|
||||
public List<CombinedEvent> getCombinedEvents() throws TskCoreException {
|
||||
return repo.getCombinedEvents(requestedTimeRange.get(), requestedFilter.get());
|
||||
}
|
||||
|
||||
@@ -339,7 +338,7 @@ public final class FilteredEventsModel {
|
||||
/**
|
||||
* @return the smallest interval spanning all the given events
|
||||
*/
|
||||
public Interval getSpanningInterval(Collection<Long> eventIDs) {
|
||||
public Interval getSpanningInterval(Collection<Long> eventIDs) throws TskCoreException {
|
||||
return repo.getSpanningInterval(eventIDs);
|
||||
}
|
||||
|
||||
@@ -391,17 +390,17 @@ public final class FilteredEventsModel {
|
||||
return repo.getEventStripes(params);
|
||||
}
|
||||
|
||||
synchronized public boolean handleContentTagAdded(ContentTagAddedEvent evt) {
|
||||
synchronized public boolean handleContentTagAdded(ContentTagAddedEvent evt) throws TskCoreException {
|
||||
ContentTag contentTag = evt.getAddedTag();
|
||||
Content content = contentTag.getContent();
|
||||
Set<Long> updatedEventIDs = repo.addTag(content.getId(), null, contentTag, null);
|
||||
Set<Long> updatedEventIDs = repo.addTag(content.getId(), null, contentTag);
|
||||
return postTagsAdded(updatedEventIDs);
|
||||
}
|
||||
|
||||
synchronized public boolean handleArtifactTagAdded(BlackBoardArtifactTagAddedEvent evt) {
|
||||
synchronized public boolean handleArtifactTagAdded(BlackBoardArtifactTagAddedEvent evt) throws TskCoreException {
|
||||
BlackboardArtifactTag artifactTag = evt.getAddedTag();
|
||||
BlackboardArtifact artifact = artifactTag.getArtifact();
|
||||
Set<Long> updatedEventIDs = repo.addTag(artifact.getObjectID(), artifact.getArtifactID(), artifactTag, null);
|
||||
Set<Long> updatedEventIDs = repo.addTag(artifact.getObjectID(), artifact.getArtifactID(), artifactTag);
|
||||
return postTagsAdded(updatedEventIDs);
|
||||
}
|
||||
|
||||
@@ -446,7 +445,7 @@ public final class FilteredEventsModel {
|
||||
* @return A List of event IDs for the events that are derived from the
|
||||
* given file.
|
||||
*/
|
||||
public List<Long> getEventIDsForFile(AbstractFile file, boolean includeDerivedArtifacts) {
|
||||
public List<Long> getEventIDsForFile(AbstractFile file, boolean includeDerivedArtifacts) throws TskCoreException {
|
||||
return repo.getEventIDsForFile(file, includeDerivedArtifacts);
|
||||
}
|
||||
|
||||
@@ -459,7 +458,7 @@ public final class FilteredEventsModel {
|
||||
* @return A List of event IDs for the events that are derived from the
|
||||
* given artifact.
|
||||
*/
|
||||
public List<Long> getEventIDsForArtifact(BlackboardArtifact artifact) {
|
||||
public List<Long> getEventIDsForArtifact(BlackboardArtifact artifact) throws TskCoreException {
|
||||
return repo.getEventIDsForArtifact(artifact);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.timeline.db;
|
||||
package org.sleuthkit.autopsy.timeline.datamodel;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -1,22 +0,0 @@
|
||||
BaseTypes.fileSystem.name=\u30D5\u30A1\u30A4\u30EB\u30B7\u30B9\u30C6\u30E0
|
||||
BaseTypes.miscTypes.name=\u305D\u306E\u4ED6\u30BF\u30A4\u30D7
|
||||
BaseTypes.webActivity.name=\u30A6\u30A7\u30D6\u30A2\u30AF\u30C6\u30A3\u30D3\u30C6\u30A3
|
||||
FileSystemTypes.fileAccessed.name=\u30A2\u30AF\u30BB\u30B9\u3055\u308C\u305F\u30D5\u30A1\u30A4\u30EB
|
||||
FileSystemTypes.fileChanged.name=\u5909\u66F4\u3055\u308C\u305F\u30D5\u30A1\u30A4\u30EB
|
||||
FileSystemTypes.fileCreated.name=\u4F5C\u6210\u3055\u308C\u305F\u30D5\u30A1\u30A4\u30EB
|
||||
FileSystemTypes.fileModified.name=\u4FEE\u6B63\u3055\u308C\u305F\u30D5\u30A1\u30A4\u30EB
|
||||
MiscTypes.Calls.name=\u30B3\u30FC\u30EB
|
||||
MiscTypes.devicesAttached.name=\u63A5\u7D9A\u3055\u308C\u3066\u3044\u308B\u6A5F\u5668
|
||||
MiscTypes.Email.name=Email
|
||||
MiscTypes.exif.name=Exif
|
||||
MiscTypes.GPSRoutes.name=GPS\u30EB\u30FC\u30C8
|
||||
MiscTypes.GPSTrackpoint.name=\u4F4D\u7F6E\u60C5\u5831\u5C65\u6B74
|
||||
MiscTypes.installedPrograms.name=\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3055\u308C\u3066\u3044\u308B\u30D7\u30ED\u30B0\u30E9\u30E0
|
||||
MiscTypes.message.name=\u30E1\u30C3\u30BB\u30FC\u30B8
|
||||
MiscTypes.recentDocuments.name=\u6700\u8FD1\u306E\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8
|
||||
RootEventType.eventTypes.name=\u30A4\u30D9\u30F3\u30C8\u30BF\u30A4\u30D7
|
||||
WebTypes.webBookmarks.name=\u30A6\u30A7\u30D6\u30D6\u30C3\u30AF\u30DE\u30FC\u30AF
|
||||
WebTypes.webCookies.name=\u30A6\u30A7\u30D6\u30AF\u30C3\u30AD\u30FC
|
||||
WebTypes.webDownloads.name=\u30A6\u30A7\u30D6\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9
|
||||
WebTypes.webHistory.name=\u30A6\u30A7\u30D6\u5C65\u6B74
|
||||
WebTypes.webSearch.name=\u30A6\u30A7\u30D6\u691C\u7D22
|
||||
@@ -1,7 +0,0 @@
|
||||
msgdlg.problem.text=\u30BF\u30A4\u30E0\u30E9\u30A4\u30F3\u306B\u5165\u529B\u3059\u308B\u969B\u306B\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002\u5168\u3066\u306E\u30A4\u30D9\u30F3\u30C8\u304C\u5B58\u5728\u3057\u306A\u3044\u304B\u6B63\u78BA\u3067\u306F\u306A\u3044\u304B\u3082\u3057\u308C\u307E\u305B\u3093\u3002
|
||||
progressWindow.msg.commitingDb=\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306B\u30A4\u30D9\u30F3\u30C8\u3092\u30B3\u30DF\u30C3\u30C8\u3057\u3066\u3044\u307E\u3059\u3002
|
||||
progressWindow.msg.gatheringData=\u30A4\u30D9\u30F3\u30C8\u30C7\u30FC\u30BF\u3092\u53CE\u96C6\u4E2D
|
||||
progressWindow.msg.populateMacEventsFiles=\u30D5\u30A1\u30A4\u30EB\u306EMAC\u30BF\u30A4\u30E0\u3092\u5165\u529B\u4E2D
|
||||
progressWindow.msg.refreshingFileTags=\u30D5\u30A1\u30A4\u30EB\u30BF\u30B0\u3092\u30EA\u30D5\u30EC\u30C3\u30B7\u30E5\u4E2D
|
||||
progressWindow.msg.refreshingResultTags=\u7D50\u679C\u30BF\u30B0\u3092\u30EA\u30D5\u30EC\u30C3\u30B7\u30E5\u4E2D
|
||||
progressWindow.populatingXevents={0}\u30A4\u30D9\u30F3\u30C8\u3092\u5165\u529B\u4E2D
|
||||
@@ -23,6 +23,7 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.InvalidationListener;
|
||||
@@ -48,6 +49,7 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.controlsfx.control.action.Action;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Interval;
|
||||
import org.openide.util.Exceptions;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||
@@ -57,6 +59,7 @@ import org.sleuthkit.autopsy.timeline.ViewMode;
|
||||
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
||||
import org.sleuthkit.autopsy.timeline.ui.AbstractTimelineChart;
|
||||
import org.sleuthkit.autopsy.timeline.utils.MappedList;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.timeline.DescriptionLoD;
|
||||
import org.sleuthkit.datamodel.timeline.EventStripe;
|
||||
import org.sleuthkit.datamodel.timeline.TimeLineEvent;
|
||||
@@ -78,7 +81,7 @@ import org.sleuthkit.datamodel.timeline.ZoomParams;
|
||||
*/
|
||||
public class DetailViewPane extends AbstractTimelineChart<DateTime, EventStripe, EventNodeBase<?>, DetailsChart> {
|
||||
|
||||
private final static Logger LOGGER = Logger.getLogger(DetailViewPane.class.getName());
|
||||
private final static Logger logger = Logger.getLogger(DetailViewPane.class.getName());
|
||||
|
||||
private final DateAxis detailsChartDateAxis = new DateAxis();
|
||||
private final DateAxis pinnedDateAxis = new DateAxis();
|
||||
@@ -101,7 +104,7 @@ public class DetailViewPane extends AbstractTimelineChart<DateTime, EventStripe,
|
||||
/**
|
||||
* Constructor for a DetailViewPane
|
||||
*
|
||||
* @param controller the Controller to use
|
||||
* @param controller the Controller to use
|
||||
*/
|
||||
public DetailViewPane(TimeLineController controller) {
|
||||
super(controller);
|
||||
@@ -119,10 +122,15 @@ public class DetailViewPane extends AbstractTimelineChart<DateTime, EventStripe,
|
||||
//update selected nodes highlight
|
||||
getChart().setHighlightPredicate(getSelectedNodes()::contains);
|
||||
|
||||
//update controllers list of selected event ids when view's selection changes.
|
||||
getController().selectEventIDs(getSelectedNodes().stream()
|
||||
.flatMap(detailNode -> detailNode.getEventIDs().stream())
|
||||
.collect(Collectors.toList()));
|
||||
try {
|
||||
//update controllers list of selected event ids when view's selection changes.
|
||||
getController().selectEventIDs(getSelectedNodes().stream()
|
||||
.flatMap(detailNode -> detailNode.getEventIDs().stream())
|
||||
.collect(Collectors.toList()));
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error selecting nodes.", ex);
|
||||
new Alert(Alert.AlertType.ERROR, "Error selecting nodes").showAndWait();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -147,7 +155,7 @@ public class DetailViewPane extends AbstractTimelineChart<DateTime, EventStripe,
|
||||
*
|
||||
*
|
||||
* @param highlightedEvents the ObservableList of events that should be
|
||||
* highlighted in this view.
|
||||
* highlighted in this view.
|
||||
*/
|
||||
public void setHighLightedEvents(ObservableList<TimeLineEvent> highlightedEvents) {
|
||||
highlightedEvents.addListener((Observable observable) -> {
|
||||
@@ -155,16 +163,16 @@ public class DetailViewPane extends AbstractTimelineChart<DateTime, EventStripe,
|
||||
* build a predicate that matches events with the same description
|
||||
* as any of the events in highlightedEvents or which are selected
|
||||
*/
|
||||
Predicate<EventNodeBase<?>> highlightPredicate =
|
||||
highlightedEvents.stream() // => events
|
||||
.map(TimeLineEvent::getDescription)// => event descriptions
|
||||
.map(new Function<String, Predicate<EventNodeBase<?>>>() {
|
||||
@Override
|
||||
public Predicate<EventNodeBase<?>> apply(String description) {
|
||||
return eventNode -> StringUtils.equalsIgnoreCase(eventNode.getDescription(), description);
|
||||
}
|
||||
})// => predicates that match strings agains the descriptions of the events in highlightedEvents
|
||||
.reduce(getSelectedNodes()::contains, Predicate::or); // => predicate that matches an of the descriptions or selected nodes
|
||||
Predicate<EventNodeBase<?>> highlightPredicate
|
||||
= highlightedEvents.stream() // => events
|
||||
.map(TimeLineEvent::getDescription)// => event descriptions
|
||||
.map(new Function<String, Predicate<EventNodeBase<?>>>() {
|
||||
@Override
|
||||
public Predicate<EventNodeBase<?>> apply(String description) {
|
||||
return eventNode -> StringUtils.equalsIgnoreCase(eventNode.getDescription(), description);
|
||||
}
|
||||
})// => predicates that match strings agains the descriptions of the events in highlightedEvents
|
||||
.reduce(getSelectedNodes()::contains, Predicate::or); // => predicate that matches an of the descriptions or selected nodes
|
||||
getChart().setHighlightPredicate(highlightPredicate); //use this predicate to highlight nodes
|
||||
});
|
||||
}
|
||||
@@ -177,7 +185,7 @@ public class DetailViewPane extends AbstractTimelineChart<DateTime, EventStripe,
|
||||
/**
|
||||
* Get a new Action that will unhide events with the given description.
|
||||
*
|
||||
* @param description the description to unhide
|
||||
* @param description the description to unhide
|
||||
* @param descriptionLoD the description level of detail to match
|
||||
*
|
||||
* @return a new Action that will unhide events with the given description.
|
||||
@@ -189,7 +197,7 @@ public class DetailViewPane extends AbstractTimelineChart<DateTime, EventStripe,
|
||||
/**
|
||||
* Get a new Action that will hide events with the given description.
|
||||
*
|
||||
* @param description the description to hide
|
||||
* @param description the description to hide
|
||||
* @param descriptionLoD the description level of detail to match
|
||||
*
|
||||
* @return a new Action that will hide events with the given description.
|
||||
|
||||
@@ -52,6 +52,7 @@ import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.ContextMenu;
|
||||
@@ -76,6 +77,7 @@ import javax.swing.JMenuItem;
|
||||
import org.controlsfx.control.Notifications;
|
||||
import org.controlsfx.control.action.ActionUtils;
|
||||
import org.openide.awt.Actions;
|
||||
import org.openide.util.Exceptions;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.actions.Presenter;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
@@ -185,10 +187,15 @@ class ListTimeline extends BorderPane {
|
||||
private final ListChangeListener<CombinedEvent> selectedEventListener = new ListChangeListener<CombinedEvent>() {
|
||||
@Override
|
||||
public void onChanged(ListChangeListener.Change<? extends CombinedEvent> c) {
|
||||
controller.selectEventIDs(table.getSelectionModel().getSelectedItems().stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(CombinedEvent::getRepresentativeEventID)
|
||||
.collect(Collectors.toSet()));
|
||||
try {
|
||||
controller.selectEventIDs(table.getSelectionModel().getSelectedItems().stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(CombinedEvent::getRepresentativeEventID)
|
||||
.collect(Collectors.toSet()));
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error selecting events.", ex);
|
||||
new Alert(Alert.AlertType.ERROR, "error selecting events.").showAndWait();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -236,19 +243,19 @@ class ListTimeline extends BorderPane {
|
||||
|
||||
//// set up cell and cell-value factories for columns
|
||||
dateTimeColumn.setCellValueFactory(CELL_VALUE_FACTORY);
|
||||
dateTimeColumn.setCellFactory(col -> new TextEventTableCell(singleEvent ->
|
||||
TimeLineController.getZonedFormatter().print(singleEvent.getStartMillis())));
|
||||
dateTimeColumn.setCellFactory(col -> new TextEventTableCell(singleEvent
|
||||
-> TimeLineController.getZonedFormatter().print(singleEvent.getStartMillis())));
|
||||
|
||||
descriptionColumn.setCellValueFactory(CELL_VALUE_FACTORY);
|
||||
descriptionColumn.setCellFactory(col -> new TextEventTableCell(singleEvent ->
|
||||
singleEvent.getDescription(DescriptionLoD.FULL)));
|
||||
descriptionColumn.setCellFactory(col -> new TextEventTableCell(singleEvent
|
||||
-> singleEvent.getDescription(DescriptionLoD.FULL)));
|
||||
|
||||
typeColumn.setCellValueFactory(CELL_VALUE_FACTORY);
|
||||
typeColumn.setCellFactory(col -> new EventTypeCell());
|
||||
|
||||
knownColumn.setCellValueFactory(CELL_VALUE_FACTORY);
|
||||
knownColumn.setCellFactory(col -> new TextEventTableCell(singleEvent ->
|
||||
singleEvent.getKnown().getName()));
|
||||
knownColumn.setCellFactory(col -> new TextEventTableCell(singleEvent
|
||||
-> singleEvent.getKnown().getName()));
|
||||
|
||||
taggedColumn.setCellValueFactory(CELL_VALUE_FACTORY);
|
||||
taggedColumn.setCellFactory(col -> new TaggedCell());
|
||||
@@ -331,7 +338,7 @@ class ListTimeline extends BorderPane {
|
||||
* ListViewPane will provide to its host ViewFrame.
|
||||
*
|
||||
* @return A List of time navigation controls in the from of JavaFX scene
|
||||
* graph Nodes.
|
||||
* graph Nodes.
|
||||
*/
|
||||
List<Node> getTimeNavigationControls() {
|
||||
return Collections.singletonList(navControls);
|
||||
@@ -342,7 +349,7 @@ class ListTimeline extends BorderPane {
|
||||
* focus it.
|
||||
*
|
||||
* @param index The index of the item that should be scrolled in to view and
|
||||
* focused.
|
||||
* focused.
|
||||
*/
|
||||
private void scrollToAndFocus(Integer index) {
|
||||
table.requestFocus();
|
||||
@@ -558,7 +565,7 @@ class ListTimeline extends BorderPane {
|
||||
* Constructor
|
||||
*
|
||||
* @param textSupplier Function that takes a SingleEvent and produces a
|
||||
* String to show in this TableCell.
|
||||
* String to show in this TableCell.
|
||||
*/
|
||||
TextEventTableCell(Function<SingleEvent, String> textSupplier) {
|
||||
this.textSupplier = textSupplier;
|
||||
@@ -730,14 +737,14 @@ class ListTimeline extends BorderPane {
|
||||
ChronoField selectedChronoField = scrollInrementComboBox.getSelectionModel().getSelectedItem();
|
||||
ZoneId timeZoneID = TimeLineController.getTimeZoneID();
|
||||
TemporalUnit selectedUnit = selectedChronoField.getBaseUnit();
|
||||
|
||||
|
||||
int focusedIndex = table.getFocusModel().getFocusedIndex();
|
||||
CombinedEvent focusedItem = table.getFocusModel().getFocusedItem();
|
||||
if (-1 == focusedIndex || null == focusedItem) {
|
||||
focusedItem = visibleEvents.first();
|
||||
focusedIndex = table.getItems().indexOf(focusedItem);
|
||||
}
|
||||
|
||||
|
||||
ZonedDateTime focusedDateTime = Instant.ofEpochMilli(focusedItem.getStartMillis()).atZone(timeZoneID);
|
||||
ZonedDateTime nextDateTime = focusedDateTime.plus(1, selectedUnit);//
|
||||
for (ChronoField field : SCROLL_BY_UNITS) {
|
||||
@@ -746,7 +753,7 @@ class ListTimeline extends BorderPane {
|
||||
}
|
||||
}
|
||||
long nextMillis = nextDateTime.toInstant().toEpochMilli();
|
||||
|
||||
|
||||
int nextIndex = table.getItems().size() - 1;
|
||||
for (int i = focusedIndex; i < table.getItems().size(); i++) {
|
||||
if (table.getItems().get(i).getStartMillis() >= nextMillis) {
|
||||
@@ -774,24 +781,24 @@ class ListTimeline extends BorderPane {
|
||||
ZoneId timeZoneID = TimeLineController.getTimeZoneID();
|
||||
ChronoField selectedChronoField = scrollInrementComboBox.getSelectionModel().getSelectedItem();
|
||||
TemporalUnit selectedUnit = selectedChronoField.getBaseUnit();
|
||||
|
||||
|
||||
int focusedIndex = table.getFocusModel().getFocusedIndex();
|
||||
CombinedEvent focusedItem = table.getFocusModel().getFocusedItem();
|
||||
if (-1 == focusedIndex || null == focusedItem) {
|
||||
focusedItem = visibleEvents.last();
|
||||
focusedIndex = table.getItems().indexOf(focusedItem);
|
||||
}
|
||||
|
||||
|
||||
ZonedDateTime focusedDateTime = Instant.ofEpochMilli(focusedItem.getStartMillis()).atZone(timeZoneID);
|
||||
ZonedDateTime previousDateTime = focusedDateTime.minus(1, selectedUnit);//
|
||||
|
||||
|
||||
for (ChronoField field : SCROLL_BY_UNITS) {
|
||||
if (field.getBaseUnit().getDuration().compareTo(selectedUnit.getDuration()) < 0) {
|
||||
previousDateTime = previousDateTime.with(field, field.rangeRefinedBy(previousDateTime).getMaximum());//
|
||||
}
|
||||
}
|
||||
long previousMillis = previousDateTime.toInstant().toEpochMilli();
|
||||
|
||||
|
||||
int previousIndex = 0;
|
||||
for (int i = focusedIndex; i > 0; i--) {
|
||||
if (table.getItems().get(i).getStartMillis() <= previousMillis) {
|
||||
@@ -799,7 +806,7 @@ class ListTimeline extends BorderPane {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
scrollToAndFocus(previousIndex);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user