19 package org.sleuthkit.autopsy.corecomponents;
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.List;
30 import java.util.concurrent.ExecutionException;
31 import java.util.logging.Level;
32 import javax.swing.JMenuItem;
33 import javax.swing.SwingWorker;
34 import javax.swing.table.DefaultTableModel;
35 import org.apache.commons.lang.StringUtils;
36 import org.openide.nodes.Node;
37 import org.openide.util.Lookup;
38 import org.openide.util.NbBundle;
39 import org.openide.util.lookup.ServiceProvider;
44 import org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
49 import org.netbeans.swing.etable.ETable;
56 @ServiceProvider(service = DataContentViewer.class, position = 3)
60 "DataContentViewerArtifact.attrsTableHeader.type=Type",
61 "DataContentViewerArtifact.attrsTableHeader.value=Value",
62 "DataContentViewerArtifact.attrsTableHeader.sources=Source(s)",
63 "DataContentViewerArtifact.failedToGetSourcePath.message=Failed to get source file path from case database",
64 "DataContentViewerArtifact.failedToGetAttributes.message=Failed to get some or all attributes from case database"
68 private final static String ERROR_TEXT = NbBundle.getMessage(
DataContentViewerArtifact.class,
"DataContentViewerArtifact.errorText");
70 private int currentPage = 1;
71 private final Object lock =
new Object();
73 SwingWorker<ViewUpdate, Void> currentTask;
74 private static final String[] COLUMN_HEADERS = {
75 Bundle.DataContentViewerArtifact_attrsTableHeader_type(),
76 Bundle.DataContentViewerArtifact_attrsTableHeader_value(),
77 Bundle.DataContentViewerArtifact_attrsTableHeader_sources()};
82 resultsTableScrollPane.setViewportView(resultsTable);
83 customizeComponents();
88 resultsTable =
new ETable();
89 resultsTable.setModel(
new javax.swing.table.DefaultTableModel() {
90 private static final long serialVersionUID = 1L;
92 public boolean isCellEditable(
int rowIndex,
int columnIndex) {
96 resultsTable.setCellSelectionEnabled(
true);
97 resultsTable.getColumnModel().getSelectionModel().setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION);
102 resultsTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_NEXT_COLUMN);
103 if (resultsTable.getColumnModel().getColumnCount() > 0) {
104 resultsTable.getColumnModel().getColumn(0).setPreferredWidth(100);
105 resultsTable.getColumnModel().getColumn(1).setPreferredWidth(800);
106 resultsTable.getColumnModel().getColumn(2).setPreferredWidth(100);
115 @SuppressWarnings(
"unchecked")
117 private
void initComponents() {
119 rightClickMenu =
new javax.swing.JPopupMenu();
120 copyMenuItem =
new javax.swing.JMenuItem();
121 selectAllMenuItem =
new javax.swing.JMenuItem();
122 jScrollPane1 =
new javax.swing.JScrollPane();
123 jPanel1 =
new javax.swing.JPanel();
124 totalPageLabel =
new javax.swing.JLabel();
125 ofLabel =
new javax.swing.JLabel();
126 currentPageLabel =
new javax.swing.JLabel();
127 pageLabel =
new javax.swing.JLabel();
128 nextPageButton =
new javax.swing.JButton();
129 pageLabel2 =
new javax.swing.JLabel();
130 prevPageButton =
new javax.swing.JButton();
131 resultsTableScrollPane =
new javax.swing.JScrollPane();
132 artifactLabel =
new javax.swing.JLabel();
134 copyMenuItem.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerArtifact.class,
"DataContentViewerArtifact.copyMenuItem.text"));
135 rightClickMenu.add(copyMenuItem);
137 selectAllMenuItem.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerArtifact.class,
"DataContentViewerArtifact.selectAllMenuItem.text"));
138 rightClickMenu.add(selectAllMenuItem);
140 setPreferredSize(
new java.awt.Dimension(622, 58));
142 jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
143 jScrollPane1.setPreferredSize(
new java.awt.Dimension(622, 58));
145 jPanel1.setPreferredSize(
new java.awt.Dimension(620, 58));
147 totalPageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerArtifact.class,
"DataContentViewerArtifact.totalPageLabel.text"));
151 currentPageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerArtifact.class,
"DataContentViewerArtifact.currentPageLabel.text"));
152 currentPageLabel.setMaximumSize(
new java.awt.Dimension(18, 14));
153 currentPageLabel.setMinimumSize(
new java.awt.Dimension(18, 14));
154 currentPageLabel.setPreferredSize(
new java.awt.Dimension(18, 14));
157 pageLabel.setMaximumSize(
new java.awt.Dimension(33, 14));
158 pageLabel.setMinimumSize(
new java.awt.Dimension(33, 14));
159 pageLabel.setPreferredSize(
new java.awt.Dimension(33, 14));
161 nextPageButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png")));
162 nextPageButton.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerArtifact.class,
"DataContentViewerArtifact.nextPageButton.text"));
163 nextPageButton.setBorderPainted(
false);
164 nextPageButton.setContentAreaFilled(
false);
165 nextPageButton.setDisabledIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png")));
166 nextPageButton.setMargin(
new java.awt.Insets(2, 0, 2, 0));
167 nextPageButton.setPreferredSize(
new java.awt.Dimension(23, 23));
168 nextPageButton.setRolloverIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png")));
169 nextPageButton.addActionListener(
new java.awt.event.ActionListener() {
170 public void actionPerformed(java.awt.event.ActionEvent evt) {
171 nextPageButtonActionPerformed(evt);
176 pageLabel2.setMaximumSize(
new java.awt.Dimension(29, 14));
177 pageLabel2.setMinimumSize(
new java.awt.Dimension(29, 14));
178 pageLabel2.setPreferredSize(
new java.awt.Dimension(29, 14));
180 prevPageButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back.png")));
181 prevPageButton.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerArtifact.class,
"DataContentViewerArtifact.prevPageButton.text"));
182 prevPageButton.setBorderPainted(
false);
183 prevPageButton.setContentAreaFilled(
false);
184 prevPageButton.setDisabledIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png")));
185 prevPageButton.setMargin(
new java.awt.Insets(2, 0, 2, 0));
186 prevPageButton.setPreferredSize(
new java.awt.Dimension(23, 23));
187 prevPageButton.setRolloverIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png")));
188 prevPageButton.addActionListener(
new java.awt.event.ActionListener() {
189 public void actionPerformed(java.awt.event.ActionEvent evt) {
190 prevPageButtonActionPerformed(evt);
194 resultsTableScrollPane.setPreferredSize(
new java.awt.Dimension(620, 271));
196 javax.swing.GroupLayout jPanel1Layout =
new javax.swing.GroupLayout(jPanel1);
197 jPanel1.setLayout(jPanel1Layout);
198 jPanel1Layout.setHorizontalGroup(
199 jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
200 .addGroup(jPanel1Layout.createSequentialGroup()
202 .addComponent(pageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE)
203 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
204 .addComponent(currentPageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
205 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
206 .addComponent(ofLabel)
207 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
208 .addComponent(totalPageLabel)
210 .addComponent(pageLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 38, javax.swing.GroupLayout.PREFERRED_SIZE)
211 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
212 .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
214 .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
215 .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
216 .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
217 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
218 .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
219 .addContainerGap(277, Short.MAX_VALUE)
220 .addComponent(artifactLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 258, javax.swing.GroupLayout.PREFERRED_SIZE)
221 .addContainerGap(85, Short.MAX_VALUE)))
223 jPanel1Layout.setVerticalGroup(
224 jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
225 .addGroup(jPanel1Layout.createSequentialGroup()
226 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
227 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
228 .addComponent(pageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
229 .addComponent(currentPageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
230 .addComponent(ofLabel)
231 .addComponent(totalPageLabel))
232 .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
233 .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
234 .addComponent(pageLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
235 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
236 .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 34, Short.MAX_VALUE))
237 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
238 .addGroup(jPanel1Layout.createSequentialGroup()
239 .addComponent(artifactLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
240 .addGap(0, 40, Short.MAX_VALUE)))
243 jScrollPane1.setViewportView(jPanel1);
245 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
246 this.setLayout(layout);
247 layout.setHorizontalGroup(
248 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
249 .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
251 layout.setVerticalGroup(
252 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
253 .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
258 currentPage = currentPage - 1;
259 currentPageLabel.setText(Integer.toString(currentPage));
260 artifactLabel.setText(artifactTableContents.get(currentPage - 1).getArtifactDisplayName());
265 currentPage = currentPage + 1;
266 currentPageLabel.setText(Integer.toString(currentPage));
267 artifactLabel.setText(artifactTableContents.get(currentPage - 1).getArtifactDisplayName());
290 resultsTable.setComponentPopupMenu(rightClickMenu);
291 ActionListener actList =
new ActionListener() {
293 public void actionPerformed(ActionEvent e) {
294 JMenuItem jmi = (JMenuItem) e.getSource();
295 if (jmi.equals(copyMenuItem)) {
296 StringBuilder selectedText =
new StringBuilder(512);
297 for (
int row : resultsTable.getSelectedRows()) {
298 for (
int col : resultsTable.getSelectedColumns()) {
299 selectedText.append((String) resultsTable.getValueAt(row, col));
300 selectedText.append(
"\t");
303 if (row != resultsTable.getSelectedRows()[resultsTable.getSelectedRows().length - 1]) {
304 selectedText.append(System.lineSeparator());
307 Toolkit.getDefaultToolkit().getSystemClipboard().setContents(
new StringSelection(selectedText.toString()), null);
308 }
else if (jmi.equals(selectAllMenuItem)) {
309 resultsTable.selectAll();
313 copyMenuItem.addActionListener(actList);
315 selectAllMenuItem.addActionListener(actList);
323 currentPageLabel.setText(
"");
324 artifactLabel.setText(
"");
325 totalPageLabel.setText(
"");
326 ((DefaultTableModel) resultsTable.getModel()).setRowCount(0);
327 prevPageButton.setEnabled(
false);
328 nextPageButton.setEnabled(
false);
334 if (currentNode == selectedNode) {
337 currentNode = selectedNode;
340 if (selectedNode == null) {
345 Lookup lookup = selectedNode.getLookup();
346 Content content = lookup.lookup(Content.class);
347 if (content == null) {
356 return NbBundle.getMessage(this.getClass(),
"DataContentViewerArtifact.title");
361 return NbBundle.getMessage(this.getClass(),
"DataContentViewerArtifact.toolTip");
385 Content content = node.getLookup().lookup(Content.class);
386 if (content != null) {
388 return content.getAllArtifactsCount() > 0;
389 }
catch (TskException ex) {
390 logger.log(Level.WARNING,
"Couldn't get count of BlackboardArtifacts for content", ex);
398 BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class);
402 if ((artifact == null)
403 || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID())
404 || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID())) {
417 private final SimpleDateFormat dateFormatter =
new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
418 private String[][] rowData = null;
422 artifactDisplayName = artifact.getDisplayName();
428 artifactDisplayName = errorMsg;
429 rowData =
new String[1][3];
430 rowData[0] =
new String[]{
"", errorMsg,
""};
438 private void addRows(BlackboardArtifact artifact) {
439 List<String[]> rowsToAdd =
new ArrayList<>();
441 Content content = artifact.getSleuthkitCase().getContentById(artifact.getObjectID());
445 for (BlackboardAttribute attr : artifact.getAttributes()) {
450 switch (attr.getAttributeType().getValueType()) {
457 value = attr.getDisplayString();
461 long epoch = attr.getValueLong();
462 value =
"0000-00-00 00:00:00";
463 if (null != content && 0 != epoch) {
465 value = dateFormatter.format(
new java.util.Date(epoch * 1000));
472 String sources = StringUtils.join(attr.getSources(),
", ");
473 rowsToAdd.add(
new String[]{attr.getAttributeType().getDisplayName(), value, sources});
480 if (null != content) {
481 path = content.getUniquePath();
483 }
catch (TskCoreException ex) {
484 logger.log(Level.SEVERE, String.format(
"Error getting source content path for artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex);
485 path = Bundle.DataContentViewerArtifact_failedToGetSourcePath_message();
487 rowsToAdd.add(
new String[]{
"Source File Path", path,
""});
491 rowsToAdd.add(
new String[]{
"Artifact ID", Long.toString(artifact.getArtifactID()),
""});
492 }
catch (TskCoreException ex) {
493 rowsToAdd.add(
new String[]{
"", Bundle.DataContentViewerArtifact_failedToGetAttributes_message(),
""});
495 rowData = rowsToAdd.toArray(
new String[0][0]);
501 String getArtifactDisplayName() {
502 return artifactDisplayName;
517 this.currentPage = currentPage;
518 this.numberOfPages = numberOfPages;
519 this.tableContents = contents;
522 ViewUpdate(
int numberOfPages,
int currentPage, String errorMsg) {
523 this.currentPage = currentPage;
524 this.numberOfPages = numberOfPages;
537 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
539 nextPageButton.setEnabled(viewUpdate.currentPage < viewUpdate.numberOfPages);
540 prevPageButton.setEnabled(viewUpdate.currentPage > 1);
541 currentPage = viewUpdate.currentPage;
542 totalPageLabel.setText(Integer.toString(viewUpdate.numberOfPages));
543 currentPageLabel.setText(Integer.toString(currentPage));
544 artifactLabel.setText(viewUpdate.tableContents.getArtifactDisplayName());
549 DefaultTableModel tModel = ((DefaultTableModel) resultsTable.getModel());
550 tModel.setDataVector(viewUpdate.tableContents.
getRows(), COLUMN_HEADERS);
552 resultsTable.clearSelection();
554 this.setCursor(null);
563 private synchronized void startNewTask(SwingWorker<ViewUpdate, Void> task) {
564 String[][] waitRow =
new String[1][3];
565 waitRow[0] =
new String[]{
"", WAIT_TEXT,
""};
566 DefaultTableModel tModel = ((DefaultTableModel) resultsTable.getModel());
567 tModel.setDataVector(waitRow, COLUMN_HEADERS);
569 resultsTable.clearSelection();
571 if (currentTask != null) {
574 currentTask.cancel(
false);
579 currentTask.execute();
589 synchronized (lock) {
590 this.artifactTableContents = artifactList;
600 synchronized (lock) {
601 return artifactTableContents;
615 this.selectedNode = selectedNode;
622 Lookup lookup = selectedNode.getLookup();
625 Content content = lookup.lookup(Content.class);
626 if (content == null) {
627 return new ViewUpdate(getArtifactContents().size(), currentPage, ERROR_TEXT);
632 ArrayList<BlackboardArtifact> artifacts;
634 artifacts = content.getAllArtifacts();
635 }
catch (TskException ex) {
636 logger.log(Level.WARNING,
"Couldn't get artifacts", ex);
637 return new ViewUpdate(getArtifactContents().size(), currentPage, ERROR_TEXT);
645 ArrayList<ResultsTableArtifact> artifactContents =
new ArrayList<>();
646 for (BlackboardArtifact artifact : artifacts) {
653 BlackboardArtifact artifact = lookup.lookup(BlackboardArtifact.class);
654 if (artifact != null) {
655 index = artifacts.indexOf(artifact);
661 for (BlackboardAttribute attr : artifact.getAttributes()) {
662 if (attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) {
663 long assocArtifactId = attr.getValueLong();
664 int assocArtifactIndex = -1;
665 for (BlackboardArtifact art : artifacts) {
666 if (assocArtifactId == art.getArtifactID()) {
667 assocArtifactIndex = artifacts.indexOf(art);
671 if (assocArtifactIndex >= 0) {
672 index = assocArtifactIndex;
677 }
catch (TskCoreException ex) {
678 logger.log(Level.WARNING,
"Couldn't get associated artifact to display in Content Viewer.", ex);
689 ViewUpdate viewUpdate =
new ViewUpdate(artifactContents.size(), index + 1, artifactContents.get(index));
697 setArtifactContents(artifactContents);
704 if (!isCancelled()) {
707 if (viewUpdate != null) {
708 updateView(viewUpdate);
710 }
catch (InterruptedException | ExecutionException ex) {
711 logger.log(Level.WARNING,
"Artifact display task unexpectedly interrupted or failed", ex);
727 this.pageIndex = pageIndex;
734 List<ResultsTableArtifact> artifactContents = getArtifactContents();
743 return new ViewUpdate(artifactContents.size(), pageIndex, artifactContent);
748 if (!isCancelled()) {
751 if (viewUpdate != null) {
752 updateView(viewUpdate);
754 }
catch (InterruptedException | ExecutionException ex) {
755 logger.log(Level.WARNING,
"Artifact display task unexpectedly interrupted or failed", ex);
javax.swing.JPopupMenu rightClickMenu
void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt)
javax.swing.JScrollPane jScrollPane1
javax.swing.JLabel pageLabel
synchronized void startNewTask(SwingWorker< ViewUpdate, Void > task)
javax.swing.JPanel jPanel1
javax.swing.JLabel artifactLabel
javax.swing.JButton nextPageButton
void setArtifactContents(List< ResultsTableArtifact > artifactList)
void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt)
DataContentViewerArtifact()
List< ResultsTableArtifact > artifactTableContents
javax.swing.JScrollPane resultsTableScrollPane
ViewUpdate doInBackground()
void updateView(ViewUpdate viewUpdate)
List< ResultsTableArtifact > getArtifactContents()
void setNode(Node selectedNode)
javax.swing.JMenuItem copyMenuItem
javax.swing.JLabel totalPageLabel
javax.swing.JButton prevPageButton
final String artifactDisplayName
javax.swing.JMenuItem selectAllMenuItem
javax.swing.JLabel pageLabel2
javax.swing.JLabel ofLabel
DataContentViewer createInstance()
synchronized static Logger getLogger(String name)
static TimeZone getTimeZone(Content c)
ViewUpdate doInBackground()
boolean isSupported(Node node)
void addRows(BlackboardArtifact artifact)
int isPreferred(Node node)
void customizeComponents()
javax.swing.JLabel currentPageLabel