Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
TimelinePanel.java
Go to the documentation of this file.
1/*
2 * Autopsy Forensic Browser
3 *
4 * Copyright 2020-2021 Basis Technology Corp.
5 * Contact: carrier <at> sleuthkit <dot> org
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19package org.sleuthkit.autopsy.datasourcesummary.ui;
20
21import java.awt.Color;
22import java.text.DateFormat;
23import java.util.ArrayList;
24import java.util.Arrays;
25import java.util.Date;
26import java.util.List;
27import java.util.logging.Level;
28import org.apache.commons.collections.CollectionUtils;
29import org.joda.time.DateTime;
30import org.joda.time.Interval;
31import org.openide.util.NbBundle.Messages;
32import org.openide.util.actions.CallableSystemAction;
33import org.sleuthkit.autopsy.coreutils.Logger;
34import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineDataSourceUtils;
35import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary;
36import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.DailyActivityAmount;
37import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.TimelineSummaryData;
38import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel;
39import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries.OrderedKey;
40import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries.BarChartItem;
41import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
42import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
43import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents;
44import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher;
45import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries;
46import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel;
47import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent;
48import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableLabel;
49import org.sleuthkit.autopsy.timeline.OpenTimelineAction;
50import org.sleuthkit.autopsy.timeline.TimeLineController;
51import org.sleuthkit.autopsy.timeline.TimeLineModule;
52import org.sleuthkit.datamodel.DataSource;
53import org.sleuthkit.datamodel.TskCoreException;
54
59@Messages({
60 "TimelinePanel_earliestLabel_title=Earliest",
61 "TimelinePanel_latestLabel_title=Latest",
62 "TimlinePanel_last30DaysChart_title=Last 30 Days",
63 "TimlinePanel_last30DaysChart_fileEvts_title=File Events",
64 "TimlinePanel_last30DaysChart_artifactEvts_title=Result Events",})
65public class TimelinePanel extends BaseDataSourceSummaryPanel {
66
67 private static final Logger logger = Logger.getLogger(TimelinePanel.class.getName());
68 private static final long serialVersionUID = 1L;
69
70 private static final String EARLIEST_LATEST_FORMAT_STR = "MMM d, yyyy";
72 private static final DateFormat CHART_FORMAT = TimelineSummary.getUtcFormat("MMM d, yyyy");
73 private static final int MOST_RECENT_DAYS_COUNT = 30;
74
75 // components displayed in the tab
77 private final LoadableLabel earliestLabel = new LoadableLabel(Bundle.TimelinePanel_earliestLabel_title());
78 private final LoadableLabel latestLabel = new LoadableLabel(Bundle.TimelinePanel_latestLabel_title());
79 private final BarChartPanel last30DaysChart = new BarChartPanel(Bundle.TimlinePanel_last30DaysChart_title(), "", "");
81
82 // all loadable components on this tab
83 private final List<LoadableComponent<?>> loadableComponents = Arrays.asList(earliestLabel, latestLabel, last30DaysChart);
84
86
87 // actions to load data for this tab
88 private final List<DataFetchComponents<DataSource, ?>> dataFetchComponents;
89
90 public TimelinePanel() {
91 this(new TimelineSummaryGetter());
92 }
93
97 public TimelinePanel(TimelineSummaryGetter timelineData) {
98 super(timelineData);
99
100 dataFetcher = (dataSource) -> timelineData.getData(dataSource, MOST_RECENT_DAYS_COUNT);
101
102 // set up data acquisition methods
103 dataFetchComponents = Arrays.asList(
104 new DataFetchWorker.DataFetchComponents<>(dataFetcher, (result) -> handleResult(result)));
105
107 }
108
109 private static final Color FILE_EVT_COLOR = new Color(228, 22, 28);
110 private static final Color ARTIFACT_EVT_COLOR = new Color(21, 227, 100);
111
123 private List<BarChartSeries> parseChartData(List<DailyActivityAmount> recentDaysActivity, boolean showIntermediateDates) {
124 // if no data, return null indicating no result.
125 if (CollectionUtils.isEmpty(recentDaysActivity)) {
126 return null;
127 }
128
129 // Create a bar chart item for each recent days activity item
130 List<BarChartItem> fileEvtCounts = new ArrayList<>();
131 List<BarChartItem> artifactEvtCounts = new ArrayList<>();
132
133 for (int i = 0; i < recentDaysActivity.size(); i++) {
134 DailyActivityAmount curItem = recentDaysActivity.get(i);
135
136 long fileAmt = curItem.getFileActivityCount();
137 long artifactAmt = curItem.getArtifactActivityCount() * 100;
138 String formattedDate = (showIntermediateDates || i == 0 || i == recentDaysActivity.size() - 1)
140
141 OrderedKey thisKey = new OrderedKey(formattedDate, i);
142 fileEvtCounts.add(new BarChartItem(thisKey, fileAmt));
143 artifactEvtCounts.add(new BarChartItem(thisKey, artifactAmt));
144 }
145
146 return Arrays.asList(
147 new BarChartSeries(Bundle.TimlinePanel_last30DaysChart_fileEvts_title(), FILE_EVT_COLOR, fileEvtCounts),
148 new BarChartSeries(Bundle.TimlinePanel_last30DaysChart_artifactEvts_title(), ARTIFACT_EVT_COLOR, artifactEvtCounts));
149 }
150
151 private final Object timelineBtnLock = new Object();
153
163 earliestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> TimelineSummary.formatDate(r.getMinDate(), EARLIEST_LATEST_FORMAT)));
164 latestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> TimelineSummary.formatDate(r.getMaxDate(), EARLIEST_LATEST_FORMAT)));
165 last30DaysChart.showDataFetchResult(DataFetchResult.getSubResult(result, r -> parseChartData(r.getMostRecentDaysActivity(), false)));
166
167 if (result != null
169 && result.getData() != null) {
170
171 synchronized (this.timelineBtnLock) {
172 this.curTimelineData = result.getData();
173 this.viewInTimelineBtn.setEnabled(true);
174 }
175 } else {
176 synchronized (this.timelineBtnLock) {
177 this.viewInTimelineBtn.setEnabled(false);
178 }
179 }
180 }
181
185 private void openFilteredChart() {
186 DataSource dataSource = null;
187 Date minDate = null;
188 Date maxDate = null;
189
190 // get date from current timelineData if that data exists.
191 synchronized (this.timelineBtnLock) {
192 if (curTimelineData == null) {
193 return;
194 }
195
196 dataSource = curTimelineData.getDataSource();
197 if (CollectionUtils.isNotEmpty(curTimelineData.getMostRecentDaysActivity())) {
198 minDate = curTimelineData.getMostRecentDaysActivity().get(0).getDay();
199 maxDate = curTimelineData.getMostRecentDaysActivity().get(curTimelineData.getMostRecentDaysActivity().size() - 1).getDay();
200 // set outer bound to end of day instead of beginning
201 if (maxDate != null) {
202 maxDate = new Date(maxDate.getTime() + 1000 * 60 * 60 * 24);
203 }
204 }
205 }
206
207 openFilteredChart(dataSource, minDate, maxDate);
208 }
209
217 private void openFilteredChart(DataSource dataSource, Date minDate, Date maxDate) {
218 OpenTimelineAction openTimelineAction = CallableSystemAction.get(OpenTimelineAction.class);
219 if (openTimelineAction == null) {
220 logger.log(Level.WARNING, "No OpenTimelineAction provided by CallableSystemAction; taking no redirect action.");
221 }
222
223 // notify dialog (if in dialog) should close.
224 TimelinePanel.this.notifyParentClose();
225
226 Interval timeSpan = null;
227
228 try {
230
231 if (dataSource != null) {
232 controller.pushFilters(timelineUtils.getDataSourceFilterState(dataSource));
233 }
234
235 if (minDate != null && maxDate != null) {
236 timeSpan = new Interval(new DateTime(minDate), new DateTime(maxDate));
237 }
238 } catch (TskCoreException ex) {
239 logger.log(Level.WARNING, "Unable to view time range in Timeline view", ex);
240 }
241
242 try {
243 openTimelineAction.showTimeline(timeSpan);
244 } catch (TskCoreException ex) {
245 logger.log(Level.WARNING, "An unexpected exception occurred while opening the timeline.", ex);
246 }
247 }
248
249 @Override
250 protected void fetchInformation(DataSource dataSource) {
252 }
253
254 @Override
255 protected void onNewDataSource(DataSource dataSource) {
257 }
258
259 @Override
260 public void close() {
261 ingestRunningLabel.unregister();
262 super.close();
263 }
264
270 @SuppressWarnings("unchecked")
271 // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
272 private void initComponents() {
273
274 javax.swing.JScrollPane mainScrollPane = new javax.swing.JScrollPane();
275 javax.swing.JPanel mainContentPanel = new javax.swing.JPanel();
276 javax.swing.JPanel ingestRunningPanel = ingestRunningLabel;
277 javax.swing.JLabel activityRangeLabel = new javax.swing.JLabel();
278 javax.swing.Box.Filler filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2));
279 javax.swing.JPanel earliestLabelPanel = earliestLabel;
280 javax.swing.JPanel latestLabelPanel = latestLabel;
281 javax.swing.Box.Filler filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20));
282 javax.swing.JPanel last30DaysPanel = last30DaysChart;
283 viewInTimelineBtn = new javax.swing.JButton();
284 javax.swing.Box.Filler filler5 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767));
285
286 mainContentPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10));
287 mainContentPanel.setLayout(new javax.swing.BoxLayout(mainContentPanel, javax.swing.BoxLayout.PAGE_AXIS));
288
289 ingestRunningPanel.setAlignmentX(0.0F);
290 ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 25));
291 ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 25));
292 ingestRunningPanel.setPreferredSize(new java.awt.Dimension(10, 25));
293 mainContentPanel.add(ingestRunningPanel);
294
295 activityRangeLabel.setFont(new java.awt.Font("Segoe UI", 1, 12)); // NOI18N
296 org.openide.awt.Mnemonics.setLocalizedText(activityRangeLabel, org.openide.util.NbBundle.getMessage(TimelinePanel.class, "TimelinePanel.activityRangeLabel.text")); // NOI18N
297 mainContentPanel.add(activityRangeLabel);
298 activityRangeLabel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(TimelinePanel.class, "PastCasesPanel.notableFileLabel.text")); // NOI18N
299
300 filler1.setAlignmentX(0.0F);
301 mainContentPanel.add(filler1);
302
303 earliestLabelPanel.setAlignmentX(0.0F);
304 earliestLabelPanel.setMaximumSize(new java.awt.Dimension(32767, 20));
305 earliestLabelPanel.setMinimumSize(new java.awt.Dimension(100, 20));
306 earliestLabelPanel.setPreferredSize(new java.awt.Dimension(100, 20));
307 mainContentPanel.add(earliestLabelPanel);
308
309 latestLabelPanel.setAlignmentX(0.0F);
310 latestLabelPanel.setMaximumSize(new java.awt.Dimension(32767, 20));
311 latestLabelPanel.setMinimumSize(new java.awt.Dimension(100, 20));
312 latestLabelPanel.setPreferredSize(new java.awt.Dimension(100, 20));
313 mainContentPanel.add(latestLabelPanel);
314
315 filler2.setAlignmentX(0.0F);
316 mainContentPanel.add(filler2);
317
318 last30DaysPanel.setAlignmentX(0.0F);
319 last30DaysPanel.setMaximumSize(new java.awt.Dimension(600, 300));
320 last30DaysPanel.setMinimumSize(new java.awt.Dimension(600, 300));
321 last30DaysPanel.setPreferredSize(new java.awt.Dimension(600, 300));
322 last30DaysPanel.setVerifyInputWhenFocusTarget(false);
323 mainContentPanel.add(last30DaysPanel);
324
325 org.openide.awt.Mnemonics.setLocalizedText(viewInTimelineBtn, org.openide.util.NbBundle.getMessage(TimelinePanel.class, "TimelinePanel.viewInTimelineBtn.text")); // NOI18N
326 viewInTimelineBtn.setEnabled(false);
327 viewInTimelineBtn.addActionListener(new java.awt.event.ActionListener() {
328 public void actionPerformed(java.awt.event.ActionEvent evt) {
329 viewInTimelineBtnActionPerformed(evt);
330 }
331 });
332 mainContentPanel.add(viewInTimelineBtn);
333
334 filler5.setAlignmentX(0.0F);
335 mainContentPanel.add(filler5);
336
337 mainScrollPane.setViewportView(mainContentPanel);
338
339 javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
340 this.setLayout(layout);
341 layout.setHorizontalGroup(
342 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
343 .addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
344 );
345 layout.setVerticalGroup(
346 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
347 .addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
348 );
349 }// </editor-fold>//GEN-END:initComponents
350
351 private void viewInTimelineBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewInTimelineBtnActionPerformed
353 }//GEN-LAST:event_viewInTimelineBtnActionPerformed
354
355 // Variables declaration - do not modify//GEN-BEGIN:variables
356 private javax.swing.JButton viewInTimelineBtn;
357 // End of variables declaration//GEN-END:variables
358
359}
synchronized static Logger getLogger(String name)
Definition Logger.java:124
static String formatDate(Date date, DateFormat formatter)
void openFilteredChart(DataSource dataSource, Date minDate, Date maxDate)
final List< LoadableComponent<?> > loadableComponents
void viewInTimelineBtnActionPerformed(java.awt.event.ActionEvent evt)
final DataFetcher< DataSource, TimelineSummaryData > dataFetcher
final List< DataFetchComponents< DataSource, ?> > dataFetchComponents
List< BarChartSeries > parseChartData(List< DailyActivityAmount > recentDaysActivity, boolean showIntermediateDates)
void handleResult(DataFetchResult< TimelineSummaryData > result)
TimelineSummaryData getData(DataSource dataSource, int recentDaysNum)
static< I, O > DataFetchResult< O > getSubResult(DataFetchResult< I > inputResult, Function< I, O > getSubResult)
synchronized void showTimeline(AbstractFile file, BlackboardArtifact artifact, Interval timeSpan)
synchronized void pushFilters(RootFilterState filter)

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.