mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-13 00:16:16 +00:00
timeline time range fix
This commit is contained in:
parent
27c6283959
commit
e015b93eb5
@ -31,6 +31,7 @@ import org.apache.commons.collections.CollectionUtils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Interval;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.util.actions.CallableSystemAction;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineDataSourceUtils;
|
||||
@ -64,7 +65,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
"TimlinePanel_last30DaysChart_fileEvts_title=File Events",
|
||||
"TimlinePanel_last30DaysChart_artifactEvts_title=Artifact Events",})
|
||||
public class TimelinePanel extends BaseDataSourceSummaryPanel {
|
||||
|
||||
|
||||
private static final Logger logger = Logger.getLogger(TimelinePanel.class.getName());
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final DateFormat EARLIEST_LATEST_FORMAT = getUtcFormat("MMM d, yyyy");
|
||||
@ -86,7 +87,6 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel {
|
||||
private final LoadableLabel earliestLabel = new LoadableLabel(Bundle.TimelinePanel_earliestLabel_title());
|
||||
private final LoadableLabel latestLabel = new LoadableLabel(Bundle.TimelinePanel_latestLabel_title());
|
||||
private final BarChartPanel last30DaysChart = new BarChartPanel(Bundle.TimlinePanel_last30DaysChart_title(), "", "");
|
||||
private final OpenTimelineAction openTimelineAction = new OpenTimelineAction();
|
||||
private final TimelineDataSourceUtils timelineUtils = TimelineDataSourceUtils.getInstance();
|
||||
|
||||
// all loadable components on this tab
|
||||
@ -94,7 +94,7 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel {
|
||||
|
||||
// actions to load data for this tab
|
||||
private final List<DataFetchComponents<DataSource, ?>> dataFetchComponents;
|
||||
|
||||
|
||||
public TimelinePanel() {
|
||||
this(new TimelineSummary());
|
||||
}
|
||||
@ -109,7 +109,7 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel {
|
||||
(dataSource) -> timelineData.getData(dataSource, MOST_RECENT_DAYS_COUNT),
|
||||
(result) -> handleResult(result))
|
||||
);
|
||||
|
||||
|
||||
initComponents();
|
||||
}
|
||||
|
||||
@ -125,7 +125,7 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel {
|
||||
private static String formatDate(Date date, DateFormat formatter) {
|
||||
return date == null ? null : formatter.format(date);
|
||||
}
|
||||
|
||||
|
||||
private static final Color FILE_EVT_COLOR = new Color(228, 22, 28);
|
||||
private static final Color ARTIFACT_EVT_COLOR = new Color(21, 227, 100);
|
||||
|
||||
@ -145,25 +145,25 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel {
|
||||
// Create a bar chart item for each recent days activity item
|
||||
List<BarChartItem> fileEvtCounts = new ArrayList<>();
|
||||
List<BarChartItem> artifactEvtCounts = new ArrayList<>();
|
||||
|
||||
|
||||
for (int i = 0; i < recentDaysActivity.size(); i++) {
|
||||
DailyActivityAmount curItem = recentDaysActivity.get(i);
|
||||
|
||||
|
||||
long fileAmt = curItem.getFileActivityCount();
|
||||
long artifactAmt = curItem.getArtifactActivityCount() * 100;
|
||||
String formattedDate = (i == 0 || i == recentDaysActivity.size() - 1)
|
||||
? formatDate(curItem.getDay(), CHART_FORMAT) : "";
|
||||
|
||||
|
||||
OrderedKey thisKey = new OrderedKey(formattedDate, i);
|
||||
fileEvtCounts.add(new BarChartItem(thisKey, fileAmt));
|
||||
artifactEvtCounts.add(new BarChartItem(thisKey, artifactAmt));
|
||||
}
|
||||
|
||||
|
||||
return Arrays.asList(
|
||||
new BarChartSeries(Bundle.TimlinePanel_last30DaysChart_fileEvts_title(), FILE_EVT_COLOR, fileEvtCounts),
|
||||
new BarChartSeries(Bundle.TimlinePanel_last30DaysChart_artifactEvts_title(), ARTIFACT_EVT_COLOR, artifactEvtCounts));
|
||||
}
|
||||
|
||||
|
||||
private final Object timelineBtnLock = new Object();
|
||||
private TimelineSummaryData curTimelineData = null;
|
||||
|
||||
@ -179,11 +179,11 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel {
|
||||
earliestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> formatDate(r.getMinDate(), EARLIEST_LATEST_FORMAT)));
|
||||
latestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> formatDate(r.getMaxDate(), EARLIEST_LATEST_FORMAT)));
|
||||
last30DaysChart.showDataFetchResult(DataFetchResult.getSubResult(result, r -> parseChartData(r.getMostRecentDaysActivity())));
|
||||
|
||||
|
||||
if (result != null
|
||||
&& result.getResultType() == DataFetchResult.ResultType.SUCCESS
|
||||
&& result.getData() != null) {
|
||||
|
||||
|
||||
synchronized (this.timelineBtnLock) {
|
||||
this.curTimelineData = result.getData();
|
||||
this.viewInTimelineBtn.setEnabled(true);
|
||||
@ -208,7 +208,7 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel {
|
||||
if (curTimelineData == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
dataSource = curTimelineData.getDataSource();
|
||||
if (CollectionUtils.isNotEmpty(curTimelineData.getMostRecentDaysActivity())) {
|
||||
minDate = curTimelineData.getMostRecentDaysActivity().get(0).getDay();
|
||||
@ -219,38 +219,59 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
openFilteredChart(dataSource, minDate, maxDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Action that occurs when 'View in Timeline' button is pressed.
|
||||
*
|
||||
* @param dataSource The data source to filter to.
|
||||
* @param minDate The min date for the zoom of the window.
|
||||
* @param maxDate The max date for the zoom of the window.
|
||||
*/
|
||||
private void openFilteredChart(DataSource dataSource, Date minDate, Date maxDate) {
|
||||
OpenTimelineAction openTimelineAction = CallableSystemAction.get(OpenTimelineAction.class);
|
||||
if (openTimelineAction == null) {
|
||||
logger.log(Level.WARNING, "No OpenTimelineAction provided by CallableSystemAction; taking no redirect action.");
|
||||
}
|
||||
|
||||
// notify dialog (if in dialog) should close.
|
||||
TimelinePanel.this.notifyParentClose();
|
||||
|
||||
// open the timeline filtered to data source and zoomed in on interval
|
||||
openTimelineAction.performAction();
|
||||
|
||||
Interval timeSpan = null;
|
||||
|
||||
try {
|
||||
TimeLineController controller = TimeLineModule.getController();
|
||||
final TimeLineController controller = TimeLineModule.getController();
|
||||
|
||||
if (dataSource != null) {
|
||||
controller.pushFilters(timelineUtils.getDataSourceFilterState(dataSource));
|
||||
}
|
||||
|
||||
|
||||
if (minDate != null && maxDate != null) {
|
||||
Interval timeSpan = new Interval(new DateTime(minDate), new DateTime(maxDate));
|
||||
controller.pushTimeRange(timeSpan);
|
||||
timeSpan = new Interval(new DateTime(minDate), new DateTime(maxDate));
|
||||
}
|
||||
|
||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Unable to open Timeline view", ex);
|
||||
logger.log(Level.WARNING, "Unable to view time range in Timeline view", ex);
|
||||
}
|
||||
|
||||
try {
|
||||
openTimelineAction.showTimeline(timeSpan);
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "An unexpected exception occurred while opening the timeline.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void fetchInformation(DataSource dataSource) {
|
||||
fetchInformation(dataFetchComponents, dataSource);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onNewDataSource(DataSource dataSource) {
|
||||
onNewDataSource(dataFetchComponents, loadableComponents, dataSource);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
ingestRunningLabel.unregister();
|
||||
|
@ -24,6 +24,7 @@ import javafx.application.Platform;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JMenuItem;
|
||||
import org.joda.time.Interval;
|
||||
import org.openide.awt.ActionID;
|
||||
import org.openide.awt.ActionReference;
|
||||
import org.openide.awt.ActionReferences;
|
||||
@ -46,13 +47,10 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
* An Action that opens the Timeline window. Has methods to open the window in
|
||||
* various specific states (e.g., showing a specific artifact in the List View)
|
||||
*/
|
||||
|
||||
|
||||
@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.timeline.Timeline")
|
||||
@ActionRegistration(displayName = "#CTL_MakeTimeline", lazy = false)
|
||||
@ActionReferences(value = {
|
||||
@ActionReference(path = "Menu/Tools", position = 104)
|
||||
,
|
||||
@ActionReference(path = "Menu/Tools", position = 104),
|
||||
@ActionReference(path = "Toolbars/Case", position = 104)})
|
||||
public final class OpenTimelineAction extends CallableSystemAction {
|
||||
|
||||
@ -64,7 +62,6 @@ public final class OpenTimelineAction extends CallableSystemAction {
|
||||
private final JButton toolbarButton = new JButton(getName(),
|
||||
new ImageIcon(getClass().getResource("images/btn_icon_timeline_colorized_26.png"))); //NON-NLS
|
||||
|
||||
|
||||
public OpenTimelineAction() {
|
||||
toolbarButton.addActionListener(actionEvent -> performAction());
|
||||
menuItem = super.getMenuPresenter();
|
||||
@ -74,9 +71,10 @@ public final class OpenTimelineAction extends CallableSystemAction {
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
/**
|
||||
* We used to also check if Case.getCurrentOpenCase().hasData() was true. We
|
||||
* disabled that check because if it is executed while a data source is
|
||||
* being added, it blocks the edt. We still do that in ImageGallery.
|
||||
* We used to also check if Case.getCurrentOpenCase().hasData() was
|
||||
* true. We disabled that check because if it is executed while a data
|
||||
* source is being added, it blocks the edt. We still do that in
|
||||
* ImageGallery.
|
||||
*/
|
||||
return super.isEnabled() && Case.isCaseOpen() && Installer.isJavaFxInited();
|
||||
}
|
||||
@ -103,7 +101,7 @@ public final class OpenTimelineAction extends CallableSystemAction {
|
||||
@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) throws TskCoreException {
|
||||
synchronized private void showTimeline(AbstractFile file, BlackboardArtifact artifact, Interval timeSpan) throws TskCoreException {
|
||||
try {
|
||||
Case currentCase = Case.getCurrentCaseThrows();
|
||||
if (currentCase.hasData() == false) {
|
||||
@ -112,6 +110,15 @@ public final class OpenTimelineAction extends CallableSystemAction {
|
||||
return;
|
||||
}
|
||||
TimeLineController controller = TimeLineModule.getController();
|
||||
// if file or artifact not specified, specify the time range as either
|
||||
// a) full range if timeSpan is null or b) the timeSpan
|
||||
if (file == null && artifact == null) {
|
||||
if (timeSpan == null) {
|
||||
controller.showFullRange();
|
||||
} else {
|
||||
controller.pushTimeRange(timeSpan);
|
||||
}
|
||||
}
|
||||
controller.showTimeLine(file, artifact);
|
||||
} catch (NoCurrentCaseException e) {
|
||||
//there is no case... Do nothing.
|
||||
@ -123,7 +130,18 @@ public final class OpenTimelineAction extends CallableSystemAction {
|
||||
*/
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||
public void showTimeline() throws TskCoreException {
|
||||
showTimeline(null, null);
|
||||
showTimeline(null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open timeline with the given timeSpan time range.
|
||||
*
|
||||
* @param timeSpan The time range to display.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||
public void showTimeline(Interval timeSpan) throws TskCoreException {
|
||||
showTimeline(null, null, timeSpan);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -135,7 +153,7 @@ public final class OpenTimelineAction extends CallableSystemAction {
|
||||
*/
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||
public void showFileInTimeline(AbstractFile file) throws TskCoreException {
|
||||
showTimeline(file, null);
|
||||
showTimeline(file, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -146,7 +164,7 @@ public final class OpenTimelineAction extends CallableSystemAction {
|
||||
*/
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||
public void showArtifactInTimeline(BlackboardArtifact artifact) throws TskCoreException {
|
||||
showTimeline(null, artifact);
|
||||
showTimeline(null, artifact, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -62,7 +62,6 @@ import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import static org.sleuthkit.autopsy.casemodule.Case.Events.CURRENT_CASE;
|
||||
import static org.sleuthkit.autopsy.casemodule.Case.Events.DATA_SOURCE_ADDED;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent;
|
||||
@ -348,7 +347,7 @@ public class TimeLineController {
|
||||
/**
|
||||
* Show the entire range of the timeline.
|
||||
*/
|
||||
private boolean showFullRange() throws TskCoreException {
|
||||
boolean showFullRange() throws TskCoreException {
|
||||
synchronized (filteredEvents) {
|
||||
return pushTimeRange(filteredEvents.getSpanningInterval());
|
||||
}
|
||||
@ -359,7 +358,7 @@ 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) throws TskCoreException {
|
||||
@ -376,14 +375,13 @@ public class TimeLineController {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shuts down the task executor in charge of handling case events.
|
||||
*/
|
||||
void shutDownTimeLineListeners() {
|
||||
ThreadUtils.shutDownTaskExecutor(executor);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* "Shut down" Timeline. Close the timeline window.
|
||||
*/
|
||||
@ -394,15 +392,13 @@ public class TimeLineController {
|
||||
topComponent = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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)
|
||||
@ -421,9 +417,7 @@ public class TimeLineController {
|
||||
try {
|
||||
if (file == null && artifact == null) {
|
||||
SwingUtilities.invokeLater(TimeLineController.this::showWindow);
|
||||
this.showFullRange();
|
||||
} else {
|
||||
|
||||
//prompt user to pick specific event and time range
|
||||
ShowInTimelineDialog showInTimelineDilaog = (file == null)
|
||||
? new ShowInTimelineDialog(this, artifact)
|
||||
@ -453,7 +447,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) throws TskCoreException {
|
||||
synchronized (filteredEvents) {
|
||||
@ -496,8 +490,8 @@ public class TimeLineController {
|
||||
*/
|
||||
topComponent.requestActive();
|
||||
}
|
||||
|
||||
synchronized public TimeLineTopComponent getTopComponent(){
|
||||
|
||||
synchronized public TimeLineTopComponent getTopComponent() {
|
||||
return topComponent;
|
||||
}
|
||||
|
||||
@ -517,7 +511,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) throws TskCoreException {
|
||||
//clamp timerange to case
|
||||
@ -709,7 +703,7 @@ public class TimeLineController {
|
||||
* Register the given object to receive events.
|
||||
*
|
||||
* @param listener The object to register. Must implement public methods
|
||||
* annotated with Subscribe.
|
||||
* annotated with Subscribe.
|
||||
*/
|
||||
synchronized public void registerForEvents(Object listener) {
|
||||
eventbus.register(listener);
|
||||
|
Loading…
x
Reference in New Issue
Block a user