mirror of
https://github.com/elisspace/autopsy.git
synced 2026-09-06 02:24:30 +00:00
comments, cleanup, bundlization
This commit is contained in:
@@ -1,7 +1,20 @@
|
||||
/*
|
||||
* 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.
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2015 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;
|
||||
|
||||
@@ -27,24 +40,30 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||
|
||||
/**
|
||||
*
|
||||
* Manager for the various prompts Timeline shows the user related to rebuilding
|
||||
* the database.
|
||||
*/
|
||||
public class PromptDialogManager {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(PromptDialogManager.class.getName());
|
||||
|
||||
private static final ButtonType SHOW_TIMELINE = new ButtonType("Show Timeline", ButtonBar.ButtonData.OK_DONE);
|
||||
private static final ButtonType CONTINUE_NO_UPDATE = new ButtonType("Continue Without Updating", ButtonBar.ButtonData.CANCEL_CLOSE);
|
||||
private static final ButtonType UPDATE = new ButtonType("Update", ButtonBar.ButtonData.OK_DONE);
|
||||
@NbBundle.Messages("PrompDialogManager.buttonType.showTimeline=Show Timeline")
|
||||
private static final ButtonType SHOW_TIMELINE = new ButtonType(Bundle.PrompDialogManager_buttonType_showTimeline(), ButtonBar.ButtonData.OK_DONE);
|
||||
|
||||
@NbBundle.Messages("PrompDialogManager.buttonType.continueNoUpdate=Continue Without Updating")
|
||||
private static final ButtonType CONTINUE_NO_UPDATE = new ButtonType(Bundle.PrompDialogManager_buttonType_continueNoUpdate(), ButtonBar.ButtonData.CANCEL_CLOSE);
|
||||
|
||||
@NbBundle.Messages("PrompDialogManager.buttonType.update=Update")
|
||||
private static final ButtonType UPDATE = new ButtonType(Bundle.PrompDialogManager_buttonType_update(), ButtonBar.ButtonData.OK_DONE);
|
||||
|
||||
private static final Image LOGO;
|
||||
|
||||
static {
|
||||
Image x = null;
|
||||
try {
|
||||
x = new Image(new URL("nbresloc:/org/netbeans/core/startup/frame.gif").openStream());
|
||||
x = new Image(new URL("nbresloc:/org/netbeans/core/startup/frame.gif").openStream()); //NOI18N
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.WARNING, "Failed to load branded icon for progress dialog.", ex);
|
||||
LOGGER.log(Level.WARNING, "Failed to load branded icon for progress dialog.", ex); //NOI18N
|
||||
}
|
||||
LOGO = x;
|
||||
}
|
||||
@@ -65,26 +84,24 @@ public class PromptDialogManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||
@NbBundle.Messages({"PromptDialogManager.progressDialog.title=Populating Timeline Data"})
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||
public void showProgressDialog(CancellationProgressTask<?> task) {
|
||||
|
||||
currentDialog = new ProgressDialog(task);
|
||||
currentDialog.setTitle(Bundle.PromptDialogManager_progressDialog_title());
|
||||
currentDialog.headerTextProperty().bind(task.titleProperty());
|
||||
setDialogIcons(currentDialog);
|
||||
currentDialog.setTitle(Bundle.PromptDialogManager_progressDialog_title());
|
||||
|
||||
DialogPane dialogPane = currentDialog.getDialogPane();
|
||||
dialogPane.setPrefWidth(400);
|
||||
dialogPane.setPrefSize(400, 200); //override autosizing which fails for some reason
|
||||
|
||||
dialogPane.setPrefHeight(200);
|
||||
//co-ordinate task cancelation and dialog hiding.
|
||||
task.setOnCancelled(cancelled -> currentDialog.close());
|
||||
task.setOnSucceeded(succeeded -> currentDialog.close());
|
||||
|
||||
dialogPane.getButtonTypes().setAll(ButtonType.CANCEL);
|
||||
final Node cancelButton = dialogPane.lookupButton(ButtonType.CANCEL);
|
||||
cancelButton.disableProperty().bind(task.cancellableProperty().not());
|
||||
currentDialog.setOnCloseRequest(closeRequest -> {
|
||||
|
||||
if (task.isRunning()) {
|
||||
closeRequest.consume();
|
||||
}
|
||||
@@ -93,43 +110,49 @@ public class PromptDialogManager {
|
||||
}
|
||||
});
|
||||
|
||||
Stage stage = (Stage) dialogPane.getScene().getWindow();
|
||||
stage.getIcons().setAll(LOGO);
|
||||
currentDialog.show();
|
||||
}
|
||||
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||
static private void setDialogIcons(Dialog<?> dialog) {
|
||||
Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow();
|
||||
stage.getIcons().setAll(LOGO);
|
||||
}
|
||||
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||
static private void setDialogTitle(Dialog<?> dialog) {
|
||||
Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow();
|
||||
stage.setTitle(Bundle.Timeline_confirmation_dialogs_title());
|
||||
}
|
||||
|
||||
/**
|
||||
* prompt the user that ingest is running and the db may not end up
|
||||
* complete.
|
||||
*
|
||||
* @return true if they want to continue anyways
|
||||
*/
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||
@NbBundle.Messages({"PromptDialogManager.confirmDuringIngest.headerText=You are trying to generate a timeline before ingest has been completed."
|
||||
+ "\nThe timeline may be incomplete.",
|
||||
@NbBundle.Messages({"PromptDialogManager.confirmDuringIngest.headerText=You are trying to show a timeline before ingest has been completed.\nThe timeline may be incomplete.",
|
||||
"PromptDialogManager.confirmDuringIngest.contentText=Do you want to continue?"})
|
||||
synchronized boolean confirmDuringIngest() {
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||
boolean confirmDuringIngest() {
|
||||
currentDialog = new Alert(Alert.AlertType.CONFIRMATION, Bundle.PromptDialogManager_confirmDuringIngest_contentText(), SHOW_TIMELINE, ButtonType.CANCEL);
|
||||
currentDialog.initModality(Modality.APPLICATION_MODAL);
|
||||
currentDialog.setHeaderText(Bundle.PromptDialogManager_confirmDuringIngest_headerText());
|
||||
brandDialog();
|
||||
setDialogIcons(currentDialog);
|
||||
setDialogTitle(currentDialog);
|
||||
|
||||
return currentDialog.showAndWait().map(SHOW_TIMELINE::equals).orElse(false);
|
||||
}
|
||||
|
||||
private void brandDialog() {
|
||||
Stage stage = (Stage) currentDialog.getDialogPane().getScene().getWindow();
|
||||
stage.setTitle(Bundle.Timeline_confirmation_dialogs_title());
|
||||
stage.getIcons().setAll(LOGO);
|
||||
}
|
||||
|
||||
@NbBundle.Messages({"PromptDialogManager.rebuildPrompt.headerText=The Timeline database is incomplete and/or out of date."
|
||||
+ "\nSome events may be missing or inaccurate and some features may be unavailable.",
|
||||
@NbBundle.Messages({"PromptDialogManager.rebuildPrompt.headerText=The Timeline database is incomplete and/or out of date.\nSome events may be missing or inaccurate and some features may be unavailable.",
|
||||
"PromptDialogManager.rebuildPrompt.details=Details:"})
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||
boolean confirmRebuild(ArrayList<String> rebuildReasons) {
|
||||
currentDialog = new Alert(Alert.AlertType.CONFIRMATION, Bundle.TimeLinecontroller_updateNowQuestion(), UPDATE, CONTINUE_NO_UPDATE);
|
||||
currentDialog.initModality(Modality.APPLICATION_MODAL);
|
||||
currentDialog.setHeaderText(Bundle.PromptDialogManager_rebuildPrompt_headerText());
|
||||
brandDialog();
|
||||
setDialogIcons(currentDialog);
|
||||
setDialogTitle(currentDialog);
|
||||
|
||||
DialogPane dialogPane = currentDialog.getDialogPane();
|
||||
ListView<String> listView = new ListView<>(FXCollections.observableArrayList(rebuildReasons));
|
||||
|
||||
@@ -119,7 +119,7 @@ public class TimeLineController {
|
||||
}
|
||||
|
||||
public static DateTimeFormatter getZonedFormatter() {
|
||||
return DateTimeFormat.forPattern("YYYY-MM-dd HH:mm:ss").withZone(getJodaTimeZone()); // NON-NLS
|
||||
return DateTimeFormat.forPattern("YYYY-MM-dd HH:mm:ss").withZone(getJodaTimeZone()); // NON-NLS //NOI18N
|
||||
}
|
||||
|
||||
public static DateTimeZone getJodaTimeZone() {
|
||||
@@ -420,7 +420,7 @@ public class TimeLineController {
|
||||
}
|
||||
|
||||
} catch (HeadlessException | MissingResourceException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unexpected error when generating timeline, ", ex); // NON-NLS
|
||||
LOGGER.log(Level.SEVERE, "Unexpected error when generating timeline, ", ex); // NON-NLS //NOI18N
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -444,30 +444,34 @@ public class TimeLineController {
|
||||
}
|
||||
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.ANY)
|
||||
@NbBundle.Messages({"TimeLineController.errorTitle=Timeline error.",
|
||||
"TimeLineController.outOfDate.errorMessage=Error determing if the timeline is out of date. We will assume it should be updated. See the logs for more details.",
|
||||
"TimeLineController.rebuildReasons.outOfDateError=Could not determine if the timeline data is out of date.",
|
||||
"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 ArrayList<String> getRebuildReasons() {
|
||||
ArrayList<String> rebuildReasons = new ArrayList<>();
|
||||
//if ingest was running during last rebuild, prompt to rebuild
|
||||
if (eventsRepository.getWasIngestRunning()) {
|
||||
rebuildReasons.add("The Timeline events database was previously populated while ingest was running:"
|
||||
+ " Some events may be missing, incomplete, or inaccurate");
|
||||
rebuildReasons.add(Bundle.TimeLineController_rebuildReasons_ingestWasRunning());
|
||||
}
|
||||
final SleuthkitCase sleuthkitCase = autoCase.getSleuthkitCase();
|
||||
try {
|
||||
//if the last artifact and object ids don't match between skc and tldb, prompt to rebuild
|
||||
if (sleuthkitCase.getLastObjectId() != eventsRepository.getLastObjID()
|
||||
|| getCaseLastArtifactID(sleuthkitCase) != eventsRepository.getLastArtfactID()) {
|
||||
rebuildReasons.add("The event data is out of date: Not all events will be visible.");
|
||||
rebuildReasons.add(Bundle.TimeLineController_rebuildReasons_outOfDate());
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error determing last object id from sleutkit case. We will assume the timeline is out of date.", ex); // NON-NLS
|
||||
MessageNotifyUtil.Notify.error("Timeline error.",
|
||||
"Error determing if the timeline is out of date. We will assume it should be updated. See the logs for more details.");
|
||||
rebuildReasons.add("Could not determine if the timeline data is out of date.");
|
||||
LOGGER.log(Level.SEVERE, "Error determing last object id from sleutkit case. We will assume the timeline is out of date.", ex); // NON-NLS
|
||||
MessageNotifyUtil.Notify.error(Bundle.TimeLineController_errorTitle(),
|
||||
Bundle.TimeLineController_outOfDate_errorMessage());
|
||||
rebuildReasons.add(Bundle.TimeLineController_rebuildReasons_outOfDateError());
|
||||
}
|
||||
// if the TLDB schema has been upgraded since last time TL ran, prompt for rebuild
|
||||
if (eventsRepository.hasNewColumns() == false) {
|
||||
rebuildReasons.add("The Timeline events database was previously populated without incomplete information:"
|
||||
+ " Some features may be unavailable or non-functional unless you update the events database.");
|
||||
rebuildReasons.add(Bundle.TimeLineController_rebuildReasons_incompleteOldSchema());
|
||||
}
|
||||
return rebuildReasons;
|
||||
}
|
||||
@@ -475,14 +479,14 @@ public class TimeLineController {
|
||||
public static long getCaseLastArtifactID(final SleuthkitCase sleuthkitCase) {
|
||||
//TODO: push this into sleuthkitCase
|
||||
long caseLastArtfId = -1;
|
||||
String query = "select Max(artifact_id) as max_id from blackboard_artifacts"; // NON-NLS
|
||||
String query = "select Max(artifact_id) as max_id from blackboard_artifacts"; // NON-NLS //NOI18N
|
||||
try (CaseDbQuery dbQuery = sleuthkitCase.executeQuery(query)) {
|
||||
ResultSet resultSet = dbQuery.getResultSet();
|
||||
while (resultSet.next()) {
|
||||
caseLastArtfId = resultSet.getLong("max_id"); // NON-NLS
|
||||
caseLastArtfId = resultSet.getLong("max_id"); // NON-NLS //NOI18N
|
||||
}
|
||||
} catch (TskCoreException | SQLException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error getting last artifact id: ", ex); // NON-NLS
|
||||
LOGGER.log(Level.SEVERE, "Error getting last artifact id: ", ex); // NON-NLS //NOI18N
|
||||
}
|
||||
return caseLastArtfId;
|
||||
}
|
||||
@@ -523,7 +527,7 @@ public class TimeLineController {
|
||||
}
|
||||
|
||||
public void selectEventIDs(Collection<Long> events) {
|
||||
final LoggedTask<Interval> selectEventIDsTask = new LoggedTask<Interval>("Select Event IDs", true) { // NON-NLS
|
||||
final LoggedTask<Interval> selectEventIDsTask = new LoggedTask<Interval>("Select Event IDs", true) { // NON-NLS //NOI18N
|
||||
@Override
|
||||
protected Interval call() throws Exception {
|
||||
return filteredEvents.getSpanningInterval(events);
|
||||
@@ -538,12 +542,8 @@ public class TimeLineController {
|
||||
selectedEventIDs.setAll(events);
|
||||
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(FilteredEventsModel.class
|
||||
.getName()).log(Level.SEVERE, getTitle() + " interrupted unexpectedly", ex); // NON-NLS
|
||||
} catch (ExecutionException ex) {
|
||||
Logger.getLogger(FilteredEventsModel.class
|
||||
.getName()).log(Level.SEVERE, getTitle() + " unexpectedly threw " + ex.getCause(), ex); // NON-NLS
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
LOGGER.log(Level.SEVERE, getTitle() + " Unexpected error", ex); // NON-NLS //NOI18N
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -587,8 +587,7 @@ public class TimeLineController {
|
||||
}
|
||||
|
||||
@NbBundle.Messages({"# {0} - the number of events",
|
||||
"Timeline.pushDescrLOD.confdlg.msg=You are about to show details for {0} events."
|
||||
+ " This might be very slow or even crash Autopsy.\n\nDo you want to continue?",
|
||||
"Timeline.pushDescrLOD.confdlg.msg=You are about to show details for {0} events. This might be very slow or even crash Autopsy.\n\nDo you want to continue?",
|
||||
"Timeline.pushDescrLOD.confdlg.title=Change description level of detail?"})
|
||||
synchronized public boolean pushDescrLOD(DescriptionLoD newLOD) {
|
||||
Map<EventType, Long> eventCounts = filteredEvents.getEventCounts(filteredEvents.zoomParametersProperty().get().getTimeRange());
|
||||
@@ -655,7 +654,7 @@ public class TimeLineController {
|
||||
public void selectTimeAndType(Interval interval, EventType type) {
|
||||
final Interval timeRange = filteredEvents.getSpanningInterval().overlap(interval);
|
||||
|
||||
final LoggedTask<Collection<Long>> selectTimeAndTypeTask = new LoggedTask<Collection<Long>>("Select Time and Type", true) { // NON-NLS
|
||||
final LoggedTask<Collection<Long>> selectTimeAndTypeTask = new LoggedTask<Collection<Long>>("Select Time and Type", true) { // NON-NLS //NOI18N
|
||||
@Override
|
||||
protected Collection< Long> call() throws Exception {
|
||||
synchronized (TimeLineController.this) {
|
||||
@@ -672,12 +671,8 @@ public class TimeLineController {
|
||||
selectedEventIDs.setAll(get());
|
||||
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(FilteredEventsModel.class
|
||||
.getName()).log(Level.SEVERE, getTitle() + " interrupted unexpectedly", ex);// NON-NLS
|
||||
} catch (ExecutionException ex) {
|
||||
Logger.getLogger(FilteredEventsModel.class
|
||||
.getName()).log(Level.SEVERE, getTitle() + " unexpectedly threw " + ex.getCause(), ex);// NON-NLS
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
LOGGER.log(Level.SEVERE, getTitle() + " Unexpected error", ex); // NON-NLS //NOI18N
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -692,6 +687,7 @@ public class TimeLineController {
|
||||
* @param task
|
||||
*/
|
||||
synchronized public void monitorTask(final Task<?> task) {
|
||||
//TODO: refactor this to use JavaFX Service? -jm
|
||||
if (task != null) {
|
||||
Platform.runLater(() -> {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user