Autopsy  4.17.0
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 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.text.SimpleDateFormat;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Date;
27 import java.util.List;
28 import java.util.Locale;
29 import java.util.logging.Level;
30 import org.apache.commons.collections.CollectionUtils;
31 import org.joda.time.DateTime;
32 import org.joda.time.Interval;
33 import org.openide.util.NbBundle.Messages;
34 import org.openide.util.actions.CallableSystemAction;
54 import org.sleuthkit.datamodel.DataSource;
55 import org.sleuthkit.datamodel.TskCoreException;
56 
61 @Messages({
62  "TimelinePanel_earliestLabel_title=Earliest",
63  "TimelinePanel_latestLabel_title=Latest",
64  "TimlinePanel_last30DaysChart_title=Last 30 Days",
65  "TimlinePanel_last30DaysChart_fileEvts_title=File Events",
66  "TimlinePanel_last30DaysChart_artifactEvts_title=Result Events",})
67 public class TimelinePanel extends BaseDataSourceSummaryPanel {
68 
69  private static final Logger logger = Logger.getLogger(TimelinePanel.class.getName());
70  private static final long serialVersionUID = 1L;
71  private static final DateFormat EARLIEST_LATEST_FORMAT = getUtcFormat("MMM d, yyyy");
72  private static final DateFormat CHART_FORMAT = getUtcFormat("MMM d, yyyy");
73  private static final int MOST_RECENT_DAYS_COUNT = 30;
74 
81  private static DateFormat getUtcFormat(String formatString) {
82  return new SimpleDateFormat(formatString, Locale.getDefault());
83  }
84 
85  // components displayed in the tab
86  private final IngestRunningLabel ingestRunningLabel = new IngestRunningLabel();
87  private final LoadableLabel earliestLabel = new LoadableLabel(Bundle.TimelinePanel_earliestLabel_title());
88  private final LoadableLabel latestLabel = new LoadableLabel(Bundle.TimelinePanel_latestLabel_title());
89  private final BarChartPanel last30DaysChart = new BarChartPanel(Bundle.TimlinePanel_last30DaysChart_title(), "", "");
91 
92  // all loadable components on this tab
93  private final List<LoadableComponent<?>> loadableComponents = Arrays.asList(earliestLabel, latestLabel, last30DaysChart);
94 
95  // actions to load data for this tab
96  private final List<DataFetchComponents<DataSource, ?>> dataFetchComponents;
97 
98  public TimelinePanel() {
99  this(new TimelineSummary());
100  }
101 
105  public TimelinePanel(TimelineSummary timelineData) {
106  super(timelineData);
107 
108  // set up data acquisition methods
109  dataFetchComponents = Arrays.asList(
111  (dataSource) -> timelineData.getData(dataSource, MOST_RECENT_DAYS_COUNT),
112  (result) -> handleResult(result))
113  );
114 
115  initComponents();
116  }
117 
127  private static String formatDate(Date date, DateFormat formatter) {
128  return date == null ? null : formatter.format(date);
129  }
130 
131  private static final Color FILE_EVT_COLOR = new Color(228, 22, 28);
132  private static final Color ARTIFACT_EVT_COLOR = new Color(21, 227, 100);
133 
141  private List<BarChartSeries> parseChartData(List<DailyActivityAmount> recentDaysActivity) {
142  // if no data, return null indicating no result.
143  if (CollectionUtils.isEmpty(recentDaysActivity)) {
144  return null;
145  }
146 
147  // Create a bar chart item for each recent days activity item
148  List<BarChartItem> fileEvtCounts = new ArrayList<>();
149  List<BarChartItem> artifactEvtCounts = new ArrayList<>();
150 
151  for (int i = 0; i < recentDaysActivity.size(); i++) {
152  DailyActivityAmount curItem = recentDaysActivity.get(i);
153 
154  long fileAmt = curItem.getFileActivityCount();
155  long artifactAmt = curItem.getArtifactActivityCount() * 100;
156  String formattedDate = (i == 0 || i == recentDaysActivity.size() - 1)
157  ? formatDate(curItem.getDay(), CHART_FORMAT) : "";
158 
159  OrderedKey thisKey = new OrderedKey(formattedDate, i);
160  fileEvtCounts.add(new BarChartItem(thisKey, fileAmt));
161  artifactEvtCounts.add(new BarChartItem(thisKey, artifactAmt));
162  }
163 
164  return Arrays.asList(
165  new BarChartSeries(Bundle.TimlinePanel_last30DaysChart_fileEvts_title(), FILE_EVT_COLOR, fileEvtCounts),
166  new BarChartSeries(Bundle.TimlinePanel_last30DaysChart_artifactEvts_title(), ARTIFACT_EVT_COLOR, artifactEvtCounts));
167  }
168 
169  private final Object timelineBtnLock = new Object();
170  private TimelineSummaryData curTimelineData = null;
171 
181  earliestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> formatDate(r.getMinDate(), EARLIEST_LATEST_FORMAT)));
182  latestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> formatDate(r.getMaxDate(), EARLIEST_LATEST_FORMAT)));
183  last30DaysChart.showDataFetchResult(DataFetchResult.getSubResult(result, r -> parseChartData(r.getMostRecentDaysActivity())));
184 
185  if (result != null
187  && result.getData() != null) {
188 
189  synchronized (this.timelineBtnLock) {
190  this.curTimelineData = result.getData();
191  this.viewInTimelineBtn.setEnabled(true);
192  }
193  } else {
194  synchronized (this.timelineBtnLock) {
195  this.viewInTimelineBtn.setEnabled(false);
196  }
197  }
198  }
199 
203  private void openFilteredChart() {
204  DataSource dataSource = null;
205  Date minDate = null;
206  Date maxDate = null;
207 
208  // get date from current timelineData if that data exists.
209  synchronized (this.timelineBtnLock) {
210  if (curTimelineData == null) {
211  return;
212  }
213 
214  dataSource = curTimelineData.getDataSource();
215  if (CollectionUtils.isNotEmpty(curTimelineData.getMostRecentDaysActivity())) {
216  minDate = curTimelineData.getMostRecentDaysActivity().get(0).getDay();
217  maxDate = curTimelineData.getMostRecentDaysActivity().get(curTimelineData.getMostRecentDaysActivity().size() - 1).getDay();
218  // set outer bound to end of day instead of beginning
219  if (maxDate != null) {
220  maxDate = new Date(maxDate.getTime() + 1000 * 60 * 60 * 24);
221  }
222  }
223  }
224 
225  openFilteredChart(dataSource, minDate, maxDate);
226  }
227 
235  private void openFilteredChart(DataSource dataSource, Date minDate, Date maxDate) {
236  OpenTimelineAction openTimelineAction = CallableSystemAction.get(OpenTimelineAction.class);
237  if (openTimelineAction == null) {
238  logger.log(Level.WARNING, "No OpenTimelineAction provided by CallableSystemAction; taking no redirect action.");
239  }
240 
241  // notify dialog (if in dialog) should close.
242  TimelinePanel.this.notifyParentClose();
243 
244  Interval timeSpan = null;
245 
246  try {
247  final TimeLineController controller = TimeLineModule.getController();
248 
249  if (dataSource != null) {
250  controller.pushFilters(timelineUtils.getDataSourceFilterState(dataSource));
251  }
252 
253  if (minDate != null && maxDate != null) {
254  timeSpan = new Interval(new DateTime(minDate), new DateTime(maxDate));
255  }
256  } catch (NoCurrentCaseException | TskCoreException ex) {
257  logger.log(Level.WARNING, "Unable to view time range in Timeline view", ex);
258  }
259 
260  try {
261  openTimelineAction.showTimeline(timeSpan);
262  } catch (TskCoreException ex) {
263  logger.log(Level.WARNING, "An unexpected exception occurred while opening the timeline.", ex);
264  }
265  }
266 
267  @Override
268  protected void fetchInformation(DataSource dataSource) {
269  fetchInformation(dataFetchComponents, dataSource);
270  }
271 
272  @Override
273  protected void onNewDataSource(DataSource dataSource) {
274  onNewDataSource(dataFetchComponents, loadableComponents, dataSource);
275  }
276 
277  @Override
278  public void close() {
279  ingestRunningLabel.unregister();
280  super.close();
281  }
282 
288  @SuppressWarnings("unchecked")
289  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
290  private void initComponents() {
291 
292  javax.swing.JScrollPane mainScrollPane = new javax.swing.JScrollPane();
293  javax.swing.JPanel mainContentPanel = new javax.swing.JPanel();
294  javax.swing.JPanel ingestRunningPanel = ingestRunningLabel;
295  javax.swing.JLabel activityRangeLabel = new javax.swing.JLabel();
296  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));
297  javax.swing.JPanel earliestLabelPanel = earliestLabel;
298  javax.swing.JPanel latestLabelPanel = latestLabel;
299  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));
300  javax.swing.JPanel last30DaysPanel = last30DaysChart;
301  viewInTimelineBtn = new javax.swing.JButton();
302  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));
303 
304  mainContentPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10));
305  mainContentPanel.setLayout(new javax.swing.BoxLayout(mainContentPanel, javax.swing.BoxLayout.PAGE_AXIS));
306 
307  ingestRunningPanel.setAlignmentX(0.0F);
308  ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 25));
309  ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 25));
310  ingestRunningPanel.setPreferredSize(new java.awt.Dimension(10, 25));
311  mainContentPanel.add(ingestRunningPanel);
312 
313  activityRangeLabel.setFont(new java.awt.Font("Segoe UI", 1, 12)); // NOI18N
314  org.openide.awt.Mnemonics.setLocalizedText(activityRangeLabel, org.openide.util.NbBundle.getMessage(TimelinePanel.class, "TimelinePanel.activityRangeLabel.text")); // NOI18N
315  mainContentPanel.add(activityRangeLabel);
316  activityRangeLabel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(TimelinePanel.class, "PastCasesPanel.notableFileLabel.text")); // NOI18N
317 
318  filler1.setAlignmentX(0.0F);
319  mainContentPanel.add(filler1);
320 
321  earliestLabelPanel.setAlignmentX(0.0F);
322  earliestLabelPanel.setMaximumSize(new java.awt.Dimension(32767, 20));
323  earliestLabelPanel.setMinimumSize(new java.awt.Dimension(100, 20));
324  earliestLabelPanel.setPreferredSize(new java.awt.Dimension(100, 20));
325  mainContentPanel.add(earliestLabelPanel);
326 
327  latestLabelPanel.setAlignmentX(0.0F);
328  latestLabelPanel.setMaximumSize(new java.awt.Dimension(32767, 20));
329  latestLabelPanel.setMinimumSize(new java.awt.Dimension(100, 20));
330  latestLabelPanel.setPreferredSize(new java.awt.Dimension(100, 20));
331  mainContentPanel.add(latestLabelPanel);
332 
333  filler2.setAlignmentX(0.0F);
334  mainContentPanel.add(filler2);
335 
336  last30DaysPanel.setAlignmentX(0.0F);
337  last30DaysPanel.setMaximumSize(new java.awt.Dimension(600, 300));
338  last30DaysPanel.setMinimumSize(new java.awt.Dimension(600, 300));
339  last30DaysPanel.setPreferredSize(new java.awt.Dimension(600, 300));
340  last30DaysPanel.setVerifyInputWhenFocusTarget(false);
341  mainContentPanel.add(last30DaysPanel);
342 
343  org.openide.awt.Mnemonics.setLocalizedText(viewInTimelineBtn, org.openide.util.NbBundle.getMessage(TimelinePanel.class, "TimelinePanel.viewInTimelineBtn.text")); // NOI18N
344  viewInTimelineBtn.setEnabled(false);
345  viewInTimelineBtn.addActionListener(new java.awt.event.ActionListener() {
346  public void actionPerformed(java.awt.event.ActionEvent evt) {
347  viewInTimelineBtnActionPerformed(evt);
348  }
349  });
350  mainContentPanel.add(viewInTimelineBtn);
351 
352  filler5.setAlignmentX(0.0F);
353  mainContentPanel.add(filler5);
354 
355  mainScrollPane.setViewportView(mainContentPanel);
356 
357  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
358  this.setLayout(layout);
359  layout.setHorizontalGroup(
360  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
361  .addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
362  );
363  layout.setVerticalGroup(
364  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
365  .addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
366  );
367  }// </editor-fold>//GEN-END:initComponents
368 
369  private void viewInTimelineBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewInTimelineBtnActionPerformed
370  openFilteredChart();
371  }//GEN-LAST:event_viewInTimelineBtnActionPerformed
372 
373  // Variables declaration - do not modify//GEN-BEGIN:variables
374  private javax.swing.JButton viewInTimelineBtn;
375  // End of variables declaration//GEN-END:variables
376 }
static DateFormat getUtcFormat(String formatString)
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)
static String formatDate(Date date, DateFormat formatter)
void viewInTimelineBtnActionPerformed(java.awt.event.ActionEvent evt)
List< BarChartSeries > parseChartData(List< DailyActivityAmount > recentDaysActivity)
void openFilteredChart(DataSource dataSource, Date minDate, Date maxDate)
synchronized void pushFilters(RootFilterState filter)
TimelineSummaryData getData(DataSource dataSource, int recentDaysNum)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

Copyright © 2012-2021 Basis Technology. Generated on: Tue Jan 19 2021
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.