Autopsy  4.5.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
DataContentViewerArtifact.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2013 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.awt.Toolkit;
24 import java.awt.event.ActionEvent;
25 import java.awt.event.ActionListener;
26 import java.awt.datatransfer.StringSelection;
27 import java.text.SimpleDateFormat;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.Enumeration;
31 import java.util.List;
32 import java.util.concurrent.ExecutionException;
33 import java.util.logging.Level;
34 import javax.swing.JMenuItem;
35 import javax.swing.SwingWorker;
36 import javax.swing.event.ChangeEvent;
37 import javax.swing.event.ListSelectionEvent;
38 import javax.swing.event.TableColumnModelEvent;
39 import javax.swing.table.DefaultTableModel;
40 import javax.swing.table.TableColumn;
41 import javax.swing.event.TableColumnModelListener;
42 import javax.swing.text.JTextComponent;
43 import javax.swing.text.View;
44 import org.apache.commons.lang.StringUtils;
45 import org.openide.nodes.Node;
46 import org.openide.util.Lookup;
47 import org.openide.util.NbBundle;
48 import org.openide.util.lookup.ServiceProvider;
52 import org.sleuthkit.datamodel.BlackboardArtifact;
53 import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
54 import org.sleuthkit.datamodel.BlackboardAttribute;
55 import org.sleuthkit.datamodel.Content;
56 import org.sleuthkit.datamodel.TskCoreException;
57 import org.sleuthkit.datamodel.TskException;
58 import org.netbeans.swing.etable.ETable;
59 
65 @ServiceProvider(service = DataContentViewer.class, position = 3)
66 public class DataContentViewerArtifact extends javax.swing.JPanel implements DataContentViewer {
67 
68  @NbBundle.Messages({
69  "DataContentViewerArtifact.attrsTableHeader.type=Type",
70  "DataContentViewerArtifact.attrsTableHeader.value=Value",
71  "DataContentViewerArtifact.attrsTableHeader.sources=Source(s)",
72  "DataContentViewerArtifact.failedToGetSourcePath.message=Failed to get source file path from case database",
73  "DataContentViewerArtifact.failedToGetAttributes.message=Failed to get some or all attributes from case database"
74  })
75  private final static Logger logger = Logger.getLogger(DataContentViewerArtifact.class.getName());
76  private final static String WAIT_TEXT = NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.waitText");
77  private final static String ERROR_TEXT = NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.errorText");
78  private Node currentNode; // @@@ Remove this when the redundant setNode() calls problem is fixed.
79  private int currentPage = 1;
80  private final Object lock = new Object();
81  private List<ResultsTableArtifact> artifactTableContents; // Accessed by multiple threads, use getArtifactContents() and setArtifactContents()
82  SwingWorker<ViewUpdate, Void> currentTask; // Accessed by multiple threads, use startNewTask()
83  private static final String[] COLUMN_HEADERS = {
84  Bundle.DataContentViewerArtifact_attrsTableHeader_type(),
85  Bundle.DataContentViewerArtifact_attrsTableHeader_value(),
86  Bundle.DataContentViewerArtifact_attrsTableHeader_sources()};
87  private static final int[] COLUMN_WIDTHS = {100, 800, 100};
88  private static final int CELL_BOTTOM_MARGIN = 5;
89 
91  initResultsTable();
92  initComponents();
93  resultsTableScrollPane.setViewportView(resultsTable);
94  customizeComponents();
95  resetComponents();
96  resultsTable.setDefaultRenderer(Object.class, new MultiLineTableCellRenderer());
97  }
98 
99  private void initResultsTable() {
100  resultsTable = new ETable();
101  resultsTable.setModel(new javax.swing.table.DefaultTableModel() {
102  private static final long serialVersionUID = 1L;
103 
104  public boolean isCellEditable(int rowIndex, int columnIndex) {
105  return false;
106  }
107  });
108  resultsTable.setCellSelectionEnabled(true);
109  resultsTable.getTableHeader().setReorderingAllowed(false);
110  resultsTable.setColumnHidingAllowed(false);
111  resultsTable.getColumnModel().getSelectionModel().setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION);
112  resultsTable.getColumnModel().addColumnModelListener(new TableColumnModelListener() {
113 
114  @Override
115  public void columnAdded(TableColumnModelEvent e) {
116  }
117 
118  @Override
119  public void columnRemoved(TableColumnModelEvent e) {
120  }
121 
122  @Override
123  public void columnMoved(TableColumnModelEvent e) {
124 
125  }
126 
127  @Override
128  public void columnMarginChanged(ChangeEvent e) {
129  updateRowHeights(); //When the user changes column width we may need to resize row height
130  }
131 
132  @Override
133  public void columnSelectionChanged(ListSelectionEvent e) {
134  }
135  });
136  resultsTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_NEXT_COLUMN);
137 
138  }
139 
143  private void updateRowHeights() {
144  int valueColIndex = -1;
145  for (int col = 0; col < resultsTable.getColumnCount(); col++) {
146  if (resultsTable.getColumnName(col).equals(COLUMN_HEADERS[1])) {
147  valueColIndex = col;
148  }
149  }
150  if (valueColIndex != -1) {
151  for (int row = 0; row < resultsTable.getRowCount(); row++) {
152  Component comp = resultsTable.prepareRenderer(
153  resultsTable.getCellRenderer(row, valueColIndex), row, valueColIndex);
154  final int rowHeight;
155  if (comp instanceof JTextComponent) {
156  final JTextComponent tc = (JTextComponent) comp;
157  final View rootView = tc.getUI().getRootView(tc);
158  java.awt.Insets i = tc.getInsets(null);
159  rootView.setSize(resultsTable.getColumnModel().getColumn(valueColIndex)
160  .getPreferredWidth() - i.left - i.right,
161  Integer.MAX_VALUE);
162  rowHeight = (int) rootView.getPreferredSpan(View.Y_AXIS);
163  } else {
164  rowHeight = comp.getPreferredSize().height;
165  }
166  if (rowHeight > 0) {
167  resultsTable.setRowHeight(row, rowHeight + CELL_BOTTOM_MARGIN);
168  }
169  }
170  }
171  }
172 
176  private void updateColumnSizes() {
177  Enumeration<TableColumn> columns = resultsTable.getColumnModel().getColumns();
178  while (columns.hasMoreElements()) {
179  TableColumn col = columns.nextElement();
180  if (col.getHeaderValue().equals(COLUMN_HEADERS[0])) {
181  col.setPreferredWidth(COLUMN_WIDTHS[0]);
182  } else if (col.getHeaderValue().equals(COLUMN_HEADERS[1])) {
183  col.setPreferredWidth(COLUMN_WIDTHS[1]);
184  } else if (col.getHeaderValue().equals(COLUMN_HEADERS[2])) {
185  col.setPreferredWidth(COLUMN_WIDTHS[2]);
186  }
187  }
188  }
189 
195  @SuppressWarnings("unchecked")
196  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
197  private void initComponents() {
198 
199  rightClickMenu = new javax.swing.JPopupMenu();
200  copyMenuItem = new javax.swing.JMenuItem();
201  selectAllMenuItem = new javax.swing.JMenuItem();
202  jPanel1 = new javax.swing.JPanel();
203  totalPageLabel = new javax.swing.JLabel();
204  ofLabel = new javax.swing.JLabel();
205  currentPageLabel = new javax.swing.JLabel();
206  pageLabel = new javax.swing.JLabel();
207  nextPageButton = new javax.swing.JButton();
208  pageLabel2 = new javax.swing.JLabel();
209  prevPageButton = new javax.swing.JButton();
210  resultsTableScrollPane = new javax.swing.JScrollPane();
211  artifactLabel = new javax.swing.JLabel();
212 
213  copyMenuItem.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.copyMenuItem.text")); // NOI18N
214  rightClickMenu.add(copyMenuItem);
215 
216  selectAllMenuItem.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.selectAllMenuItem.text")); // NOI18N
217  rightClickMenu.add(selectAllMenuItem);
218 
219  setPreferredSize(new java.awt.Dimension(622, 58));
220 
221  jPanel1.setPreferredSize(new java.awt.Dimension(620, 58));
222 
223  totalPageLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.totalPageLabel.text")); // NOI18N
224 
225  ofLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.ofLabel.text")); // NOI18N
226 
227  currentPageLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.currentPageLabel.text")); // NOI18N
228  currentPageLabel.setMaximumSize(new java.awt.Dimension(18, 14));
229  currentPageLabel.setMinimumSize(new java.awt.Dimension(18, 14));
230  currentPageLabel.setPreferredSize(new java.awt.Dimension(18, 14));
231 
232  pageLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.pageLabel.text")); // NOI18N
233  pageLabel.setMaximumSize(new java.awt.Dimension(33, 14));
234  pageLabel.setMinimumSize(new java.awt.Dimension(33, 14));
235  pageLabel.setPreferredSize(new java.awt.Dimension(33, 14));
236 
237  nextPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"))); // NOI18N
238  nextPageButton.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.nextPageButton.text")); // NOI18N
239  nextPageButton.setBorderPainted(false);
240  nextPageButton.setContentAreaFilled(false);
241  nextPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); // NOI18N
242  nextPageButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
243  nextPageButton.setPreferredSize(new java.awt.Dimension(23, 23));
244  nextPageButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"))); // NOI18N
245  nextPageButton.addActionListener(new java.awt.event.ActionListener() {
246  public void actionPerformed(java.awt.event.ActionEvent evt) {
247  nextPageButtonActionPerformed(evt);
248  }
249  });
250 
251  pageLabel2.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.pageLabel2.text")); // NOI18N
252  pageLabel2.setMaximumSize(new java.awt.Dimension(29, 14));
253  pageLabel2.setMinimumSize(new java.awt.Dimension(29, 14));
254  pageLabel2.setPreferredSize(new java.awt.Dimension(29, 14));
255 
256  prevPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); // NOI18N
257  prevPageButton.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.prevPageButton.text")); // NOI18N
258  prevPageButton.setBorderPainted(false);
259  prevPageButton.setContentAreaFilled(false);
260  prevPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); // NOI18N
261  prevPageButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
262  prevPageButton.setPreferredSize(new java.awt.Dimension(23, 23));
263  prevPageButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"))); // NOI18N
264  prevPageButton.addActionListener(new java.awt.event.ActionListener() {
265  public void actionPerformed(java.awt.event.ActionEvent evt) {
266  prevPageButtonActionPerformed(evt);
267  }
268  });
269 
270  resultsTableScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
271  resultsTableScrollPane.setPreferredSize(new java.awt.Dimension(620, 34));
272 
273  javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
274  jPanel1.setLayout(jPanel1Layout);
275  jPanel1Layout.setHorizontalGroup(
276  jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
277  .addGroup(jPanel1Layout.createSequentialGroup()
278  .addContainerGap()
279  .addComponent(pageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE)
280  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
281  .addComponent(currentPageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
282  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
283  .addComponent(ofLabel)
284  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
285  .addComponent(totalPageLabel)
286  .addGap(41, 41, 41)
287  .addComponent(pageLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 38, javax.swing.GroupLayout.PREFERRED_SIZE)
288  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
289  .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
290  .addGap(0, 0, 0)
291  .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
292  .addContainerGap(366, Short.MAX_VALUE))
293  .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
294  .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
295  .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
296  .addContainerGap(280, Short.MAX_VALUE)
297  .addComponent(artifactLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 258, javax.swing.GroupLayout.PREFERRED_SIZE)
298  .addContainerGap(84, Short.MAX_VALUE)))
299  );
300  jPanel1Layout.setVerticalGroup(
301  jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
302  .addGroup(jPanel1Layout.createSequentialGroup()
303  .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
304  .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
305  .addComponent(pageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
306  .addComponent(currentPageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
307  .addComponent(ofLabel)
308  .addComponent(totalPageLabel))
309  .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
310  .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
311  .addComponent(pageLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
312  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
313  .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 29, Short.MAX_VALUE)
314  .addGap(0, 0, 0))
315  .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
316  .addGroup(jPanel1Layout.createSequentialGroup()
317  .addComponent(artifactLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
318  .addGap(0, 401, Short.MAX_VALUE)))
319  );
320 
321  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
322  this.setLayout(layout);
323  layout.setHorizontalGroup(
324  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
325  .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 622, Short.MAX_VALUE)
326  );
327  layout.setVerticalGroup(
328  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
329  .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
330  );
331  }// </editor-fold>//GEN-END:initComponents
332 
333  private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed
334  currentPage = currentPage + 1;
335  currentPageLabel.setText(Integer.toString(currentPage));
336  artifactLabel.setText(artifactTableContents.get(currentPage - 1).getArtifactDisplayName());
337  startNewTask(new SelectedArtifactChangedTask(currentPage));
338  }//GEN-LAST:event_nextPageButtonActionPerformed
339 
340  private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevPageButtonActionPerformed
341  currentPage = currentPage - 1;
342  currentPageLabel.setText(Integer.toString(currentPage));
343  artifactLabel.setText(artifactTableContents.get(currentPage - 1).getArtifactDisplayName());
344  startNewTask(new SelectedArtifactChangedTask(currentPage));
345  }//GEN-LAST:event_prevPageButtonActionPerformed
346 
347  // Variables declaration - do not modify//GEN-BEGIN:variables
348  private javax.swing.JLabel artifactLabel;
349  private javax.swing.JMenuItem copyMenuItem;
350  private javax.swing.JLabel currentPageLabel;
351  private javax.swing.JPanel jPanel1;
352  private javax.swing.JButton nextPageButton;
353  private javax.swing.JLabel ofLabel;
354  private javax.swing.JLabel pageLabel;
355  private javax.swing.JLabel pageLabel2;
356  private javax.swing.JButton prevPageButton;
357  private javax.swing.JScrollPane resultsTableScrollPane;
358  private javax.swing.JPopupMenu rightClickMenu;
359  private javax.swing.JMenuItem selectAllMenuItem;
360  private javax.swing.JLabel totalPageLabel;
361  // End of variables declaration//GEN-END:variables
362  private ETable resultsTable;
363 
364  private void customizeComponents() {
365  resultsTable.setComponentPopupMenu(rightClickMenu);
366  ActionListener actList = new ActionListener() {
367  @Override
368  public void actionPerformed(ActionEvent e) {
369  JMenuItem jmi = (JMenuItem) e.getSource();
370  if (jmi.equals(copyMenuItem)) {
371  StringBuilder selectedText = new StringBuilder(512);
372  for (int row : resultsTable.getSelectedRows()) {
373  for (int col : resultsTable.getSelectedColumns()) {
374  selectedText.append((String) resultsTable.getValueAt(row, col));
375  selectedText.append("\t");
376  }
377  //if its the last row selected don't add a new line
378  if (row != resultsTable.getSelectedRows()[resultsTable.getSelectedRows().length - 1]) {
379  selectedText.append(System.lineSeparator());
380  }
381  }
382  Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(selectedText.toString()), null);
383  } else if (jmi.equals(selectAllMenuItem)) {
384  resultsTable.selectAll();
385  }
386  }
387  };
388  copyMenuItem.addActionListener(actList);
389 
390  selectAllMenuItem.addActionListener(actList);
391  }
392 
396  private void resetComponents() {
397  currentPage = 1;
398  currentPageLabel.setText("");
399  artifactLabel.setText("");
400  totalPageLabel.setText("");
401  ((DefaultTableModel) resultsTable.getModel()).setRowCount(0);
402  prevPageButton.setEnabled(false);
403  nextPageButton.setEnabled(false);
404  currentNode = null;
405  }
406 
407  @Override
408  public void setNode(Node selectedNode) {
409  if (currentNode == selectedNode) {
410  return;
411  }
412  currentNode = selectedNode;
413 
414  // Make sure there is a node. Null might be passed to reset the viewer.
415  if (selectedNode == null) {
416  return;
417  }
418 
419  // Make sure the node is of the correct type.
420  Lookup lookup = selectedNode.getLookup();
421  Content content = lookup.lookup(Content.class);
422  if (content == null) {
423  return;
424  }
425 
426  startNewTask(new SelectedNodeChangedTask(selectedNode));
427  }
428 
429  @Override
430  public String getTitle() {
431  return NbBundle.getMessage(this.getClass(), "DataContentViewerArtifact.title");
432  }
433 
434  @Override
435  public String getToolTip() {
436  return NbBundle.getMessage(this.getClass(), "DataContentViewerArtifact.toolTip");
437  }
438 
439  @Override
440  public DataContentViewer createInstance() {
441  return new DataContentViewerArtifact();
442  }
443 
444  @Override
445  public Component getComponent() {
446  return this;
447  }
448 
449  @Override
450  public void resetComponent() {
451  resetComponents();
452  }
453 
454  @Override
455  public boolean isSupported(Node node) {
456  if (node == null) {
457  return false;
458  }
459 
460  for (Content content : node.getLookup().lookupAll(Content.class)) {
461  if ( (content != null) && (!(content instanceof BlackboardArtifact)) ){
462  try {
463  return content.getAllArtifactsCount() > 0;
464  } catch (TskException ex) {
465  logger.log(Level.SEVERE, "Couldn't get count of BlackboardArtifacts for content", ex); //NON-NLS
466  }
467  }
468  }
469  return false;
470  }
471 
472  @Override
473  public int isPreferred(Node node) {
474  BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class);
475  // low priority if node doesn't have an artifact (meaning it was found from normal directory
476  // browsing, or if the artifact is something that means the user really wants to see the original
477  // file and not more details about the artifact
478  if ((artifact == null)
479  || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID())
480  || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID())) {
481  return 3;
482  } else {
483  return 5;
484  }
485  }
486 
491  private class ResultsTableArtifact {
492 
493  private final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
494  private String[][] rowData = null;
495  private final String artifactDisplayName;
496  private final Content content;
497 
498  ResultsTableArtifact(BlackboardArtifact artifact, Content content) {
499  artifactDisplayName = artifact.getDisplayName();
500  this.content = content;
501  addRows(artifact);
502  }
503 
504  ResultsTableArtifact(String errorMsg) {
505  artifactDisplayName = errorMsg;
506  rowData = new String[1][3];
507  rowData[0] = new String[]{"", errorMsg, ""};
508  content = null;
509  }
510 
511  private String[][] getRows() {
512  return rowData;
513  }
514 
515  private void addRows(BlackboardArtifact artifact) {
516  List<String[]> rowsToAdd = new ArrayList<>();
517  try {
518  /*
519  * Add rows for each attribute.
520  */
521  for (BlackboardAttribute attr : artifact.getAttributes()) {
522  /*
523  * Attribute value column.
524  */
525  String value = "";
526  switch (attr.getAttributeType().getValueType()) {
527  case STRING:
528  case INTEGER:
529  case LONG:
530  case DOUBLE:
531  case BYTE:
532  default:
533  value = attr.getDisplayString();
534  break;
535  // Use Autopsy date formatting settings, not TSK defaults
536  case DATETIME:
537  long epoch = attr.getValueLong();
538  value = "0000-00-00 00:00:00";
539  if (null != content && 0 != epoch) {
540  dateFormatter.setTimeZone(ContentUtils.getTimeZone(content));
541  value = dateFormatter.format(new java.util.Date(epoch * 1000));
542  }
543  break;
544  }
545  /*
546  * Attribute sources column.
547  */
548  String sources = StringUtils.join(attr.getSources(), ", ");
549  rowsToAdd.add(new String[]{attr.getAttributeType().getDisplayName(), value, sources});
550  }
551  /*
552  * Add a row for the source content path.
553  */
554  String path = "";
555  try {
556  if (null != content) {
557  path = content.getUniquePath();
558  }
559  } catch (TskCoreException ex) {
560  logger.log(Level.SEVERE, String.format("Error getting source content path for artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex);
561  path = Bundle.DataContentViewerArtifact_failedToGetSourcePath_message();
562  }
563  rowsToAdd.add(new String[]{"Source File Path", path, ""});
564  /*
565  * Add a row for the artifact id.
566  */
567  rowsToAdd.add(new String[]{"Artifact ID", Long.toString(artifact.getArtifactID()), ""});
568  } catch (TskCoreException ex) {
569  rowsToAdd.add(new String[]{"", Bundle.DataContentViewerArtifact_failedToGetAttributes_message(), ""});
570  }
571  rowData = rowsToAdd.toArray(new String[0][0]);
572  }
573 
577  String getArtifactDisplayName() {
578  return artifactDisplayName;
579  }
580  }
581 
586  private class ViewUpdate {
587 
588  int numberOfPages;
589  int currentPage;
590  ResultsTableArtifact tableContents;
591 
592  ViewUpdate(int numberOfPages, int currentPage, ResultsTableArtifact contents) {
593  this.currentPage = currentPage;
594  this.numberOfPages = numberOfPages;
595  this.tableContents = contents;
596  }
597 
598  ViewUpdate(int numberOfPages, int currentPage, String errorMsg) {
599  this.currentPage = currentPage;
600  this.numberOfPages = numberOfPages;
601  this.tableContents = new ResultsTableArtifact(errorMsg);
602  }
603  }
604 
612  private void updateView(ViewUpdate viewUpdate) {
613  this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
614 
615  nextPageButton.setEnabled(viewUpdate.currentPage < viewUpdate.numberOfPages);
616  prevPageButton.setEnabled(viewUpdate.currentPage > 1);
617  currentPage = viewUpdate.currentPage;
618  totalPageLabel.setText(Integer.toString(viewUpdate.numberOfPages));
619  currentPageLabel.setText(Integer.toString(currentPage));
620  artifactLabel.setText(viewUpdate.tableContents.getArtifactDisplayName());
621  DefaultTableModel tModel = ((DefaultTableModel) resultsTable.getModel());
622  tModel.setDataVector(viewUpdate.tableContents.getRows(), COLUMN_HEADERS);
623  updateColumnSizes();
624  updateRowHeights();
625  resultsTable.clearSelection();
626 
627  this.setCursor(null);
628  }
629 
636  private synchronized void startNewTask(SwingWorker<ViewUpdate, Void> task) {
637  String[][] waitRow = new String[1][3];
638  waitRow[0] = new String[]{"", WAIT_TEXT, ""};
639  DefaultTableModel tModel = ((DefaultTableModel) resultsTable.getModel());
640  tModel.setDataVector(waitRow, COLUMN_HEADERS);
641  updateColumnSizes();
642  updateRowHeights();
643  resultsTable.clearSelection();
644  // The output of the previous task is no longer relevant.
645  if (currentTask != null) {
646  // This call sets a cancellation flag. It does not terminate the background thread running the task.
647  // The task must check the cancellation flag and react appropriately.
648  currentTask.cancel(false);
649  }
650 
651  // Start the new task.
652  currentTask = task;
653  currentTask.execute();
654  }
655 
662  private void setArtifactContents(List<ResultsTableArtifact> artifactList) {
663  synchronized (lock) {
664  this.artifactTableContents = artifactList;
665  }
666  }
667 
673  private List<ResultsTableArtifact> getArtifactContents() {
674  synchronized (lock) {
675  return artifactTableContents;
676  }
677  }
678 
684  private class SelectedNodeChangedTask extends SwingWorker<ViewUpdate, Void> {
685 
686  private final Node selectedNode;
687 
688  SelectedNodeChangedTask(Node selectedNode) {
689  this.selectedNode = selectedNode;
690  }
691 
692  @Override
694  // Get the lookup for the node for access to its underlying content and
695  // blackboard artifact, if any.
696  Lookup lookup = selectedNode.getLookup();
697 
698  // Get the content. We may get BlackboardArtifacts, ignore those here.
699  ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
700  Collection<? extends Content> contents = lookup.lookupAll(Content.class);
701  if (contents.isEmpty()) {
702  return new ViewUpdate(getArtifactContents().size(), currentPage, ERROR_TEXT);
703  }
704  Content underlyingContent = null;
705  for (Content content : contents) {
706  if ( (content != null) && (!(content instanceof BlackboardArtifact)) ) {
707  // Get all of the blackboard artifacts associated with the content. These are what this
708  // viewer displays.
709  try {
710  artifacts = content.getAllArtifacts();
711  underlyingContent = content;
712  break;
713  } catch (TskException ex) {
714  logger.log(Level.SEVERE, "Couldn't get artifacts", ex); //NON-NLS
715  return new ViewUpdate(getArtifactContents().size(), currentPage, ERROR_TEXT);
716  }
717  }
718  }
719 
720  if (isCancelled()) {
721  return null;
722  }
723 
724  // Build the new artifact contents cache.
725  ArrayList<ResultsTableArtifact> artifactContents = new ArrayList<>();
726  for (BlackboardArtifact artifact : artifacts) {
727  artifactContents.add(new ResultsTableArtifact(artifact, underlyingContent));
728  }
729 
730  // If the node has an underlying blackboard artifact, show it. If not,
731  // show the first artifact.
732  int index = 0;
733  BlackboardArtifact artifact = lookup.lookup(BlackboardArtifact.class);
734  if (artifact != null) {
735  index = artifacts.indexOf(artifact);
736  if (index == -1) {
737  index = 0;
738  } else {
739  // if the artifact has an ASSOCIATED ARTIFACT, then we display the associated artifact instead
740  try {
741  for (BlackboardAttribute attr : artifact.getAttributes()) {
742  if (attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) {
743  long assocArtifactId = attr.getValueLong();
744  int assocArtifactIndex = -1;
745  for (BlackboardArtifact art : artifacts) {
746  if (assocArtifactId == art.getArtifactID()) {
747  assocArtifactIndex = artifacts.indexOf(art);
748  break;
749  }
750  }
751  if (assocArtifactIndex >= 0) {
752  index = assocArtifactIndex;
753  }
754  break;
755  }
756  }
757  } catch (TskCoreException ex) {
758  logger.log(Level.WARNING, "Couldn't get associated artifact to display in Content Viewer.", ex); //NON-NLS
759  }
760  }
761 
762  }
763 
764  if (isCancelled()) {
765  return null;
766  }
767 
768  // Add one to the index of the artifact content for the corresponding page index.
769  ViewUpdate viewUpdate = new ViewUpdate(artifactContents.size(), index + 1, artifactContents.get(index));
770 
771  // It may take a considerable amount of time to fetch the attributes of the selected artifact
772  if (isCancelled()) {
773  return null;
774  }
775 
776  // Update the artifact contents cache.
777  setArtifactContents(artifactContents);
778 
779  return viewUpdate;
780  }
781 
782  @Override
783  protected void done() {
784  if (!isCancelled()) {
785  try {
786  ViewUpdate viewUpdate = get();
787  if (viewUpdate != null) {
788  updateView(viewUpdate);
789  }
790  } catch (InterruptedException | ExecutionException ex) {
791  logger.log(Level.WARNING, "Artifact display task unexpectedly interrupted or failed", ex); //NON-NLS
792  }
793  }
794  }
795  }
796 
802  private class SelectedArtifactChangedTask extends SwingWorker<ViewUpdate, Void> {
803 
804  private final int pageIndex;
805 
806  SelectedArtifactChangedTask(final int pageIndex) {
807  this.pageIndex = pageIndex;
808  }
809 
810  @Override
812  // Get the artifact content to display from the cache. Note that one must be subtracted from the
813  // page index to get the corresponding artifact content index.
814  List<ResultsTableArtifact> artifactContents = getArtifactContents();
815  ResultsTableArtifact artifactContent = artifactContents.get(pageIndex - 1);
816 
817  // It may take a considerable amount of time to fetch the attributes of the selected artifact so check for cancellation.
818  if (isCancelled()) {
819  return null;
820  }
821 
822  return new ViewUpdate(artifactContents.size(), pageIndex, artifactContent);
823  }
824 
825  @Override
826  protected void done() {
827  if (!isCancelled()) {
828  try {
829  ViewUpdate viewUpdate = get();
830  if (viewUpdate != null) {
831  updateView(viewUpdate);
832  }
833  } catch (InterruptedException | ExecutionException ex) {
834  logger.log(Level.WARNING, "Artifact display task unexpectedly interrupted or failed", ex); //NON-NLS
835  }
836  }
837  }
838  }
839 
843  private class MultiLineTableCellRenderer implements javax.swing.table.TableCellRenderer {
844 
845  @Override
846  public Component getTableCellRendererComponent(javax.swing.JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
847  javax.swing.JTextArea jtex = new javax.swing.JTextArea();
848  if (value instanceof String) {
849  jtex.setText((String) value);
850  jtex.setLineWrap(true);
851  jtex.setWrapStyleWord(true);
852  }
853  //cell backgroud color when selected
854  if (isSelected) {
855  jtex.setBackground(javax.swing.UIManager.getColor("Table.selectionBackground"));
856  } else {
857  jtex.setBackground(javax.swing.UIManager.getColor("Table.background"));
858  }
859  return jtex;
860  }
861  }
862 }
synchronized void startNewTask(SwingWorker< ViewUpdate, Void > task)
void setArtifactContents(List< ResultsTableArtifact > artifactList)
Component getTableCellRendererComponent(javax.swing.JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

Copyright © 2012-2016 Basis Technology. Generated on: Tue Feb 20 2018
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.