Autopsy  4.20.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
DataArtifactContentViewer.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-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.corecomponents;
20 
21 import java.awt.Component;
22 import java.awt.Cursor;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.List;
26 import java.util.concurrent.ExecutionException;
27 import java.util.logging.Level;
28 import javax.swing.SwingWorker;
29 import org.openide.nodes.Node;
30 import org.openide.util.Lookup;
31 import org.openide.util.NbBundle;
32 import org.openide.util.lookup.ServiceProvider;
35 import org.sleuthkit.datamodel.BlackboardAttribute;
36 import org.sleuthkit.datamodel.Content;
37 import org.sleuthkit.datamodel.TskCoreException;
38 import org.sleuthkit.datamodel.TskException;
39 import java.util.Collections;
40 import java.util.HashSet;
46 import org.sleuthkit.datamodel.AnalysisResult;
47 import org.sleuthkit.datamodel.BlackboardArtifact;
48 import org.sleuthkit.datamodel.DataArtifact;
49 
57 @ServiceProvider(service = DataContentViewer.class, position = 6)
58 @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
59 public class DataArtifactContentViewer extends javax.swing.JPanel implements DataContentViewer {
60 
61  private static final long serialVersionUID = 1L;
62 
63  @NbBundle.Messages({
64  "DataArtifactContentViewer.failedToGetSourcePath.message=Failed to get source file path from case database",
65  "DataArtifactContentViewer.failedToGetAttributes.message=Failed to get some or all attributes from case database"
66  })
67  private final static Logger logger = Logger.getLogger(DataArtifactContentViewer.class.getName());
68  private final static String WAIT_TEXT = NbBundle.getMessage(DataArtifactContentViewer.class, "DataArtifactContentViewer.waitText");
69  private final static String ERROR_TEXT = NbBundle.getMessage(DataArtifactContentViewer.class, "DataArtifactContentViewer.errorText");
70 
71  // Value to return in isPreferred if this viewer is less preferred.
72  private static final int LESS_PREFERRED = ViewerPriority.viewerPriority.LevelThree.getFlag();
73  // Value to return in isPreferred if this viewer is more preferred.
74  private static final int MORE_PREFERRED = ViewerPriority.viewerPriority.LevelSeven.getFlag();
75 
76  private Node currentNode; // @@@ Remove this when the redundant setNode() calls problem is fixed.
77  private int currentPage = 1;
78  private final Object lock = new Object();
79  private List<DataArtifact> artifactTableContents; // Accessed by multiple threads, use getArtifactContents() and setArtifactContents()
80  private SwingWorker<ViewUpdate, Void> currentTask; // Accessed by multiple threads, use startNewTask()
81 
82  private final Collection<ArtifactContentViewer> knowArtifactViewers = new HashSet<>(Lookup.getDefault().lookupAll(ArtifactContentViewer.class));
83 
85 
86  initComponents();
87 
88  resetComponents();
89  }
90 
96  @SuppressWarnings("unchecked")
97  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
98  private void initComponents() {
99  java.awt.GridBagConstraints gridBagConstraints;
100 
101  scrollPane = new javax.swing.JScrollPane();
102  menuBar = new javax.swing.JPanel();
103  totalPageLabel = new javax.swing.JLabel();
104  ofLabel = new javax.swing.JLabel();
105  currentPageLabel = new javax.swing.JLabel();
106  pageLabel = new javax.swing.JLabel();
107  nextPageButton = new javax.swing.JButton();
108  pageLabel2 = new javax.swing.JLabel();
109  prevPageButton = new javax.swing.JButton();
110  artifactLabel = new javax.swing.JLabel();
111  filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0));
112  artifactContentPanel = new javax.swing.JPanel();
113 
114  setMinimumSize(new java.awt.Dimension(300, 60));
115  setPreferredSize(new java.awt.Dimension(300, 60));
116 
117  scrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
118  scrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
119  scrollPane.setPreferredSize(new java.awt.Dimension(6, 60));
120 
121  menuBar.setMaximumSize(null);
122  menuBar.setMinimumSize(null);
123  menuBar.setPreferredSize(null);
124  menuBar.setLayout(new java.awt.GridBagLayout());
125 
126  totalPageLabel.setText(org.openide.util.NbBundle.getMessage(DataArtifactContentViewer.class, "DataArtifactContentViewer.totalPageLabel.text")); // NOI18N
127  totalPageLabel.setMaximumSize(null);
128  totalPageLabel.setPreferredSize(null);
129  gridBagConstraints = new java.awt.GridBagConstraints();
130  gridBagConstraints.gridx = 3;
131  gridBagConstraints.gridy = 0;
132  gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
133  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
134  gridBagConstraints.insets = new java.awt.Insets(3, 12, 0, 0);
135  menuBar.add(totalPageLabel, gridBagConstraints);
136 
137  ofLabel.setText(org.openide.util.NbBundle.getMessage(DataArtifactContentViewer.class, "DataArtifactContentViewer.ofLabel.text")); // NOI18N
138  gridBagConstraints = new java.awt.GridBagConstraints();
139  gridBagConstraints.gridx = 2;
140  gridBagConstraints.gridy = 0;
141  gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
142  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
143  gridBagConstraints.insets = new java.awt.Insets(3, 12, 0, 0);
144  menuBar.add(ofLabel, gridBagConstraints);
145 
146  currentPageLabel.setText(org.openide.util.NbBundle.getMessage(DataArtifactContentViewer.class, "DataArtifactContentViewer.currentPageLabel.text")); // NOI18N
147  currentPageLabel.setMaximumSize(null);
148  currentPageLabel.setPreferredSize(null);
149  gridBagConstraints = new java.awt.GridBagConstraints();
150  gridBagConstraints.gridx = 1;
151  gridBagConstraints.gridy = 0;
152  gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
153  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
154  gridBagConstraints.insets = new java.awt.Insets(3, 7, 0, 0);
155  menuBar.add(currentPageLabel, gridBagConstraints);
156 
157  pageLabel.setText(org.openide.util.NbBundle.getMessage(DataArtifactContentViewer.class, "DataArtifactContentViewer.pageLabel.text")); // NOI18N
158  gridBagConstraints = new java.awt.GridBagConstraints();
159  gridBagConstraints.gridx = 0;
160  gridBagConstraints.gridy = 0;
161  gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
162  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
163  gridBagConstraints.insets = new java.awt.Insets(3, 12, 0, 0);
164  menuBar.add(pageLabel, gridBagConstraints);
165 
166  nextPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"))); // NOI18N
167  nextPageButton.setText(org.openide.util.NbBundle.getMessage(DataArtifactContentViewer.class, "DataArtifactContentViewer.nextPageButton.text")); // NOI18N
168  nextPageButton.setBorderPainted(false);
169  nextPageButton.setContentAreaFilled(false);
170  nextPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); // NOI18N
171  nextPageButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
172  nextPageButton.setPreferredSize(new java.awt.Dimension(23, 23));
173  nextPageButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"))); // NOI18N
174  nextPageButton.addActionListener(new java.awt.event.ActionListener() {
175  public void actionPerformed(java.awt.event.ActionEvent evt) {
176  nextPageButtonActionPerformed(evt);
177  }
178  });
179  gridBagConstraints = new java.awt.GridBagConstraints();
180  gridBagConstraints.gridx = 6;
181  gridBagConstraints.gridy = 0;
182  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
183  gridBagConstraints.insets = new java.awt.Insets(0, 0, 35, 0);
184  menuBar.add(nextPageButton, gridBagConstraints);
185 
186  pageLabel2.setText(org.openide.util.NbBundle.getMessage(DataArtifactContentViewer.class, "DataArtifactContentViewer.pageLabel2.text")); // NOI18N
187  pageLabel2.setMaximumSize(new java.awt.Dimension(29, 14));
188  pageLabel2.setMinimumSize(new java.awt.Dimension(29, 14));
189  gridBagConstraints = new java.awt.GridBagConstraints();
190  gridBagConstraints.gridx = 4;
191  gridBagConstraints.gridy = 0;
192  gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
193  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
194  gridBagConstraints.insets = new java.awt.Insets(3, 30, 0, 0);
195  menuBar.add(pageLabel2, gridBagConstraints);
196 
197  prevPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); // NOI18N
198  prevPageButton.setText(org.openide.util.NbBundle.getMessage(DataArtifactContentViewer.class, "DataArtifactContentViewer.prevPageButton.text")); // NOI18N
199  prevPageButton.setBorderPainted(false);
200  prevPageButton.setContentAreaFilled(false);
201  prevPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); // NOI18N
202  prevPageButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
203  prevPageButton.setPreferredSize(new java.awt.Dimension(23, 23));
204  prevPageButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"))); // NOI18N
205  prevPageButton.addActionListener(new java.awt.event.ActionListener() {
206  public void actionPerformed(java.awt.event.ActionEvent evt) {
207  prevPageButtonActionPerformed(evt);
208  }
209  });
210  gridBagConstraints = new java.awt.GridBagConstraints();
211  gridBagConstraints.gridx = 5;
212  gridBagConstraints.gridy = 0;
213  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
214  gridBagConstraints.insets = new java.awt.Insets(0, 5, 35, 0);
215  menuBar.add(prevPageButton, gridBagConstraints);
216  gridBagConstraints = new java.awt.GridBagConstraints();
217  gridBagConstraints.gridx = 8;
218  gridBagConstraints.gridy = 0;
219  gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
220  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
221  gridBagConstraints.insets = new java.awt.Insets(3, 0, 0, 8);
222  menuBar.add(artifactLabel, gridBagConstraints);
223  gridBagConstraints = new java.awt.GridBagConstraints();
224  gridBagConstraints.gridx = 7;
225  gridBagConstraints.gridy = 0;
226  gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
227  gridBagConstraints.weightx = 0.1;
228  menuBar.add(filler1, gridBagConstraints);
229 
230  scrollPane.setViewportView(menuBar);
231 
232  artifactContentPanel.setLayout(new javax.swing.OverlayLayout(artifactContentPanel));
233 
234  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
235  this.setLayout(layout);
236  layout.setHorizontalGroup(
237  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
238  .addComponent(scrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
239  .addComponent(artifactContentPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
240  );
241  layout.setVerticalGroup(
242  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
243  .addGroup(layout.createSequentialGroup()
244  .addComponent(scrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)
245  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
246  .addComponent(artifactContentPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 30, Short.MAX_VALUE))
247  );
248  }// </editor-fold>//GEN-END:initComponents
249 
250  private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed
251  currentPage += 1;
252  currentPageLabel.setText(Integer.toString(currentPage));
253  artifactLabel.setText(artifactTableContents.get(currentPage - 1).getDisplayName());
254  startNewTask(new SelectedArtifactChangedTask(currentPage));
255  }//GEN-LAST:event_nextPageButtonActionPerformed
256 
257  private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevPageButtonActionPerformed
258  currentPage -= 1;
259  currentPageLabel.setText(Integer.toString(currentPage));
260  artifactLabel.setText(artifactTableContents.get(currentPage - 1).getDisplayName());
261  startNewTask(new SelectedArtifactChangedTask(currentPage));
262  }//GEN-LAST:event_prevPageButtonActionPerformed
263 
264  // Variables declaration - do not modify//GEN-BEGIN:variables
265  private javax.swing.JPanel artifactContentPanel;
266  private javax.swing.JLabel artifactLabel;
267  private javax.swing.JLabel currentPageLabel;
268  private javax.swing.Box.Filler filler1;
269  private javax.swing.JPanel menuBar;
270  private javax.swing.JButton nextPageButton;
271  private javax.swing.JLabel ofLabel;
272  private javax.swing.JLabel pageLabel;
273  private javax.swing.JLabel pageLabel2;
274  private javax.swing.JButton prevPageButton;
275  private javax.swing.JScrollPane scrollPane;
276  private javax.swing.JLabel totalPageLabel;
277  // End of variables declaration//GEN-END:variables
278 
282  private void resetComponents() {
283  currentPage = 1;
284  currentPageLabel.setText("");
285  artifactLabel.setText("");
286  totalPageLabel.setText("");
287 
288  prevPageButton.setEnabled(false);
289  nextPageButton.setEnabled(false);
290  currentNode = null;
291 
292  artifactContentPanel.removeAll();
293  }
294 
295  @Override
296  public void setNode(Node selectedNode) {
297  currentNode = null;
298 
299  // Make sure there is a node. Null might be passed to reset the viewer.
300  if (selectedNode == null) {
301  return;
302  }
303 
304  // Make sure the node is of the correct type.
305  Lookup lookup = selectedNode.getLookup();
306  Content content = lookup.lookup(Content.class);
307  if (content == null) {
308  return;
309  }
310 
311  startNewTask(new SelectedNodeChangedTask(selectedNode));
312  }
313 
314  @Override
315  public String getTitle() {
316  return NbBundle.getMessage(this.getClass(), "DataArtifactContentViewer.title");
317  }
318 
319  @Override
320  public String getToolTip() {
321  return NbBundle.getMessage(this.getClass(), "DataArtifactContentViewer.toolTip");
322  }
323 
324  @Override
325  public DataContentViewer createInstance() {
326  return new DataArtifactContentViewer();
327  }
328 
329  @Override
330  public Component getComponent() {
331  return this;
332  }
333 
334  @Override
335  public void resetComponent() {
336  resetComponents();
337  }
338 
339  @Override
340  public boolean isSupported(Node node) {
341  if (node == null) {
342  return false;
343  }
344 
345  for (Content content : node.getLookup().lookupAll(Content.class)) {
346  if ((content != null) && (!(content instanceof DataArtifact)) && (!(content instanceof AnalysisResult))) {
347  try {
348  return Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().hasDataArtifacts(content.getId());
349  } catch (NoCurrentCaseException | TskException ex) {
350  logger.log(Level.SEVERE, "Couldn't get count of DataArtifacts for content", ex); //NON-NLS
351  }
352  }
353  }
354 
355  return false;
356  }
357 
358  @Override
359  public int isPreferred(Node node) {
360  // get the artifact from the lookup
361  DataArtifact artifact = node.getLookup().lookup(DataArtifact.class);
362  if (artifact == null) {
363  return LESS_PREFERRED;
364  }
365 
366  // get the type of the artifact
367  BlackboardArtifact.Type artifactType;
368  try {
369  artifactType = artifact.getType();
370  } catch (TskCoreException ex) {
371  logger.log(Level.SEVERE,
372  String.format("There was an error getting the artifact type for artifact with id: %d", artifact.getId()),
373  ex);
374  return LESS_PREFERRED;
375  }
376 
377  // if web download or web cache, less preferred since the content is important and not the artifact itself.
378  if (artifactType.getTypeID() == BlackboardArtifact.Type.TSK_WEB_DOWNLOAD.getTypeID()
379  || artifactType.getTypeID() == BlackboardArtifact.Type.TSK_WEB_CACHE.getTypeID()) {
380 
381  return LESS_PREFERRED;
382  }
383 
384  switch (artifactType.getCategory()) {
385  // data artifacts should be more preferred
386  case DATA_ARTIFACT:
387  return MORE_PREFERRED;
388  // everything else is less preferred
389  default:
390  return LESS_PREFERRED;
391  }
392  }
393 
394  private ArtifactContentViewer getSupportingViewer(DataArtifact artifact) {
395  for (ArtifactContentViewer viewer : knowArtifactViewers) {
396  if (viewer.isSupported(artifact)) {
397  return viewer;
398  }
399  }
401  }
402 
407  private class ViewUpdate {
408 
409  int numberOfPages;
410  int currentPage;
411  DataArtifact artifact;
412  String errorMsg;
413 
414  ViewUpdate(int numberOfPages, int currentPage, DataArtifact artifact) {
415  this.currentPage = currentPage;
416  this.numberOfPages = numberOfPages;
417  this.artifact = artifact;
418  this.errorMsg = null;
419  }
420 
421  ViewUpdate(int numberOfPages, int currentPage, String errorMsg) {
422  this.currentPage = currentPage;
423  this.numberOfPages = numberOfPages;
424  this.errorMsg = errorMsg;
425  this.artifact = null;
426  }
427  }
428 
436  private void updateView(ViewUpdate viewUpdate) {
437  this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
438 
439  nextPageButton.setEnabled(viewUpdate.currentPage < viewUpdate.numberOfPages);
440  prevPageButton.setEnabled(viewUpdate.currentPage > 1);
441  currentPage = viewUpdate.currentPage;
442  totalPageLabel.setText(Integer.toString(viewUpdate.numberOfPages));
443  currentPageLabel.setText(Integer.toString(currentPage));
444 
445  artifactContentPanel.removeAll();
446 
447  if (viewUpdate.artifact != null) {
448  artifactLabel.setText(viewUpdate.artifact.getDisplayName());
449 
450  DataArtifact artifact = viewUpdate.artifact;
451  ArtifactContentViewer viewer = this.getSupportingViewer(artifact);
452  viewer.setArtifact(artifact);
453 
454  artifactContentPanel.add(viewer.getComponent());
455  } else {
456  artifactLabel.setText(viewUpdate.errorMsg);
457  }
458 
459  artifactContentPanel.repaint();
460  artifactContentPanel.revalidate();
461  this.setCursor(null);
462 
463  this.revalidate();
464  }
465 
472  private synchronized void startNewTask(SwingWorker<ViewUpdate, Void> task) {
473 
474  // The output of the previous task is no longer relevant.
475  if (currentTask != null) {
476  // This call sets a cancellation flag. It does not terminate the background thread running the task.
477  // The task must check the cancellation flag and react appropriately.
478  currentTask.cancel(false);
479  }
480 
481  // Start the new task.
482  currentTask = task;
483  currentTask.execute();
484  }
485 
492  private void setArtifactContents(List<DataArtifact> artifactList) {
493  synchronized (lock) {
494  this.artifactTableContents = artifactList;
495  }
496  }
497 
503  private List<DataArtifact> getArtifactContents() {
504  synchronized (lock) {
505  return Collections.unmodifiableList(artifactTableContents);
506  }
507  }
508 
514  private static boolean isSourceContent(Content content) {
515  return (content != null) &&
516  (!(content instanceof DataArtifact)) &&
517  (!(content instanceof AnalysisResult));
518  }
519 
525  private class SelectedNodeChangedTask extends SwingWorker<ViewUpdate, Void> {
526 
527  private final Node selectedNode;
528 
529  SelectedNodeChangedTask(Node selectedNode) {
530  this.selectedNode = selectedNode;
531  }
532 
533  @Override
535  // Get the lookup for the node for access to its underlying content and
536  // blackboard artifact, if any.
537  Lookup lookup = selectedNode.getLookup();
538 
539  // Get the content. We may get DataArtifacts, ignore those here.
540  List<DataArtifact> artifacts = Collections.emptyList();
541  Collection<? extends Content> contents = lookup.lookupAll(Content.class);
542  if (contents.isEmpty()) {
543  return new ViewUpdate(getArtifactContents().size(), currentPage, ERROR_TEXT);
544  }
545  for (Content content : contents) {
546  if (isSourceContent(content)) {
547  // Get all of the blackboard artifacts associated with the content. These are what this
548  // viewer displays.
549  try {
550  artifacts = content.getAllDataArtifacts();
551  break;
552  } catch (TskException ex) {
553  logger.log(Level.SEVERE, "Couldn't get artifacts", ex); //NON-NLS
554  return new ViewUpdate(getArtifactContents().size(), currentPage, ERROR_TEXT);
555  }
556  }
557  }
558 
559  if (isCancelled()) {
560  return null;
561  }
562 
563  // Build the new artifact contents cache.
564  ArrayList<DataArtifact> artifactContents = new ArrayList<>();
565  for (DataArtifact artifact : artifacts) {
566  artifactContents.add(artifact);
567  }
568 
569  // If the node has an underlying data artifact, show it. If not,
570  // show the first artifact.
571  int index = 0;
572  DataArtifact artifact = lookup.lookup(DataArtifact.class);
573  if (artifact != null) {
574  index = artifacts.indexOf(artifact);
575  if (index == -1) {
576  index = 0;
577  } else {
578  // if the artifact has an ASSOCIATED ARTIFACT, then we display the associated artifact instead
579  try {
580  for (BlackboardAttribute attr : artifact.getAttributes()) {
581  if (attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) {
582  long assocArtifactId = attr.getValueLong();
583  int assocArtifactIndex = -1;
584  for (DataArtifact art : artifacts) {
585  if (assocArtifactId == art.getArtifactID()) {
586  assocArtifactIndex = artifacts.indexOf(art);
587  break;
588  }
589  }
590  if (assocArtifactIndex >= 0) {
591  index = assocArtifactIndex;
592  }
593  break;
594  }
595  }
596  } catch (TskCoreException ex) {
597  logger.log(Level.WARNING, "Couldn't get associated artifact to display in Content Viewer.", ex); //NON-NLS
598  }
599  }
600 
601  }
602 
603  if (isCancelled()) {
604  return null;
605  }
606 
607  // Add one to the index of the artifact content for the corresponding page index.
608  ViewUpdate viewUpdate = new ViewUpdate(artifactContents.size(), index + 1, artifactContents.get(index));
609 
610  // It may take a considerable amount of time to fetch the attributes of the selected artifact
611  if (isCancelled()) {
612  return null;
613  }
614 
615  // Update the artifact contents cache.
616  setArtifactContents(artifactContents);
617 
618  return viewUpdate;
619  }
620 
621  @Override
622  protected void done() {
623  if (!isCancelled()) {
624  try {
625  ViewUpdate viewUpdate = get();
626  if (viewUpdate != null) {
627  currentNode = selectedNode;
628  updateView(viewUpdate);
629  }
630  } catch (InterruptedException | ExecutionException ex) {
631  logger.log(Level.WARNING, "Artifact display task unexpectedly interrupted or failed", ex); //NON-NLS
632  }
633  }
634  }
635  }
636 
642  private class SelectedArtifactChangedTask extends SwingWorker<ViewUpdate, Void> {
643 
644  private final int pageIndex;
645 
646  SelectedArtifactChangedTask(final int pageIndex) {
647  this.pageIndex = pageIndex;
648  }
649 
650  @Override
652  // Get the artifact content to display from the cache. Note that one must be subtracted from the
653  // page index to get the corresponding artifact content index.
654  List<DataArtifact> artifactContents = getArtifactContents();
655 
656  // It may take a considerable amount of time to fetch the attributes of the selected artifact so check for cancellation.
657  if (isCancelled()) {
658  return null;
659  }
660 
661  DataArtifact artifactContent = artifactContents.get(pageIndex - 1);
662  return new ViewUpdate(artifactContents.size(), pageIndex, artifactContent);
663  }
664 
665  @Override
666  protected void done() {
667  if (!isCancelled()) {
668  try {
669  ViewUpdate viewUpdate = get();
670  if (viewUpdate != null) {
671  updateView(viewUpdate);
672  }
673  } catch (InterruptedException | ExecutionException ex) {
674  logger.log(Level.WARNING, "Artifact display task unexpectedly interrupted or failed", ex); //NON-NLS
675  }
676  }
677  }
678  }
679 }
synchronized void startNewTask(SwingWorker< ViewUpdate, Void > task)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

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