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