Autopsy  4.19.3
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  */
19 package org.sleuthkit.autopsy.datasourcesummary.ui;
20 
21 import java.awt.Color;
22 import java.text.DateFormat;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Date;
26 import java.util.List;
27 import java.util.logging.Level;
28 import org.apache.commons.collections.CollectionUtils;
29 import org.joda.time.DateTime;
30 import org.joda.time.Interval;
31 import org.openide.util.NbBundle.Messages;
32 import org.openide.util.actions.CallableSystemAction;
52 import org.sleuthkit.datamodel.DataSource;
53 import 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",})
65 public 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";
71  private static final DateFormat EARLIEST_LATEST_FORMAT = TimelineSummary.getUtcFormat(EARLIEST_LATEST_FORMAT_STR);
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
76  private final IngestRunningLabel ingestRunningLabel = new IngestRunningLabel();
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 
106  initComponents();
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)
139  ? TimelineSummary.formatDate(curItem.getDay(), CHART_FORMAT) : "";
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();
152  private TimelineSummaryData curTimelineData = null;
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 {
229  final TimeLineController controller = TimeLineModule.getController();
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) {
251  fetchInformation(dataFetchComponents, dataSource);
252  }
253 
254  @Override
255  protected void onNewDataSource(DataSource dataSource) {
256  onNewDataSource(dataFetchComponents, loadableComponents, 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
352  openFilteredChart();
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 }
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)
final List< DataFetchComponents< DataSource,?> > dataFetchComponents
void showDataFetchResult(DataFetchResult< T > result, String errorMessage, String noResultsMessage)
void handleResult(DataFetchResult< TimelineSummaryData > result)
void viewInTimelineBtnActionPerformed(java.awt.event.ActionEvent evt)
TimelinePanel(TimelineSummaryGetter timelineData)
void openFilteredChart(DataSource dataSource, Date minDate, Date maxDate)
synchronized void pushFilters(RootFilterState filter)
final DataFetcher< DataSource, TimelineSummaryData > dataFetcher
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static String formatDate(Date date, DateFormat formatter)
List< BarChartSeries > parseChartData(List< DailyActivityAmount > recentDaysActivity, boolean showIntermediateDates)

Copyright © 2012-2022 Basis Technology. Generated on: Tue Jun 27 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.