From 341f15e8ae3f2941c45762d6dfe0089d6f540550 Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Fri, 8 May 2020 14:53:52 -0400 Subject: [PATCH 1/8] Interim checkpoint commit. --- .../contentviewers/ArtifactContentViewer.java | 57 + .../autopsy/contentviewers/Bundle.properties | 15 +- .../contentviewers/Bundle_ja.properties | 9 + .../DefaultArtifactContentViewer.form | 266 +++++ .../DefaultArtifactContentViewer.java | 983 ++++++++++++++++++ .../DummyArtifactContentViewer.form | 85 ++ .../DummyArtifactContentViewer.java | 108 ++ .../autopsy/corecomponents/Bundle.properties | 1 + .../DataContentViewerArtifact.form | 54 +- .../DataContentViewerArtifact.java | 48 +- 10 files changed, 1618 insertions(+), 8 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/ArtifactContentViewer.java create mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.form create mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java create mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.form create mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.java diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/ArtifactContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/ArtifactContentViewer.java new file mode 100644 index 0000000000..4e3dae286b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/ArtifactContentViewer.java @@ -0,0 +1,57 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.contentviewers; + +import java.awt.Component; +import org.sleuthkit.datamodel.BlackboardArtifact; + +/** + * Common interface implemented by artifact viewers. + * + * An artifact viewer displays the artifact in a custom + * layout panel suitable for the artifact type. + * + */ +public interface ArtifactContentViewer { + + /** + * Called to display the contents of the given artifact. + * + * @param artifact the node which is used to obtain and display the + * artifacts. + */ + void setArtifact(BlackboardArtifact artifact); + + /** + * Returns the panel. + * + * @return display panel. + */ + Component getComponent(); + + /** + * Checks whether the given artifact is supported by the viewer. + * + * @param artifact Artifact to check. + * + * @return True if the node can be displayed / processed, else false + */ + boolean isSupported(BlackboardArtifact artifact); + +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties index ebc9a58e1a..1064a8e354 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties @@ -953,4 +953,17 @@ manager.properties.lafError =\ manager.properties.brokenProperty = Broken default property {0} value: {1} -manager.properties.missingProperty = Missing default property {0} value: {1} \ No newline at end of file +manager.properties.missingProperty = Missing default property {0} value: {1} +DefaultArtifactContentViewer.copyMenuItem.text=Copy +DefaultArtifactContentViewer.prevPageButton.text= +DefaultArtifactContentViewer.pageLabel2.text=Result +DefaultArtifactContentViewer.nextPageButton.text= +DefaultArtifactContentViewer.pageLabel.text=Result: +DefaultArtifactContentViewer.currentPageLabel.text=1 +DefaultArtifactContentViewer.ofLabel.text=of +DefaultArtifactContentViewer.totalPageLabel.text=100 +DefaultArtifactContentViewer.selectAllMenuItem.text=Select All +DummyArtifactContentViewer.jLabel1.text=Artifact Type: +DummyArtifactContentViewer.artifactTypeTextField.text=jTextField1 +DummyArtifactContentViewer.jLabel2.text=Artifact Id: +DummyArtifactContentViewer.artifactIdTextField.text=jTextField1 diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle_ja.properties index f7b7844e60..31e821797d 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle_ja.properties @@ -164,3 +164,12 @@ MediaViewImagePanel.tagsMenu.text_1=\u30bf\u30b0\u30e1\u30cb\u30e5\u30fc SQLiteViewer.readTable.errorText=\u6b21\u306e\u30c6\u30fc\u30d6\u30eb\u306e\u884c\u3092\u53d6\u5f97\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f: {0} # {0} - tableName SQLiteViewer.selectTable.errorText=\u6b21\u306e\u30c6\u30fc\u30d6\u30eb\u306e\u884c\u30ab\u30a6\u30f3\u30c8\u3092\u53d6\u5f97\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f: {0} +DefaultArtifactContentViewer.prevPageButton.text= +DefaultArtifactContentViewer.pageLabel2.text=\u7d50\u679c +DefaultArtifactContentViewer.nextPageButton.text= +DefaultArtifactContentViewer.pageLabel.text=\u7d50\u679c: +DefaultArtifactContentViewer.currentPageLabel.text=1 +DefaultArtifactContentViewer.ofLabel.text=/ +DefaultArtifactContentViewer.totalPageLabel.text=100 +DefaultArtifactContentViewer.selectAllMenuItem.text=\u3059\u3079\u3066\u3092\u9078\u629e +DefaultArtifactContentViewer.copyMenuItem.text=\u30b3\u30d4\u30fc diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.form new file mode 100644 index 0000000000..08d2fc0205 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.form @@ -0,0 +1,266 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java new file mode 100644 index 0000000000..b72320c8b9 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java @@ -0,0 +1,983 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.contentviewers; + +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.datatransfer.StringSelection; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import javax.swing.JMenuItem; +import javax.swing.JTextArea; +import javax.swing.SwingWorker; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.TableColumnModelEvent; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableColumn; +import javax.swing.event.TableColumnModelListener; +import javax.swing.text.View; +import org.apache.commons.lang.StringUtils; +import org.openide.nodes.Node; +import org.openide.util.Lookup; +import org.openide.util.NbBundle; +import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.ContentUtils; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; +import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskException; +import org.netbeans.swing.etable.ETable; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonArray; +import java.util.Map; + +/** + * Instances of this class display the BlackboardArtifacts associated with the + * Content represented by a Node. Each BlackboardArtifact is rendered displayed + * in a JTable representation of its BlackboardAttributes. + */ +@ServiceProvider(service = DataContentViewer.class, position = 11) +@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives +public class DefaultArtifactContentViewer extends javax.swing.JPanel implements DataContentViewer { + + @NbBundle.Messages({ + "DataContentViewerArtifact.attrsTableHeader.type=Type", + "DataContentViewerArtifact.attrsTableHeader.value=Value", + "DataContentViewerArtifact.attrsTableHeader.sources=Source(s)", + "DataContentViewerArtifact.failedToGetSourcePath.message=Failed to get source file path from case database", + "DataContentViewerArtifact.failedToGetAttributes.message=Failed to get some or all attributes from case database" + }) + private final static Logger logger = Logger.getLogger(DefaultArtifactContentViewer.class.getName()); + private final static String WAIT_TEXT = NbBundle.getMessage(DefaultArtifactContentViewer.class, "DataContentViewerArtifact.waitText"); + private final static String ERROR_TEXT = NbBundle.getMessage(DefaultArtifactContentViewer.class, "DataContentViewerArtifact.errorText"); + private Node currentNode; // @@@ Remove this when the redundant setNode() calls problem is fixed. + private int currentPage = 1; + private final Object lock = new Object(); + private List artifactTableContents; // Accessed by multiple threads, use getArtifactContents() and setArtifactContents() + SwingWorker currentTask; // Accessed by multiple threads, use startNewTask() + private static final String[] COLUMN_HEADERS = { + Bundle.DataContentViewerArtifact_attrsTableHeader_type(), + Bundle.DataContentViewerArtifact_attrsTableHeader_value(), + Bundle.DataContentViewerArtifact_attrsTableHeader_sources()}; + private static final int[] COLUMN_WIDTHS = {100, 800, 100}; + private static final int CELL_BOTTOM_MARGIN = 5; + private static final int CELL_RIGHT_MARGIN = 1; + + public DefaultArtifactContentViewer() { + initResultsTable(); + initComponents(); + resultsTableScrollPane.setViewportView(resultsTable); + customizeComponents(); + resetComponents(); + resultsTable.setDefaultRenderer(Object.class, new MultiLineTableCellRenderer()); + } + + private void initResultsTable() { + resultsTable = new ETable(); + resultsTable.setModel(new javax.swing.table.DefaultTableModel() { + private static final long serialVersionUID = 1L; + + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + }); + resultsTable.setCellSelectionEnabled(true); + resultsTable.getTableHeader().setReorderingAllowed(false); + resultsTable.setColumnHidingAllowed(false); + resultsTable.getColumnModel().getSelectionModel().setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION); + resultsTable.getColumnModel().addColumnModelListener(new TableColumnModelListener() { + + @Override + public void columnAdded(TableColumnModelEvent e) { + } + + @Override + public void columnRemoved(TableColumnModelEvent e) { + } + + @Override + public void columnMoved(TableColumnModelEvent e) { + + } + + @Override + public void columnMarginChanged(ChangeEvent e) { + updateRowHeights(); //When the user changes column width we may need to resize row height + } + + @Override + public void columnSelectionChanged(ListSelectionEvent e) { + } + }); + resultsTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_NEXT_COLUMN); + + } + + /** + * Sets the row heights to the heights of the content in their Value column. + */ + private void updateRowHeights() { + int valueColIndex = -1; + for (int col = 0; col < resultsTable.getColumnCount(); col++) { + if (resultsTable.getColumnName(col).equals(COLUMN_HEADERS[1])) { + valueColIndex = col; + } + } + if (valueColIndex != -1) { + for (int row = 0; row < resultsTable.getRowCount(); row++) { + Component comp = resultsTable.prepareRenderer( + resultsTable.getCellRenderer(row, valueColIndex), row, valueColIndex); + final int rowHeight; + if (comp instanceof JTextArea) { + final JTextArea tc = (JTextArea) comp; + final View rootView = tc.getUI().getRootView(tc); + java.awt.Insets i = tc.getInsets(); + rootView.setSize(resultsTable.getColumnModel().getColumn(valueColIndex) + .getWidth() - (i.left + i.right +CELL_RIGHT_MARGIN), //current width minus borders + Integer.MAX_VALUE); + rowHeight = (int) rootView.getPreferredSpan(View.Y_AXIS); + } else { + rowHeight = comp.getPreferredSize().height; + } + if (rowHeight > 0) { + resultsTable.setRowHeight(row, rowHeight + CELL_BOTTOM_MARGIN); + } + } + } + } + + /** + * Update the column widths so that the Value column has most of the space. + */ + private void updateColumnSizes() { + Enumeration columns = resultsTable.getColumnModel().getColumns(); + while (columns.hasMoreElements()) { + TableColumn col = columns.nextElement(); + if (col.getHeaderValue().equals(COLUMN_HEADERS[0])) { + col.setPreferredWidth(COLUMN_WIDTHS[0]); + } else if (col.getHeaderValue().equals(COLUMN_HEADERS[1])) { + col.setPreferredWidth(COLUMN_WIDTHS[1]); + } else if (col.getHeaderValue().equals(COLUMN_HEADERS[2])) { + col.setPreferredWidth(COLUMN_WIDTHS[2]); + } + } + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + java.awt.GridBagConstraints gridBagConstraints; + + rightClickMenu = new javax.swing.JPopupMenu(); + copyMenuItem = new javax.swing.JMenuItem(); + selectAllMenuItem = new javax.swing.JMenuItem(); + jScrollPane1 = new javax.swing.JScrollPane(); + jPanel1 = new javax.swing.JPanel(); + totalPageLabel = new javax.swing.JLabel(); + ofLabel = new javax.swing.JLabel(); + currentPageLabel = new javax.swing.JLabel(); + pageLabel = new javax.swing.JLabel(); + nextPageButton = new javax.swing.JButton(); + pageLabel2 = new javax.swing.JLabel(); + prevPageButton = new javax.swing.JButton(); + artifactLabel = new javax.swing.JLabel(); + filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0)); + resultsTableScrollPane = new javax.swing.JScrollPane(); + + copyMenuItem.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.copyMenuItem.text")); // NOI18N + rightClickMenu.add(copyMenuItem); + + selectAllMenuItem.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.selectAllMenuItem.text")); // NOI18N + rightClickMenu.add(selectAllMenuItem); + + setPreferredSize(new java.awt.Dimension(100, 58)); + + jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + jScrollPane1.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); + + jPanel1.setPreferredSize(new java.awt.Dimension(620, 58)); + jPanel1.setLayout(new java.awt.GridBagLayout()); + + totalPageLabel.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.totalPageLabel.text")); // NOI18N + totalPageLabel.setMaximumSize(new java.awt.Dimension(40, 16)); + totalPageLabel.setPreferredSize(new java.awt.Dimension(25, 16)); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 3; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(3, 12, 0, 0); + jPanel1.add(totalPageLabel, gridBagConstraints); + + ofLabel.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.ofLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 2; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(3, 12, 0, 0); + jPanel1.add(ofLabel, gridBagConstraints); + + currentPageLabel.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.currentPageLabel.text")); // NOI18N + currentPageLabel.setMaximumSize(new java.awt.Dimension(38, 14)); + currentPageLabel.setMinimumSize(new java.awt.Dimension(18, 14)); + currentPageLabel.setPreferredSize(new java.awt.Dimension(20, 14)); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(4, 7, 0, 0); + jPanel1.add(currentPageLabel, gridBagConstraints); + + pageLabel.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.pageLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(3, 12, 0, 0); + jPanel1.add(pageLabel, gridBagConstraints); + + nextPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"))); // NOI18N + nextPageButton.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.nextPageButton.text")); // NOI18N + nextPageButton.setBorderPainted(false); + nextPageButton.setContentAreaFilled(false); + nextPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); // NOI18N + nextPageButton.setMargin(new java.awt.Insets(2, 0, 2, 0)); + nextPageButton.setPreferredSize(new java.awt.Dimension(23, 23)); + nextPageButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"))); // NOI18N + nextPageButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + nextPageButtonActionPerformed(evt); + } + }); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 6; + gridBagConstraints.gridy = 0; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 35, 0); + jPanel1.add(nextPageButton, gridBagConstraints); + + pageLabel2.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.pageLabel2.text")); // NOI18N + pageLabel2.setMaximumSize(new java.awt.Dimension(29, 14)); + pageLabel2.setMinimumSize(new java.awt.Dimension(29, 14)); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 4; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(3, 41, 0, 0); + jPanel1.add(pageLabel2, gridBagConstraints); + + prevPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); // NOI18N + prevPageButton.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.prevPageButton.text")); // NOI18N + prevPageButton.setBorderPainted(false); + prevPageButton.setContentAreaFilled(false); + prevPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); // NOI18N + prevPageButton.setMargin(new java.awt.Insets(2, 0, 2, 0)); + prevPageButton.setPreferredSize(new java.awt.Dimension(23, 23)); + prevPageButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"))); // NOI18N + prevPageButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + prevPageButtonActionPerformed(evt); + } + }); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 5; + gridBagConstraints.gridy = 0; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(0, 5, 35, 0); + jPanel1.add(prevPageButton, gridBagConstraints); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 8; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST; + gridBagConstraints.insets = new java.awt.Insets(3, 0, 0, 8); + jPanel1.add(artifactLabel, gridBagConstraints); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 7; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.weightx = 0.1; + jPanel1.add(filler1, gridBagConstraints); + + jScrollPane1.setViewportView(jPanel1); + + resultsTableScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); + resultsTableScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); + resultsTableScrollPane.setPreferredSize(new java.awt.Dimension(620, 34)); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane1) + .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed + currentPage = currentPage + 1; + currentPageLabel.setText(Integer.toString(currentPage)); + artifactLabel.setText(artifactTableContents.get(currentPage - 1).getArtifactDisplayName()); + startNewTask(new SelectedArtifactChangedTask(currentPage)); + }//GEN-LAST:event_nextPageButtonActionPerformed + + private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevPageButtonActionPerformed + currentPage = currentPage - 1; + currentPageLabel.setText(Integer.toString(currentPage)); + artifactLabel.setText(artifactTableContents.get(currentPage - 1).getArtifactDisplayName()); + startNewTask(new SelectedArtifactChangedTask(currentPage)); + }//GEN-LAST:event_prevPageButtonActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel artifactLabel; + private javax.swing.JMenuItem copyMenuItem; + private javax.swing.JLabel currentPageLabel; + private javax.swing.Box.Filler filler1; + private javax.swing.JPanel jPanel1; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JButton nextPageButton; + private javax.swing.JLabel ofLabel; + private javax.swing.JLabel pageLabel; + private javax.swing.JLabel pageLabel2; + private javax.swing.JButton prevPageButton; + private javax.swing.JScrollPane resultsTableScrollPane; + private javax.swing.JPopupMenu rightClickMenu; + private javax.swing.JMenuItem selectAllMenuItem; + private javax.swing.JLabel totalPageLabel; + // End of variables declaration//GEN-END:variables + private ETable resultsTable; + + private void customizeComponents() { + resultsTable.setComponentPopupMenu(rightClickMenu); + ActionListener actList = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + JMenuItem jmi = (JMenuItem) e.getSource(); + if (jmi.equals(copyMenuItem)) { + StringBuilder selectedText = new StringBuilder(512); + for (int row : resultsTable.getSelectedRows()) { + for (int col : resultsTable.getSelectedColumns()) { + selectedText.append((String) resultsTable.getValueAt(row, col)); + selectedText.append("\t"); + } + //if its the last row selected don't add a new line + if (row != resultsTable.getSelectedRows()[resultsTable.getSelectedRows().length - 1]) { + selectedText.append(System.lineSeparator()); + } + } + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(selectedText.toString()), null); + } else if (jmi.equals(selectAllMenuItem)) { + resultsTable.selectAll(); + } + } + }; + copyMenuItem.addActionListener(actList); + + selectAllMenuItem.addActionListener(actList); + } + + /** + * Resets the components to an empty view state. + */ + private void resetComponents() { + currentPage = 1; + currentPageLabel.setText(""); + artifactLabel.setText(""); + totalPageLabel.setText(""); + ((DefaultTableModel) resultsTable.getModel()).setRowCount(0); + prevPageButton.setEnabled(false); + nextPageButton.setEnabled(false); + currentNode = null; + } + + @Override + public void setNode(Node selectedNode) { + if (currentNode == selectedNode) { + return; + } + currentNode = selectedNode; + + // Make sure there is a node. Null might be passed to reset the viewer. + if (selectedNode == null) { + return; + } + + // Make sure the node is of the correct type. + Lookup lookup = selectedNode.getLookup(); + Content content = lookup.lookup(Content.class); + if (content == null) { + return; + } + + startNewTask(new SelectedNodeChangedTask(selectedNode)); + } + + @Override + public String getTitle() { + return NbBundle.getMessage(this.getClass(), "DataContentViewerArtifact.title"); + } + + @Override + public String getToolTip() { + return NbBundle.getMessage(this.getClass(), "DataContentViewerArtifact.toolTip"); + } + + @Override + public DataContentViewer createInstance() { + return new DefaultArtifactContentViewer(); + } + + @Override + public Component getComponent() { + return this; + } + + @Override + public void resetComponent() { + resetComponents(); + } + + @Override + public boolean isSupported(Node node) { + if (node == null) { + return false; + } + + for (Content content : node.getLookup().lookupAll(Content.class)) { + if ( (content != null) && (!(content instanceof BlackboardArtifact)) ){ + try { + return content.getAllArtifactsCount() > 0; + } catch (TskException ex) { + logger.log(Level.SEVERE, "Couldn't get count of BlackboardArtifacts for content", ex); //NON-NLS + } + } + } + return false; + } + + @Override + public int isPreferred(Node node) { + BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class); + // low priority if node doesn't have an artifact (meaning it was found from normal directory + // browsing, or if the artifact is something that means the user really wants to see the original + // file and not more details about the artifact + if ((artifact == null) + || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) + || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) + || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()) + || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID()) + || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID()) + || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID())) { + return 3; + } else { + return 6; + } + } + + /** + * This class is a container to hold the data necessary for each of the + * result pages associated with file or artifact beivng viewed. + */ + private class ResultsTableArtifact { + + private final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + private String[][] rowData = null; + private final String artifactDisplayName; + private final Content content; + + ResultsTableArtifact(BlackboardArtifact artifact, Content content) { + artifactDisplayName = artifact.getDisplayName(); + this.content = content; + addRows(artifact); + } + + ResultsTableArtifact(String errorMsg) { + artifactDisplayName = errorMsg; + rowData = new String[1][3]; + rowData[0] = new String[]{"", errorMsg, ""}; + content = null; + } + + private String[][] getRows() { + return rowData; + } + + private void addRows(BlackboardArtifact artifact) { + List rowsToAdd = new ArrayList<>(); + try { + /* + * Add rows for each attribute. + */ + for (BlackboardAttribute attr : artifact.getAttributes()) { + /* + * Attribute value column. + */ + String value = ""; + switch (attr.getAttributeType().getValueType()) { + case STRING: + case INTEGER: + case LONG: + case DOUBLE: + case BYTE: + default: + value = attr.getDisplayString(); + break; + // Use Autopsy date formatting settings, not TSK defaults + case DATETIME: + value = epochTimeToString(attr.getValueLong()); + break; + case JSON: + // Get the attribute's JSON value and convert to indented multiline display string + String jsonVal = attr.getValueString(); + JsonParser parser = new JsonParser(); + JsonObject json = parser.parse(jsonVal).getAsJsonObject(); + + value = toJsonDisplayString(json, ""); + break; + } + /* + * Attribute sources column. + */ + String sources = StringUtils.join(attr.getSources(), ", "); + rowsToAdd.add(new String[]{attr.getAttributeType().getDisplayName(), value, sources}); + } + /* + * Add a row for the source content path. + */ + String path = ""; + try { + if (null != content) { + path = content.getUniquePath(); + } + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Error getting source content path for artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex); + path = Bundle.DataContentViewerArtifact_failedToGetSourcePath_message(); + } + rowsToAdd.add(new String[]{"Source File Path", path, ""}); + /* + * Add a row for the artifact id. + */ + rowsToAdd.add(new String[]{"Artifact ID", Long.toString(artifact.getArtifactID()), ""}); + } catch (TskCoreException ex) { + rowsToAdd.add(new String[]{"", Bundle.DataContentViewerArtifact_failedToGetAttributes_message(), ""}); + } + rowData = rowsToAdd.toArray(new String[0][0]); + } + + /** + * @return the artifactDisplayName + */ + String getArtifactDisplayName() { + return artifactDisplayName; + } + + private static final String INDENT_RIGHT = " "; + private static final String NEW_LINE = "\n"; + + /** + * Recursively converts a JSON element into an indented multi-line + * display string. + * + * @param element JSON element to convert + * @param startIndent Starting indentation for the element. + * + * @return A multi-line display string. + */ + private String toJsonDisplayString(JsonElement element, String startIndent) { + + StringBuilder sb = new StringBuilder(""); + JsonObject obj = element.getAsJsonObject(); + + for (Map.Entry entry : obj.entrySet()) { + appendJsonElementToString(entry.getKey(), entry.getValue(), startIndent, sb ); + } + + String returnString = sb.toString(); + if (startIndent.length() == 0 && returnString.startsWith(NEW_LINE)) { + returnString = returnString.substring(NEW_LINE.length()); + } + return returnString; + } + + + /** + * Converts the given JSON element into string and appends to the given string builder. + * + * @param jsonKey + * @param jsonElement + * @param startIndent Starting indentation for the element. + * @param sb String builder to append to. + */ + private void appendJsonElementToString(String jsonKey, JsonElement jsonElement, String startIndent, StringBuilder sb) { + if (jsonElement.isJsonArray()) { + JsonArray jsonArray = jsonElement.getAsJsonArray(); + if (jsonArray.size() > 0) { + int count = 1; + sb.append(NEW_LINE).append(String.format("%s%s", startIndent, jsonKey)); + for (JsonElement arrayMember : jsonArray) { + sb.append(NEW_LINE).append(String.format("%s%d", startIndent.concat(INDENT_RIGHT), count)); + sb.append(toJsonDisplayString(arrayMember, startIndent.concat(INDENT_RIGHT).concat(INDENT_RIGHT))); + count++; + } + } + } else if (jsonElement.isJsonObject()) { + sb.append(NEW_LINE).append(String.format("%s%s %s", startIndent, jsonKey, toJsonDisplayString(jsonElement.getAsJsonObject(), startIndent + INDENT_RIGHT))); + } else if (jsonElement.isJsonPrimitive()) { + String attributeName = jsonKey; + String attributeValue; + if (attributeName.toUpperCase().contains("DATETIME")) { + attributeValue = epochTimeToString(Long.parseLong(jsonElement.getAsString())); + } else { + attributeValue = jsonElement.getAsString(); + } + sb.append(NEW_LINE).append(String.format("%s%s = %s", startIndent, attributeName, attributeValue)); + } else if (jsonElement.isJsonNull()) { + sb.append(NEW_LINE).append(String.format("%s%s = null", startIndent, jsonKey)); + } + } + + /** + * Converts epoch time to readable string. + * + * @param epochTime epoch time value to be converted to string. + * @return String with human readable time. + */ + private String epochTimeToString(long epochTime) { + String dateTimeString = "0000-00-00 00:00:00"; + if (null != content && 0 != epochTime) { + dateFormatter.setTimeZone(ContentUtils.getTimeZone(content)); + dateTimeString = dateFormatter.format(new java.util.Date(epochTime * 1000)); + } + return dateTimeString; + } + + } + + /** + * Instances of this class are simple containers for view update information + * generated by a background thread. + */ + private class ViewUpdate { + + int numberOfPages; + int currentPage; + ResultsTableArtifact tableContents; + + ViewUpdate(int numberOfPages, int currentPage, ResultsTableArtifact contents) { + this.currentPage = currentPage; + this.numberOfPages = numberOfPages; + this.tableContents = contents; + } + + ViewUpdate(int numberOfPages, int currentPage, String errorMsg) { + this.currentPage = currentPage; + this.numberOfPages = numberOfPages; + this.tableContents = new ResultsTableArtifact(errorMsg); + } + } + + /** + * Called from queued SwingWorker done() methods on the EDT thread, so + * doesn't need to be synchronized. + * + * @param viewUpdate A simple container for display update information from + * a background thread. + */ + private void updateView(ViewUpdate viewUpdate) { + this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + nextPageButton.setEnabled(viewUpdate.currentPage < viewUpdate.numberOfPages); + prevPageButton.setEnabled(viewUpdate.currentPage > 1); + currentPage = viewUpdate.currentPage; + totalPageLabel.setText(Integer.toString(viewUpdate.numberOfPages)); + currentPageLabel.setText(Integer.toString(currentPage)); + artifactLabel.setText(viewUpdate.tableContents.getArtifactDisplayName()); + DefaultTableModel tModel = ((DefaultTableModel) resultsTable.getModel()); + tModel.setDataVector(viewUpdate.tableContents.getRows(), COLUMN_HEADERS); + updateColumnSizes(); + updateRowHeights(); + resultsTable.clearSelection(); + + this.setCursor(null); + } + + /** + * Start a new task on its own background thread, canceling the previous + * task. + * + * @param task A new SwingWorker object to execute as a background thread. + */ + private synchronized void startNewTask(SwingWorker task) { + String[][] waitRow = new String[1][3]; + waitRow[0] = new String[]{"", WAIT_TEXT, ""}; + DefaultTableModel tModel = ((DefaultTableModel) resultsTable.getModel()); + tModel.setDataVector(waitRow, COLUMN_HEADERS); + updateColumnSizes(); + updateRowHeights(); + resultsTable.clearSelection(); + // The output of the previous task is no longer relevant. + if (currentTask != null) { + // This call sets a cancellation flag. It does not terminate the background thread running the task. + // The task must check the cancellation flag and react appropriately. + currentTask.cancel(false); + } + + // Start the new task. + currentTask = task; + currentTask.execute(); + } + + /** + * Populate the cache of artifact represented as ResultsTableArtifacts. + * + * @param artifactList A list of ResultsTableArtifact representations of + * artifacts. + */ + private void setArtifactContents(List artifactList) { + synchronized (lock) { + this.artifactTableContents = artifactList; + } + } + + /** + * Retrieve the cache of artifact represented as ResultsTableArtifacts. + * + * @return A list of ResultsTableArtifact representations of artifacts. + */ + private List getArtifactContents() { + synchronized (lock) { + return artifactTableContents; + } + } + + /** + * Instances of this class use a background thread to generate a ViewUpdate + * when a node is selected, changing the set of blackboard artifacts + * ("results") to be displayed. + */ + private class SelectedNodeChangedTask extends SwingWorker { + + private final Node selectedNode; + + SelectedNodeChangedTask(Node selectedNode) { + this.selectedNode = selectedNode; + } + + @Override + protected ViewUpdate doInBackground() { + // Get the lookup for the node for access to its underlying content and + // blackboard artifact, if any. + Lookup lookup = selectedNode.getLookup(); + + // Get the content. We may get BlackboardArtifacts, ignore those here. + ArrayList artifacts = new ArrayList<>(); + Collection contents = lookup.lookupAll(Content.class); + if (contents.isEmpty()) { + return new ViewUpdate(getArtifactContents().size(), currentPage, ERROR_TEXT); + } + Content underlyingContent = null; + for (Content content : contents) { + if ( (content != null) && (!(content instanceof BlackboardArtifact)) ) { + // Get all of the blackboard artifacts associated with the content. These are what this + // viewer displays. + try { + artifacts = content.getAllArtifacts(); + underlyingContent = content; + break; + } catch (TskException ex) { + logger.log(Level.SEVERE, "Couldn't get artifacts", ex); //NON-NLS + return new ViewUpdate(getArtifactContents().size(), currentPage, ERROR_TEXT); + } + } + } + + if (isCancelled()) { + return null; + } + + // Build the new artifact contents cache. + ArrayList artifactContents = new ArrayList<>(); + for (BlackboardArtifact artifact : artifacts) { + artifactContents.add(new ResultsTableArtifact(artifact, underlyingContent)); + } + + // If the node has an underlying blackboard artifact, show it. If not, + // show the first artifact. + int index = 0; + BlackboardArtifact artifact = lookup.lookup(BlackboardArtifact.class); + if (artifact != null) { + index = artifacts.indexOf(artifact); + if (index == -1) { + index = 0; + } else { + // if the artifact has an ASSOCIATED ARTIFACT, then we display the associated artifact instead + try { + for (BlackboardAttribute attr : artifact.getAttributes()) { + if (attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) { + long assocArtifactId = attr.getValueLong(); + int assocArtifactIndex = -1; + for (BlackboardArtifact art : artifacts) { + if (assocArtifactId == art.getArtifactID()) { + assocArtifactIndex = artifacts.indexOf(art); + break; + } + } + if (assocArtifactIndex >= 0) { + index = assocArtifactIndex; + } + break; + } + } + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Couldn't get associated artifact to display in Content Viewer.", ex); //NON-NLS + } + } + + } + + if (isCancelled()) { + return null; + } + + // Add one to the index of the artifact content for the corresponding page index. + ViewUpdate viewUpdate = new ViewUpdate(artifactContents.size(), index + 1, artifactContents.get(index)); + + // It may take a considerable amount of time to fetch the attributes of the selected artifact + if (isCancelled()) { + return null; + } + + // Update the artifact contents cache. + setArtifactContents(artifactContents); + + return viewUpdate; + } + + @Override + protected void done() { + if (!isCancelled()) { + try { + ViewUpdate viewUpdate = get(); + if (viewUpdate != null) { + updateView(viewUpdate); + } + } catch (InterruptedException | ExecutionException ex) { + logger.log(Level.WARNING, "Artifact display task unexpectedly interrupted or failed", ex); //NON-NLS + } + } + } + } + + /** + * Instances of this class use a background thread to generate a ViewUpdate + * when the user pages the view to look at another blackboard artifact + * ("result"). + */ + private class SelectedArtifactChangedTask extends SwingWorker { + + private final int pageIndex; + + SelectedArtifactChangedTask(final int pageIndex) { + this.pageIndex = pageIndex; + } + + @Override + protected ViewUpdate doInBackground() { + // Get the artifact content to display from the cache. Note that one must be subtracted from the + // page index to get the corresponding artifact content index. + List artifactContents = getArtifactContents(); + ResultsTableArtifact artifactContent = artifactContents.get(pageIndex - 1); + + // It may take a considerable amount of time to fetch the attributes of the selected artifact so check for cancellation. + if (isCancelled()) { + return null; + } + + return new ViewUpdate(artifactContents.size(), pageIndex, artifactContent); + } + + @Override + protected void done() { + if (!isCancelled()) { + try { + ViewUpdate viewUpdate = get(); + if (viewUpdate != null) { + updateView(viewUpdate); + } + } catch (InterruptedException | ExecutionException ex) { + logger.log(Level.WARNING, "Artifact display task unexpectedly interrupted or failed", ex); //NON-NLS + } + } + } + } + + /** + * TableCellRenderer for displaying multiline text. + */ + private class MultiLineTableCellRenderer implements javax.swing.table.TableCellRenderer { + + @Override + public Component getTableCellRendererComponent(javax.swing.JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + javax.swing.JTextArea jtex = new javax.swing.JTextArea(); + if (value instanceof String) { + jtex.setText((String) value); + jtex.setLineWrap(true); + jtex.setWrapStyleWord(false); + } + //cell backgroud color when selected + if (isSelected) { + jtex.setBackground(javax.swing.UIManager.getColor("Table.selectionBackground")); + } else { + jtex.setBackground(javax.swing.UIManager.getColor("Table.background")); + } + return jtex; + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.form new file mode 100644 index 0000000000..b7cef5505b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.form @@ -0,0 +1,85 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.java new file mode 100644 index 0000000000..edc793f98b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.java @@ -0,0 +1,108 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.contentviewers; + +import java.awt.Component; +import org.sleuthkit.datamodel.BlackboardArtifact; + +/** + * + * @author raman + */ +public class DummyArtifactContentViewer extends javax.swing.JPanel implements ArtifactContentViewer { + + /** + * Creates new form DummyArtifactContentViewer + */ + public DummyArtifactContentViewer() { + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jLabel1 = new javax.swing.JLabel(); + artifactTypeTextField = new javax.swing.JTextField(); + jLabel2 = new javax.swing.JLabel(); + artifactIdTextField = new javax.swing.JTextField(); + + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(DummyArtifactContentViewer.class, "DummyArtifactContentViewer.jLabel1.text")); // NOI18N + + artifactTypeTextField.setText(org.openide.util.NbBundle.getMessage(DummyArtifactContentViewer.class, "DummyArtifactContentViewer.artifactTypeTextField.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(DummyArtifactContentViewer.class, "DummyArtifactContentViewer.jLabel2.text")); // NOI18N + + artifactIdTextField.setText(org.openide.util.NbBundle.getMessage(DummyArtifactContentViewer.class, "DummyArtifactContentViewer.artifactIdTextField.text")); // NOI18N + artifactIdTextField.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + artifactIdTextFieldActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel1) + .addComponent(jLabel2)) + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(artifactTypeTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 133, Short.MAX_VALUE) + .addComponent(artifactIdTextField)) + .addContainerGap(165, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(16, 16, 16) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel1) + .addComponent(artifactTypeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel2) + .addComponent(artifactIdTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(218, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + private void artifactIdTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_artifactIdTextFieldActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_artifactIdTextFieldActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JTextField artifactIdTextField; + private javax.swing.JTextField artifactTypeTextField; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + // End of variables declaration//GEN-END:variables + + @Override + public void setArtifact(BlackboardArtifact artifact) { + artifactTypeTextField.setText(artifact.getArtifactTypeName()); + artifactIdTextField.setText(String.format("%d", artifact.getId())); + } + + @Override + public Component getComponent() { + return this; + } + + @Override + public boolean isSupported(BlackboardArtifact artifact) { + return true; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index 4571bcc3df..4eb87c3496 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -218,3 +218,4 @@ DataResultViewerTable.exportCSVButton.text=Save Table as CSV ViewPreferencesPanel.scoColumnsCheckbox.text=S(core), C(omments), and O(ccurences) ViewPreferencesPanel.scoColumnsWrapAroundText.text=to reduce loading times ViewPreferencesPanel.scoColumnsLabel.text=Do not add columns for: +DataContentViewerArtifact.jLabel1.text=Artifact Content View diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.form index 5827ce617f..52207ebf35 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.form @@ -1,6 +1,6 @@ -
+ @@ -45,8 +45,14 @@ - - + + + + + + + + @@ -54,7 +60,11 @@ - + + + + + @@ -262,5 +272,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java index 78ccd6e4ec..a5779005a8 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java @@ -61,6 +61,8 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonArray; import java.util.Map; +import org.sleuthkit.autopsy.contentviewers.ArtifactContentViewer; +import org.sleuthkit.autopsy.contentviewers.DummyArtifactContentViewer; /** * Instances of this class display the BlackboardArtifacts associated with the @@ -219,6 +221,8 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat artifactLabel = new javax.swing.JLabel(); filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0)); resultsTableScrollPane = new javax.swing.JScrollPane(); + jLabel1 = new javax.swing.JLabel(); + artifactContentPanel = new javax.swing.JPanel(); copyMenuItem.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.copyMenuItem.text")); // NOI18N rightClickMenu.add(copyMenuItem); @@ -345,19 +349,32 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat resultsTableScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); resultsTableScrollPane.setPreferredSize(new java.awt.Dimension(620, 34)); + jLabel1.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.jLabel1.text")); // NOI18N + + artifactContentPanel.setLayout(new javax.swing.OverlayLayout(artifactContentPanel)); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1) - .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 476, Short.MAX_VALUE) + .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 476, Short.MAX_VALUE) + .addComponent(artifactContentPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addGap(166, 166, 166) + .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 129, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 130, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(artifactContentPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 134, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -376,10 +393,12 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat }//GEN-LAST:event_prevPageButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JPanel artifactContentPanel; private javax.swing.JLabel artifactLabel; private javax.swing.JMenuItem copyMenuItem; private javax.swing.JLabel currentPageLabel; private javax.swing.Box.Filler filler1; + private javax.swing.JLabel jLabel1; private javax.swing.JPanel jPanel1; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JButton nextPageButton; @@ -521,6 +540,11 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat } } + private ArtifactContentViewer getArtifactViewer(BlackboardArtifact artifact) { + + return new DummyArtifactContentViewer(); + + } /** * This class is a container to hold the data necessary for each of the * result pages associated with file or artifact beivng viewed. @@ -531,10 +555,12 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat private String[][] rowData = null; private final String artifactDisplayName; private final Content content; + private final BlackboardArtifact artifact; ResultsTableArtifact(BlackboardArtifact artifact, Content content) { artifactDisplayName = artifact.getDisplayName(); this.content = content; + this.artifact = artifact; addRows(artifact); } @@ -543,12 +569,17 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat rowData = new String[1][3]; rowData[0] = new String[]{"", errorMsg, ""}; content = null; + artifact = null; } private String[][] getRows() { return rowData; } + BlackboardArtifact getArtifact() { + return this.artifact; + } + private void addRows(BlackboardArtifact artifact) { List rowsToAdd = new ArrayList<>(); try { @@ -618,6 +649,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat return artifactDisplayName; } + private static final String INDENT_RIGHT = " "; private static final String NEW_LINE = "\n"; @@ -745,7 +777,17 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat updateRowHeights(); resultsTable.clearSelection(); + BlackboardArtifact artifact = viewUpdate.tableContents.getArtifact(); + ArtifactContentViewer viewer = this.getArtifactViewer(artifact); + viewer.setArtifact(artifact); + + artifactContentPanel.removeAll(); + artifactContentPanel.add(viewer.getComponent()); + artifactContentPanel.revalidate(); + this.setCursor(null); + + this.revalidate(); } /** From f5ec04548b5a20f100cba26e1b364e8a9ae06c0b Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Fri, 8 May 2020 16:23:42 -0400 Subject: [PATCH 2/8] Interim commit - DefaultArtifactContentViewer now implements ArtifactContentViewer, though it does nothing with the artifact yet. --- .../DefaultArtifactContentViewer.java | 95 +++---------------- 1 file changed, 14 insertions(+), 81 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java index b72320c8b9..3b6515a8ca 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java @@ -45,12 +45,9 @@ import org.apache.commons.lang.StringUtils; import org.openide.nodes.Node; import org.openide.util.Lookup; import org.openide.util.NbBundle; -import org.openide.util.lookup.ServiceProvider; -import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; @@ -63,13 +60,12 @@ import com.google.gson.JsonArray; import java.util.Map; /** - * Instances of this class display the BlackboardArtifacts associated with the - * Content represented by a Node. Each BlackboardArtifact is rendered displayed - * in a JTable representation of its BlackboardAttributes. + * This class displays a Blackboard artifact as a table listing all the + * attribute names and values. */ -@ServiceProvider(service = DataContentViewer.class, position = 11) + @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives -public class DefaultArtifactContentViewer extends javax.swing.JPanel implements DataContentViewer { +public class DefaultArtifactContentViewer extends javax.swing.JPanel implements ArtifactContentViewer { @NbBundle.Messages({ "DataContentViewerArtifact.attrsTableHeader.type=Type", @@ -81,11 +77,16 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements private final static Logger logger = Logger.getLogger(DefaultArtifactContentViewer.class.getName()); private final static String WAIT_TEXT = NbBundle.getMessage(DefaultArtifactContentViewer.class, "DataContentViewerArtifact.waitText"); private final static String ERROR_TEXT = NbBundle.getMessage(DefaultArtifactContentViewer.class, "DataContentViewerArtifact.errorText"); + + private static final long serialVersionUID = 1L; + private Node currentNode; // @@@ Remove this when the redundant setNode() calls problem is fixed. private int currentPage = 1; private final Object lock = new Object(); + private List artifactTableContents; // Accessed by multiple threads, use getArtifactContents() and setArtifactContents() SwingWorker currentTask; // Accessed by multiple threads, use startNewTask() + private static final String[] COLUMN_HEADERS = { Bundle.DataContentViewerArtifact_attrsTableHeader_type(), Bundle.DataContentViewerArtifact_attrsTableHeader_value(), @@ -437,88 +438,20 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements currentNode = null; } - @Override - public void setNode(Node selectedNode) { - if (currentNode == selectedNode) { - return; - } - currentNode = selectedNode; - - // Make sure there is a node. Null might be passed to reset the viewer. - if (selectedNode == null) { - return; - } - - // Make sure the node is of the correct type. - Lookup lookup = selectedNode.getLookup(); - Content content = lookup.lookup(Content.class); - if (content == null) { - return; - } - - startNewTask(new SelectedNodeChangedTask(selectedNode)); - } - - @Override - public String getTitle() { - return NbBundle.getMessage(this.getClass(), "DataContentViewerArtifact.title"); - } - - @Override - public String getToolTip() { - return NbBundle.getMessage(this.getClass(), "DataContentViewerArtifact.toolTip"); - } - - @Override - public DataContentViewer createInstance() { - return new DefaultArtifactContentViewer(); - } - @Override public Component getComponent() { return this; } @Override - public void resetComponent() { - resetComponents(); + public void setArtifact(BlackboardArtifact artifact) { + // RAMAN TBD: ****************** IMPLMENT THIS. ********************** + } @Override - public boolean isSupported(Node node) { - if (node == null) { - return false; - } - - for (Content content : node.getLookup().lookupAll(Content.class)) { - if ( (content != null) && (!(content instanceof BlackboardArtifact)) ){ - try { - return content.getAllArtifactsCount() > 0; - } catch (TskException ex) { - logger.log(Level.SEVERE, "Couldn't get count of BlackboardArtifacts for content", ex); //NON-NLS - } - } - } - return false; - } - - @Override - public int isPreferred(Node node) { - BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class); - // low priority if node doesn't have an artifact (meaning it was found from normal directory - // browsing, or if the artifact is something that means the user really wants to see the original - // file and not more details about the artifact - if ((artifact == null) - || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) - || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) - || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()) - || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID()) - || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID()) - || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID())) { - return 3; - } else { - return 6; - } + public boolean isSupported(BlackboardArtifact artifact) { + return true; } /** From 52f08dfb524a12e1aae7a4c99e8e6bba15563f96 Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Mon, 11 May 2020 10:05:16 -0400 Subject: [PATCH 3/8] Interim commit - use a KNOWN_ARTIFACT_VIERS list to find the supporting viewer for an artifact. --- .../DataContentViewerArtifact.java | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java index a5779005a8..9c44648c65 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java @@ -60,9 +60,11 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonArray; +import java.util.Arrays; import java.util.Map; import org.sleuthkit.autopsy.contentviewers.ArtifactContentViewer; import org.sleuthkit.autopsy.contentviewers.DummyArtifactContentViewer; +import org.sleuthkit.autopsy.contentviewers.MessageContentViewer; /** * Instances of this class display the BlackboardArtifacts associated with the @@ -96,6 +98,11 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat private static final int CELL_BOTTOM_MARGIN = 5; private static final int CELL_RIGHT_MARGIN = 1; + private final Collection KNOWN_ARTIFACT_VIEWERS = + Arrays.asList( + // RAMAN TBD: new MessageContentViewer() + ); + public DataContentViewerArtifact() { initResultsTable(); initComponents(); @@ -540,14 +547,17 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat } } - private ArtifactContentViewer getArtifactViewer(BlackboardArtifact artifact) { - - return new DummyArtifactContentViewer(); + private ArtifactContentViewer getSupportingViewer(BlackboardArtifact artifact) { + return this.KNOWN_ARTIFACT_VIEWERS.stream() + .filter(knownViewer -> knownViewer.isSupported(artifact)) + .findAny() + .orElse(new DummyArtifactContentViewer()); // RAMAN TBD: return the default viewer here + } /** * This class is a container to hold the data necessary for each of the - * result pages associated with file or artifact beivng viewed. + * result pages associated with file or artifact being viewed. */ private class ResultsTableArtifact { @@ -778,7 +788,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat resultsTable.clearSelection(); BlackboardArtifact artifact = viewUpdate.tableContents.getArtifact(); - ArtifactContentViewer viewer = this.getArtifactViewer(artifact); + ArtifactContentViewer viewer = this.getSupportingViewer(artifact); viewer.setArtifact(artifact); artifactContentPanel.removeAll(); From 3e3b9516e603a6789ff7a31025b0c48876843b18 Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Mon, 11 May 2020 18:20:29 -0400 Subject: [PATCH 4/8] Interim commit - DataContentViewerArtifact is now only responsible to get the artifacts for the given node, and provide navigation controls to view the artifacts - DefaultArtifactContentViewer now displays the given artifact in a table as a list of attribute name/value pairs. --- .../autopsy/contentviewers/Bundle.properties | 7 - .../contentviewers/Bundle_ja.properties | 7 - .../DefaultArtifactContentViewer.form | 169 ------ .../DefaultArtifactContentViewer.java | 457 ++-------------- .../autopsy/corecomponents/Bundle.properties | 3 - .../corecomponents/Bundle_ja.properties | 2 - .../DataContentViewerArtifact.form | 61 +-- .../DataContentViewerArtifact.java | 500 ++---------------- 8 files changed, 96 insertions(+), 1110 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties index 1064a8e354..eeb46367d5 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties @@ -955,13 +955,6 @@ manager.properties.brokenProperty = Broken default property {0} value: {1} manager.properties.missingProperty = Missing default property {0} value: {1} DefaultArtifactContentViewer.copyMenuItem.text=Copy -DefaultArtifactContentViewer.prevPageButton.text= -DefaultArtifactContentViewer.pageLabel2.text=Result -DefaultArtifactContentViewer.nextPageButton.text= -DefaultArtifactContentViewer.pageLabel.text=Result: -DefaultArtifactContentViewer.currentPageLabel.text=1 -DefaultArtifactContentViewer.ofLabel.text=of -DefaultArtifactContentViewer.totalPageLabel.text=100 DefaultArtifactContentViewer.selectAllMenuItem.text=Select All DummyArtifactContentViewer.jLabel1.text=Artifact Type: DummyArtifactContentViewer.artifactTypeTextField.text=jTextField1 diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle_ja.properties index 31e821797d..18fdb5ce50 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle_ja.properties @@ -164,12 +164,5 @@ MediaViewImagePanel.tagsMenu.text_1=\u30bf\u30b0\u30e1\u30cb\u30e5\u30fc SQLiteViewer.readTable.errorText=\u6b21\u306e\u30c6\u30fc\u30d6\u30eb\u306e\u884c\u3092\u53d6\u5f97\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f: {0} # {0} - tableName SQLiteViewer.selectTable.errorText=\u6b21\u306e\u30c6\u30fc\u30d6\u30eb\u306e\u884c\u30ab\u30a6\u30f3\u30c8\u3092\u53d6\u5f97\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f: {0} -DefaultArtifactContentViewer.prevPageButton.text= -DefaultArtifactContentViewer.pageLabel2.text=\u7d50\u679c -DefaultArtifactContentViewer.nextPageButton.text= -DefaultArtifactContentViewer.pageLabel.text=\u7d50\u679c: -DefaultArtifactContentViewer.currentPageLabel.text=1 -DefaultArtifactContentViewer.ofLabel.text=/ -DefaultArtifactContentViewer.totalPageLabel.text=100 DefaultArtifactContentViewer.selectAllMenuItem.text=\u3059\u3079\u3066\u3092\u9078\u629e DefaultArtifactContentViewer.copyMenuItem.text=\u30b3\u30d4\u30fc diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.form index 08d2fc0205..37ea0f00fa 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.form @@ -76,175 +76,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java index 3b6515a8ca..7cbb279b21 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java @@ -26,14 +26,11 @@ import java.awt.event.ActionListener; import java.awt.datatransfer.StringSelection; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Collection; import java.util.Enumeration; import java.util.List; -import java.util.concurrent.ExecutionException; import java.util.logging.Level; import javax.swing.JMenuItem; import javax.swing.JTextArea; -import javax.swing.SwingWorker; import javax.swing.event.ChangeEvent; import javax.swing.event.ListSelectionEvent; import javax.swing.event.TableColumnModelEvent; @@ -42,8 +39,6 @@ import javax.swing.table.TableColumn; import javax.swing.event.TableColumnModelListener; import javax.swing.text.View; import org.apache.commons.lang.StringUtils; -import org.openide.nodes.Node; -import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.ContentUtils; @@ -51,46 +46,38 @@ import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.TskException; import org.netbeans.swing.etable.ETable; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonArray; import java.util.Map; +import javax.swing.SwingUtilities; /** - * This class displays a Blackboard artifact as a table listing all the - * attribute names and values. + * This class displays a Blackboard artifact as a table listing all it's + * attributes names and values. */ @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives public class DefaultArtifactContentViewer extends javax.swing.JPanel implements ArtifactContentViewer { @NbBundle.Messages({ - "DataContentViewerArtifact.attrsTableHeader.type=Type", - "DataContentViewerArtifact.attrsTableHeader.value=Value", - "DataContentViewerArtifact.attrsTableHeader.sources=Source(s)", + "DefaultArtifactContentViewer.attrsTableHeader.type=Type", + "DefaultArtifactContentViewer.attrsTableHeader.value=Value", + "DefaultArtifactContentViewer.attrsTableHeader.sources=Source(s)", "DataContentViewerArtifact.failedToGetSourcePath.message=Failed to get source file path from case database", "DataContentViewerArtifact.failedToGetAttributes.message=Failed to get some or all attributes from case database" }) - private final static Logger logger = Logger.getLogger(DefaultArtifactContentViewer.class.getName()); - private final static String WAIT_TEXT = NbBundle.getMessage(DefaultArtifactContentViewer.class, "DataContentViewerArtifact.waitText"); - private final static String ERROR_TEXT = NbBundle.getMessage(DefaultArtifactContentViewer.class, "DataContentViewerArtifact.errorText"); + private final static Logger logger = Logger.getLogger(DefaultArtifactContentViewer.class.getName()); + private static final long serialVersionUID = 1L; - private Node currentNode; // @@@ Remove this when the redundant setNode() calls problem is fixed. - private int currentPage = 1; - private final Object lock = new Object(); - - private List artifactTableContents; // Accessed by multiple threads, use getArtifactContents() and setArtifactContents() - SwingWorker currentTask; // Accessed by multiple threads, use startNewTask() - private static final String[] COLUMN_HEADERS = { - Bundle.DataContentViewerArtifact_attrsTableHeader_type(), - Bundle.DataContentViewerArtifact_attrsTableHeader_value(), - Bundle.DataContentViewerArtifact_attrsTableHeader_sources()}; + Bundle.DefaultArtifactContentViewer_attrsTableHeader_type(), + Bundle.DefaultArtifactContentViewer_attrsTableHeader_value(), + Bundle.DefaultArtifactContentViewer_attrsTableHeader_sources()}; private static final int[] COLUMN_WIDTHS = {100, 800, 100}; private static final int CELL_BOTTOM_MARGIN = 5; private static final int CELL_RIGHT_MARGIN = 1; @@ -109,6 +96,7 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements resultsTable.setModel(new javax.swing.table.DefaultTableModel() { private static final long serialVersionUID = 1L; + @Override public boolean isCellEditable(int rowIndex, int columnIndex) { return false; } @@ -203,22 +191,12 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { - java.awt.GridBagConstraints gridBagConstraints; rightClickMenu = new javax.swing.JPopupMenu(); copyMenuItem = new javax.swing.JMenuItem(); selectAllMenuItem = new javax.swing.JMenuItem(); jScrollPane1 = new javax.swing.JScrollPane(); jPanel1 = new javax.swing.JPanel(); - totalPageLabel = new javax.swing.JLabel(); - ofLabel = new javax.swing.JLabel(); - currentPageLabel = new javax.swing.JLabel(); - pageLabel = new javax.swing.JLabel(); - nextPageButton = new javax.swing.JButton(); - pageLabel2 = new javax.swing.JLabel(); - prevPageButton = new javax.swing.JButton(); - artifactLabel = new javax.swing.JLabel(); - filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0)); resultsTableScrollPane = new javax.swing.JScrollPane(); copyMenuItem.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.copyMenuItem.text")); // NOI18N @@ -234,112 +212,6 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements jPanel1.setPreferredSize(new java.awt.Dimension(620, 58)); jPanel1.setLayout(new java.awt.GridBagLayout()); - - totalPageLabel.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.totalPageLabel.text")); // NOI18N - totalPageLabel.setMaximumSize(new java.awt.Dimension(40, 16)); - totalPageLabel.setPreferredSize(new java.awt.Dimension(25, 16)); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 3; - gridBagConstraints.gridy = 0; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.insets = new java.awt.Insets(3, 12, 0, 0); - jPanel1.add(totalPageLabel, gridBagConstraints); - - ofLabel.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.ofLabel.text")); // NOI18N - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 2; - gridBagConstraints.gridy = 0; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.insets = new java.awt.Insets(3, 12, 0, 0); - jPanel1.add(ofLabel, gridBagConstraints); - - currentPageLabel.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.currentPageLabel.text")); // NOI18N - currentPageLabel.setMaximumSize(new java.awt.Dimension(38, 14)); - currentPageLabel.setMinimumSize(new java.awt.Dimension(18, 14)); - currentPageLabel.setPreferredSize(new java.awt.Dimension(20, 14)); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 0; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.insets = new java.awt.Insets(4, 7, 0, 0); - jPanel1.add(currentPageLabel, gridBagConstraints); - - pageLabel.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.pageLabel.text")); // NOI18N - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 0; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.insets = new java.awt.Insets(3, 12, 0, 0); - jPanel1.add(pageLabel, gridBagConstraints); - - nextPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"))); // NOI18N - nextPageButton.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.nextPageButton.text")); // NOI18N - nextPageButton.setBorderPainted(false); - nextPageButton.setContentAreaFilled(false); - nextPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); // NOI18N - nextPageButton.setMargin(new java.awt.Insets(2, 0, 2, 0)); - nextPageButton.setPreferredSize(new java.awt.Dimension(23, 23)); - nextPageButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"))); // NOI18N - nextPageButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - nextPageButtonActionPerformed(evt); - } - }); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 6; - gridBagConstraints.gridy = 0; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.insets = new java.awt.Insets(0, 0, 35, 0); - jPanel1.add(nextPageButton, gridBagConstraints); - - pageLabel2.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.pageLabel2.text")); // NOI18N - pageLabel2.setMaximumSize(new java.awt.Dimension(29, 14)); - pageLabel2.setMinimumSize(new java.awt.Dimension(29, 14)); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 4; - gridBagConstraints.gridy = 0; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.insets = new java.awt.Insets(3, 41, 0, 0); - jPanel1.add(pageLabel2, gridBagConstraints); - - prevPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); // NOI18N - prevPageButton.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.prevPageButton.text")); // NOI18N - prevPageButton.setBorderPainted(false); - prevPageButton.setContentAreaFilled(false); - prevPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); // NOI18N - prevPageButton.setMargin(new java.awt.Insets(2, 0, 2, 0)); - prevPageButton.setPreferredSize(new java.awt.Dimension(23, 23)); - prevPageButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"))); // NOI18N - prevPageButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - prevPageButtonActionPerformed(evt); - } - }); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 5; - gridBagConstraints.gridy = 0; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.insets = new java.awt.Insets(0, 5, 35, 0); - jPanel1.add(prevPageButton, gridBagConstraints); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 8; - gridBagConstraints.gridy = 0; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST; - gridBagConstraints.insets = new java.awt.Insets(3, 0, 0, 8); - jPanel1.add(artifactLabel, gridBagConstraints); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 7; - gridBagConstraints.gridy = 0; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.weightx = 0.1; - jPanel1.add(filler1, gridBagConstraints); - jScrollPane1.setViewportView(jPanel1); resultsTableScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); @@ -362,36 +234,13 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements ); }// //GEN-END:initComponents - private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed - currentPage = currentPage + 1; - currentPageLabel.setText(Integer.toString(currentPage)); - artifactLabel.setText(artifactTableContents.get(currentPage - 1).getArtifactDisplayName()); - startNewTask(new SelectedArtifactChangedTask(currentPage)); - }//GEN-LAST:event_nextPageButtonActionPerformed - - private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevPageButtonActionPerformed - currentPage = currentPage - 1; - currentPageLabel.setText(Integer.toString(currentPage)); - artifactLabel.setText(artifactTableContents.get(currentPage - 1).getArtifactDisplayName()); - startNewTask(new SelectedArtifactChangedTask(currentPage)); - }//GEN-LAST:event_prevPageButtonActionPerformed - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel artifactLabel; private javax.swing.JMenuItem copyMenuItem; - private javax.swing.JLabel currentPageLabel; - private javax.swing.Box.Filler filler1; private javax.swing.JPanel jPanel1; private javax.swing.JScrollPane jScrollPane1; - private javax.swing.JButton nextPageButton; - private javax.swing.JLabel ofLabel; - private javax.swing.JLabel pageLabel; - private javax.swing.JLabel pageLabel2; - private javax.swing.JButton prevPageButton; private javax.swing.JScrollPane resultsTableScrollPane; private javax.swing.JPopupMenu rightClickMenu; private javax.swing.JMenuItem selectAllMenuItem; - private javax.swing.JLabel totalPageLabel; // End of variables declaration//GEN-END:variables private ETable resultsTable; @@ -428,14 +277,8 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements * Resets the components to an empty view state. */ private void resetComponents() { - currentPage = 1; - currentPageLabel.setText(""); - artifactLabel.setText(""); - totalPageLabel.setText(""); + ((DefaultTableModel) resultsTable.getModel()).setRowCount(0); - prevPageButton.setEnabled(false); - nextPageButton.setEnabled(false); - currentNode = null; } @Override @@ -445,18 +288,31 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements @Override public void setArtifact(BlackboardArtifact artifact) { - // RAMAN TBD: ****************** IMPLMENT THIS. ********************** - + try { + ResultsTableArtifact resultsTableArtifact = new ResultsTableArtifact(artifact, artifact.getParent()); + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + updateView(resultsTableArtifact); + } + }); + + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Error getting parent content for artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex); + } + } @Override public boolean isSupported(BlackboardArtifact artifact) { + // This viewer supports all artifacts. return true; } /** - * This class is a container to hold the data necessary for each of the - * result pages associated with file or artifact beivng viewed. + * This class is a container to hold the data necessary for the artifact + * being viewed. */ private class ResultsTableArtifact { @@ -492,7 +348,7 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements /* * Attribute value column. */ - String value = ""; + String value; switch (attr.getAttributeType().getValueType()) { case STRING: case INTEGER: @@ -634,46 +490,17 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements } /** - * Instances of this class are simple containers for view update information - * generated by a background thread. - */ - private class ViewUpdate { - - int numberOfPages; - int currentPage; - ResultsTableArtifact tableContents; - - ViewUpdate(int numberOfPages, int currentPage, ResultsTableArtifact contents) { - this.currentPage = currentPage; - this.numberOfPages = numberOfPages; - this.tableContents = contents; - } - - ViewUpdate(int numberOfPages, int currentPage, String errorMsg) { - this.currentPage = currentPage; - this.numberOfPages = numberOfPages; - this.tableContents = new ResultsTableArtifact(errorMsg); - } - } - - /** - * Called from queued SwingWorker done() methods on the EDT thread, so - * doesn't need to be synchronized. + * Updates the table view with the given artifact data. + * + * It should be called on EDT. * - * @param viewUpdate A simple container for display update information from - * a background thread. + * @param resultsTableArtifact Artifact data to display in the view. */ - private void updateView(ViewUpdate viewUpdate) { + private void updateView(ResultsTableArtifact resultsTableArtifact) { this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - nextPageButton.setEnabled(viewUpdate.currentPage < viewUpdate.numberOfPages); - prevPageButton.setEnabled(viewUpdate.currentPage > 1); - currentPage = viewUpdate.currentPage; - totalPageLabel.setText(Integer.toString(viewUpdate.numberOfPages)); - currentPageLabel.setText(Integer.toString(currentPage)); - artifactLabel.setText(viewUpdate.tableContents.getArtifactDisplayName()); DefaultTableModel tModel = ((DefaultTableModel) resultsTable.getModel()); - tModel.setDataVector(viewUpdate.tableContents.getRows(), COLUMN_HEADERS); + tModel.setDataVector(resultsTableArtifact.getRows(), COLUMN_HEADERS); updateColumnSizes(); updateRowHeights(); resultsTable.clearSelection(); @@ -681,216 +508,6 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements this.setCursor(null); } - /** - * Start a new task on its own background thread, canceling the previous - * task. - * - * @param task A new SwingWorker object to execute as a background thread. - */ - private synchronized void startNewTask(SwingWorker task) { - String[][] waitRow = new String[1][3]; - waitRow[0] = new String[]{"", WAIT_TEXT, ""}; - DefaultTableModel tModel = ((DefaultTableModel) resultsTable.getModel()); - tModel.setDataVector(waitRow, COLUMN_HEADERS); - updateColumnSizes(); - updateRowHeights(); - resultsTable.clearSelection(); - // The output of the previous task is no longer relevant. - if (currentTask != null) { - // This call sets a cancellation flag. It does not terminate the background thread running the task. - // The task must check the cancellation flag and react appropriately. - currentTask.cancel(false); - } - - // Start the new task. - currentTask = task; - currentTask.execute(); - } - - /** - * Populate the cache of artifact represented as ResultsTableArtifacts. - * - * @param artifactList A list of ResultsTableArtifact representations of - * artifacts. - */ - private void setArtifactContents(List artifactList) { - synchronized (lock) { - this.artifactTableContents = artifactList; - } - } - - /** - * Retrieve the cache of artifact represented as ResultsTableArtifacts. - * - * @return A list of ResultsTableArtifact representations of artifacts. - */ - private List getArtifactContents() { - synchronized (lock) { - return artifactTableContents; - } - } - - /** - * Instances of this class use a background thread to generate a ViewUpdate - * when a node is selected, changing the set of blackboard artifacts - * ("results") to be displayed. - */ - private class SelectedNodeChangedTask extends SwingWorker { - - private final Node selectedNode; - - SelectedNodeChangedTask(Node selectedNode) { - this.selectedNode = selectedNode; - } - - @Override - protected ViewUpdate doInBackground() { - // Get the lookup for the node for access to its underlying content and - // blackboard artifact, if any. - Lookup lookup = selectedNode.getLookup(); - - // Get the content. We may get BlackboardArtifacts, ignore those here. - ArrayList artifacts = new ArrayList<>(); - Collection contents = lookup.lookupAll(Content.class); - if (contents.isEmpty()) { - return new ViewUpdate(getArtifactContents().size(), currentPage, ERROR_TEXT); - } - Content underlyingContent = null; - for (Content content : contents) { - if ( (content != null) && (!(content instanceof BlackboardArtifact)) ) { - // Get all of the blackboard artifacts associated with the content. These are what this - // viewer displays. - try { - artifacts = content.getAllArtifacts(); - underlyingContent = content; - break; - } catch (TskException ex) { - logger.log(Level.SEVERE, "Couldn't get artifacts", ex); //NON-NLS - return new ViewUpdate(getArtifactContents().size(), currentPage, ERROR_TEXT); - } - } - } - - if (isCancelled()) { - return null; - } - - // Build the new artifact contents cache. - ArrayList artifactContents = new ArrayList<>(); - for (BlackboardArtifact artifact : artifacts) { - artifactContents.add(new ResultsTableArtifact(artifact, underlyingContent)); - } - - // If the node has an underlying blackboard artifact, show it. If not, - // show the first artifact. - int index = 0; - BlackboardArtifact artifact = lookup.lookup(BlackboardArtifact.class); - if (artifact != null) { - index = artifacts.indexOf(artifact); - if (index == -1) { - index = 0; - } else { - // if the artifact has an ASSOCIATED ARTIFACT, then we display the associated artifact instead - try { - for (BlackboardAttribute attr : artifact.getAttributes()) { - if (attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) { - long assocArtifactId = attr.getValueLong(); - int assocArtifactIndex = -1; - for (BlackboardArtifact art : artifacts) { - if (assocArtifactId == art.getArtifactID()) { - assocArtifactIndex = artifacts.indexOf(art); - break; - } - } - if (assocArtifactIndex >= 0) { - index = assocArtifactIndex; - } - break; - } - } - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Couldn't get associated artifact to display in Content Viewer.", ex); //NON-NLS - } - } - - } - - if (isCancelled()) { - return null; - } - - // Add one to the index of the artifact content for the corresponding page index. - ViewUpdate viewUpdate = new ViewUpdate(artifactContents.size(), index + 1, artifactContents.get(index)); - - // It may take a considerable amount of time to fetch the attributes of the selected artifact - if (isCancelled()) { - return null; - } - - // Update the artifact contents cache. - setArtifactContents(artifactContents); - - return viewUpdate; - } - - @Override - protected void done() { - if (!isCancelled()) { - try { - ViewUpdate viewUpdate = get(); - if (viewUpdate != null) { - updateView(viewUpdate); - } - } catch (InterruptedException | ExecutionException ex) { - logger.log(Level.WARNING, "Artifact display task unexpectedly interrupted or failed", ex); //NON-NLS - } - } - } - } - - /** - * Instances of this class use a background thread to generate a ViewUpdate - * when the user pages the view to look at another blackboard artifact - * ("result"). - */ - private class SelectedArtifactChangedTask extends SwingWorker { - - private final int pageIndex; - - SelectedArtifactChangedTask(final int pageIndex) { - this.pageIndex = pageIndex; - } - - @Override - protected ViewUpdate doInBackground() { - // Get the artifact content to display from the cache. Note that one must be subtracted from the - // page index to get the corresponding artifact content index. - List artifactContents = getArtifactContents(); - ResultsTableArtifact artifactContent = artifactContents.get(pageIndex - 1); - - // It may take a considerable amount of time to fetch the attributes of the selected artifact so check for cancellation. - if (isCancelled()) { - return null; - } - - return new ViewUpdate(artifactContents.size(), pageIndex, artifactContent); - } - - @Override - protected void done() { - if (!isCancelled()) { - try { - ViewUpdate viewUpdate = get(); - if (viewUpdate != null) { - updateView(viewUpdate); - } - } catch (InterruptedException | ExecutionException ex) { - logger.log(Level.WARNING, "Artifact display task unexpectedly interrupted or failed", ex); //NON-NLS - } - } - } - } - /** * TableCellRenderer for displaying multiline text. */ diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index 4eb87c3496..8834b0f5d7 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -30,8 +30,6 @@ DataContentViewerArtifact.pageLabel2.text=Result DataContentViewerArtifact.nextPageButton.text= DataContentViewerArtifact.currentPageLabel.text=1 DataContentViewerArtifact.ofLabel.text=of -DataContentViewerArtifact.copyMenuItem.text=Copy -DataContentViewerArtifact.selectAllMenuItem.text=Select All DataContentViewerArtifact.pageLabel.text=Result: AdvancedConfigurationDialog.applyButton.text=OK DataContentViewerHex.goToPageTextField.text= @@ -218,4 +216,3 @@ DataResultViewerTable.exportCSVButton.text=Save Table as CSV ViewPreferencesPanel.scoColumnsCheckbox.text=S(core), C(omments), and O(ccurences) ViewPreferencesPanel.scoColumnsWrapAroundText.text=to reduce loading times ViewPreferencesPanel.scoColumnsLabel.text=Do not add columns for: -DataContentViewerArtifact.jLabel1.text=Artifact Content View diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle_ja.properties index 6f941632c8..ec91946e79 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle_ja.properties @@ -82,8 +82,6 @@ DataContentViewerArtifact.pageLabel2.text=\u7d50\u679c DataContentViewerArtifact.nextPageButton.text= DataContentViewerArtifact.currentPageLabel.text=1 DataContentViewerArtifact.ofLabel.text=/ -DataContentViewerArtifact.copyMenuItem.text=\u30b3\u30d4\u30fc -DataContentViewerArtifact.selectAllMenuItem.text=\u3059\u3079\u3066\u3092\u9078\u629e DataContentViewerArtifact.pageLabel.text=\u7d50\u679c: AdvancedConfigurationDialog.applyButton.text=OK DataContentViewerHex.goToPageTextField.text= diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.form index 52207ebf35..c4928f5111 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.form @@ -1,30 +1,6 @@
- - - - - - - - - - - - - - - - - - - - - - - - @@ -45,26 +21,16 @@ - - + - - - - - - - - - - - + + @@ -258,27 +224,6 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java index 9c44648c65..bb6fc2e1b3 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java @@ -20,187 +20,67 @@ package org.sleuthkit.autopsy.corecomponents; import java.awt.Component; import java.awt.Cursor; -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.datatransfer.StringSelection; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; -import java.util.Enumeration; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.logging.Level; -import javax.swing.JMenuItem; -import javax.swing.JTextArea; import javax.swing.SwingWorker; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.TableColumnModelEvent; -import javax.swing.table.DefaultTableModel; -import javax.swing.table.TableColumn; -import javax.swing.event.TableColumnModelListener; -import javax.swing.text.View; -import org.apache.commons.lang.StringUtils; import org.openide.nodes.Node; import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskException; -import org.netbeans.swing.etable.ETable; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.JsonArray; import java.util.Arrays; -import java.util.Map; +import java.util.Collections; import org.sleuthkit.autopsy.contentviewers.ArtifactContentViewer; -import org.sleuthkit.autopsy.contentviewers.DummyArtifactContentViewer; -import org.sleuthkit.autopsy.contentviewers.MessageContentViewer; +import org.sleuthkit.autopsy.contentviewers.DefaultArtifactContentViewer; /** * Instances of this class display the BlackboardArtifacts associated with the - * Content represented by a Node. Each BlackboardArtifact is rendered displayed - * in a JTable representation of its BlackboardAttributes. + * Content represented by a Node. + * + * It goes through a list of known ArtifactContentViewer to find a viewer that + * supports a given artifact and then hands it the artifact to display. */ @ServiceProvider(service = DataContentViewer.class, position = 7) @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives public class DataContentViewerArtifact extends javax.swing.JPanel implements DataContentViewer { + private static final long serialVersionUID = 1L; + @NbBundle.Messages({ - "DataContentViewerArtifact.attrsTableHeader.type=Type", - "DataContentViewerArtifact.attrsTableHeader.value=Value", - "DataContentViewerArtifact.attrsTableHeader.sources=Source(s)", "DataContentViewerArtifact.failedToGetSourcePath.message=Failed to get source file path from case database", "DataContentViewerArtifact.failedToGetAttributes.message=Failed to get some or all attributes from case database" }) private final static Logger logger = Logger.getLogger(DataContentViewerArtifact.class.getName()); private final static String WAIT_TEXT = NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.waitText"); private final static String ERROR_TEXT = NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.errorText"); + private Node currentNode; // @@@ Remove this when the redundant setNode() calls problem is fixed. private int currentPage = 1; private final Object lock = new Object(); - private List artifactTableContents; // Accessed by multiple threads, use getArtifactContents() and setArtifactContents() - SwingWorker currentTask; // Accessed by multiple threads, use startNewTask() - private static final String[] COLUMN_HEADERS = { - Bundle.DataContentViewerArtifact_attrsTableHeader_type(), - Bundle.DataContentViewerArtifact_attrsTableHeader_value(), - Bundle.DataContentViewerArtifact_attrsTableHeader_sources()}; - private static final int[] COLUMN_WIDTHS = {100, 800, 100}; - private static final int CELL_BOTTOM_MARGIN = 5; - private static final int CELL_RIGHT_MARGIN = 1; + private List artifactTableContents; // Accessed by multiple threads, use getArtifactContents() and setArtifactContents() + private SwingWorker currentTask; // Accessed by multiple threads, use startNewTask() + private final Collection KNOWN_ARTIFACT_VIEWERS = Arrays.asList( - // RAMAN TBD: new MessageContentViewer() + // TBD: populate with custom artifact viewers. ); public DataContentViewerArtifact() { - initResultsTable(); + initComponents(); - resultsTableScrollPane.setViewportView(resultsTable); - customizeComponents(); + resetComponents(); - resultsTable.setDefaultRenderer(Object.class, new MultiLineTableCellRenderer()); - } - - private void initResultsTable() { - resultsTable = new ETable(); - resultsTable.setModel(new javax.swing.table.DefaultTableModel() { - private static final long serialVersionUID = 1L; - - public boolean isCellEditable(int rowIndex, int columnIndex) { - return false; - } - }); - resultsTable.setCellSelectionEnabled(true); - resultsTable.getTableHeader().setReorderingAllowed(false); - resultsTable.setColumnHidingAllowed(false); - resultsTable.getColumnModel().getSelectionModel().setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION); - resultsTable.getColumnModel().addColumnModelListener(new TableColumnModelListener() { - - @Override - public void columnAdded(TableColumnModelEvent e) { - } - - @Override - public void columnRemoved(TableColumnModelEvent e) { - } - - @Override - public void columnMoved(TableColumnModelEvent e) { - - } - - @Override - public void columnMarginChanged(ChangeEvent e) { - updateRowHeights(); //When the user changes column width we may need to resize row height - } - - @Override - public void columnSelectionChanged(ListSelectionEvent e) { - } - }); - resultsTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_NEXT_COLUMN); - - } - - /** - * Sets the row heights to the heights of the content in their Value column. - */ - private void updateRowHeights() { - int valueColIndex = -1; - for (int col = 0; col < resultsTable.getColumnCount(); col++) { - if (resultsTable.getColumnName(col).equals(COLUMN_HEADERS[1])) { - valueColIndex = col; - } - } - if (valueColIndex != -1) { - for (int row = 0; row < resultsTable.getRowCount(); row++) { - Component comp = resultsTable.prepareRenderer( - resultsTable.getCellRenderer(row, valueColIndex), row, valueColIndex); - final int rowHeight; - if (comp instanceof JTextArea) { - final JTextArea tc = (JTextArea) comp; - final View rootView = tc.getUI().getRootView(tc); - java.awt.Insets i = tc.getInsets(); - rootView.setSize(resultsTable.getColumnModel().getColumn(valueColIndex) - .getWidth() - (i.left + i.right +CELL_RIGHT_MARGIN), //current width minus borders - Integer.MAX_VALUE); - rowHeight = (int) rootView.getPreferredSpan(View.Y_AXIS); - } else { - rowHeight = comp.getPreferredSize().height; - } - if (rowHeight > 0) { - resultsTable.setRowHeight(row, rowHeight + CELL_BOTTOM_MARGIN); - } - } - } - } - - /** - * Update the column widths so that the Value column has most of the space. - */ - private void updateColumnSizes() { - Enumeration columns = resultsTable.getColumnModel().getColumns(); - while (columns.hasMoreElements()) { - TableColumn col = columns.nextElement(); - if (col.getHeaderValue().equals(COLUMN_HEADERS[0])) { - col.setPreferredWidth(COLUMN_WIDTHS[0]); - } else if (col.getHeaderValue().equals(COLUMN_HEADERS[1])) { - col.setPreferredWidth(COLUMN_WIDTHS[1]); - } else if (col.getHeaderValue().equals(COLUMN_HEADERS[2])) { - col.setPreferredWidth(COLUMN_WIDTHS[2]); - } - } } /** @@ -213,9 +93,6 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; - rightClickMenu = new javax.swing.JPopupMenu(); - copyMenuItem = new javax.swing.JMenuItem(); - selectAllMenuItem = new javax.swing.JMenuItem(); jScrollPane1 = new javax.swing.JScrollPane(); jPanel1 = new javax.swing.JPanel(); totalPageLabel = new javax.swing.JLabel(); @@ -227,16 +104,8 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat prevPageButton = new javax.swing.JButton(); artifactLabel = new javax.swing.JLabel(); filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0)); - resultsTableScrollPane = new javax.swing.JScrollPane(); - jLabel1 = new javax.swing.JLabel(); artifactContentPanel = new javax.swing.JPanel(); - copyMenuItem.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.copyMenuItem.text")); // NOI18N - rightClickMenu.add(copyMenuItem); - - selectAllMenuItem.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.selectAllMenuItem.text")); // NOI18N - rightClickMenu.add(selectAllMenuItem); - setPreferredSize(new java.awt.Dimension(100, 58)); jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); @@ -352,60 +221,43 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat jScrollPane1.setViewportView(jPanel1); - resultsTableScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); - resultsTableScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); - resultsTableScrollPane.setPreferredSize(new java.awt.Dimension(620, 34)); - - jLabel1.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.jLabel1.text")); // NOI18N - artifactContentPanel.setLayout(new javax.swing.OverlayLayout(artifactContentPanel)); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 476, Short.MAX_VALUE) - .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 476, Short.MAX_VALUE) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 561, Short.MAX_VALUE) .addComponent(artifactContentPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createSequentialGroup() - .addGap(166, 166, 166) - .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 129, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 130, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jLabel1) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(artifactContentPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 134, Short.MAX_VALUE)) + .addComponent(artifactContentPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 397, Short.MAX_VALUE)) ); }// //GEN-END:initComponents private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed - currentPage = currentPage + 1; + currentPage += 1; currentPageLabel.setText(Integer.toString(currentPage)); - artifactLabel.setText(artifactTableContents.get(currentPage - 1).getArtifactDisplayName()); + artifactLabel.setText(artifactTableContents.get(currentPage - 1).getDisplayName()); startNewTask(new SelectedArtifactChangedTask(currentPage)); }//GEN-LAST:event_nextPageButtonActionPerformed private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevPageButtonActionPerformed - currentPage = currentPage - 1; + currentPage -= 1; currentPageLabel.setText(Integer.toString(currentPage)); - artifactLabel.setText(artifactTableContents.get(currentPage - 1).getArtifactDisplayName()); + artifactLabel.setText(artifactTableContents.get(currentPage - 1).getDisplayName()); startNewTask(new SelectedArtifactChangedTask(currentPage)); }//GEN-LAST:event_prevPageButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel artifactContentPanel; private javax.swing.JLabel artifactLabel; - private javax.swing.JMenuItem copyMenuItem; private javax.swing.JLabel currentPageLabel; private javax.swing.Box.Filler filler1; - private javax.swing.JLabel jLabel1; private javax.swing.JPanel jPanel1; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JButton nextPageButton; @@ -413,41 +265,9 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat private javax.swing.JLabel pageLabel; private javax.swing.JLabel pageLabel2; private javax.swing.JButton prevPageButton; - private javax.swing.JScrollPane resultsTableScrollPane; - private javax.swing.JPopupMenu rightClickMenu; - private javax.swing.JMenuItem selectAllMenuItem; private javax.swing.JLabel totalPageLabel; // End of variables declaration//GEN-END:variables - private ETable resultsTable; - private void customizeComponents() { - resultsTable.setComponentPopupMenu(rightClickMenu); - ActionListener actList = new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - JMenuItem jmi = (JMenuItem) e.getSource(); - if (jmi.equals(copyMenuItem)) { - StringBuilder selectedText = new StringBuilder(512); - for (int row : resultsTable.getSelectedRows()) { - for (int col : resultsTable.getSelectedColumns()) { - selectedText.append((String) resultsTable.getValueAt(row, col)); - selectedText.append("\t"); - } - //if its the last row selected don't add a new line - if (row != resultsTable.getSelectedRows()[resultsTable.getSelectedRows().length - 1]) { - selectedText.append(System.lineSeparator()); - } - } - Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(selectedText.toString()), null); - } else if (jmi.equals(selectAllMenuItem)) { - resultsTable.selectAll(); - } - } - }; - copyMenuItem.addActionListener(actList); - - selectAllMenuItem.addActionListener(actList); - } /** * Resets the components to an empty view state. @@ -457,10 +277,12 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat currentPageLabel.setText(""); artifactLabel.setText(""); totalPageLabel.setText(""); - ((DefaultTableModel) resultsTable.getModel()).setRowCount(0); + prevPageButton.setEnabled(false); nextPageButton.setEnabled(false); currentNode = null; + + artifactContentPanel.removeAll(); } @Override @@ -552,194 +374,8 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat return this.KNOWN_ARTIFACT_VIEWERS.stream() .filter(knownViewer -> knownViewer.isSupported(artifact)) .findAny() - .orElse(new DummyArtifactContentViewer()); // RAMAN TBD: return the default viewer here + .orElse(new DefaultArtifactContentViewer()); - } - /** - * This class is a container to hold the data necessary for each of the - * result pages associated with file or artifact being viewed. - */ - private class ResultsTableArtifact { - - private final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - private String[][] rowData = null; - private final String artifactDisplayName; - private final Content content; - private final BlackboardArtifact artifact; - - ResultsTableArtifact(BlackboardArtifact artifact, Content content) { - artifactDisplayName = artifact.getDisplayName(); - this.content = content; - this.artifact = artifact; - addRows(artifact); - } - - ResultsTableArtifact(String errorMsg) { - artifactDisplayName = errorMsg; - rowData = new String[1][3]; - rowData[0] = new String[]{"", errorMsg, ""}; - content = null; - artifact = null; - } - - private String[][] getRows() { - return rowData; - } - - BlackboardArtifact getArtifact() { - return this.artifact; - } - - private void addRows(BlackboardArtifact artifact) { - List rowsToAdd = new ArrayList<>(); - try { - /* - * Add rows for each attribute. - */ - for (BlackboardAttribute attr : artifact.getAttributes()) { - /* - * Attribute value column. - */ - String value = ""; - switch (attr.getAttributeType().getValueType()) { - case STRING: - case INTEGER: - case LONG: - case DOUBLE: - case BYTE: - default: - value = attr.getDisplayString(); - break; - // Use Autopsy date formatting settings, not TSK defaults - case DATETIME: - value = epochTimeToString(attr.getValueLong()); - break; - case JSON: - // Get the attribute's JSON value and convert to indented multiline display string - String jsonVal = attr.getValueString(); - JsonParser parser = new JsonParser(); - JsonObject json = parser.parse(jsonVal).getAsJsonObject(); - - value = toJsonDisplayString(json, ""); - break; - } - /* - * Attribute sources column. - */ - String sources = StringUtils.join(attr.getSources(), ", "); - rowsToAdd.add(new String[]{attr.getAttributeType().getDisplayName(), value, sources}); - } - /* - * Add a row for the source content path. - */ - String path = ""; - try { - if (null != content) { - path = content.getUniquePath(); - } - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, String.format("Error getting source content path for artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex); - path = Bundle.DataContentViewerArtifact_failedToGetSourcePath_message(); - } - rowsToAdd.add(new String[]{"Source File Path", path, ""}); - /* - * Add a row for the artifact id. - */ - rowsToAdd.add(new String[]{"Artifact ID", Long.toString(artifact.getArtifactID()), ""}); - } catch (TskCoreException ex) { - rowsToAdd.add(new String[]{"", Bundle.DataContentViewerArtifact_failedToGetAttributes_message(), ""}); - } - rowData = rowsToAdd.toArray(new String[0][0]); - } - - /** - * @return the artifactDisplayName - */ - String getArtifactDisplayName() { - return artifactDisplayName; - } - - - private static final String INDENT_RIGHT = " "; - private static final String NEW_LINE = "\n"; - - /** - * Recursively converts a JSON element into an indented multi-line - * display string. - * - * @param element JSON element to convert - * @param startIndent Starting indentation for the element. - * - * @return A multi-line display string. - */ - private String toJsonDisplayString(JsonElement element, String startIndent) { - - StringBuilder sb = new StringBuilder(""); - JsonObject obj = element.getAsJsonObject(); - - for (Map.Entry entry : obj.entrySet()) { - appendJsonElementToString(entry.getKey(), entry.getValue(), startIndent, sb ); - } - - String returnString = sb.toString(); - if (startIndent.length() == 0 && returnString.startsWith(NEW_LINE)) { - returnString = returnString.substring(NEW_LINE.length()); - } - return returnString; - } - - - /** - * Converts the given JSON element into string and appends to the given string builder. - * - * @param jsonKey - * @param jsonElement - * @param startIndent Starting indentation for the element. - * @param sb String builder to append to. - */ - private void appendJsonElementToString(String jsonKey, JsonElement jsonElement, String startIndent, StringBuilder sb) { - if (jsonElement.isJsonArray()) { - JsonArray jsonArray = jsonElement.getAsJsonArray(); - if (jsonArray.size() > 0) { - int count = 1; - sb.append(NEW_LINE).append(String.format("%s%s", startIndent, jsonKey)); - for (JsonElement arrayMember : jsonArray) { - sb.append(NEW_LINE).append(String.format("%s%d", startIndent.concat(INDENT_RIGHT), count)); - sb.append(toJsonDisplayString(arrayMember, startIndent.concat(INDENT_RIGHT).concat(INDENT_RIGHT))); - count++; - } - } - } else if (jsonElement.isJsonObject()) { - sb.append(NEW_LINE).append(String.format("%s%s %s", startIndent, jsonKey, toJsonDisplayString(jsonElement.getAsJsonObject(), startIndent + INDENT_RIGHT))); - } else if (jsonElement.isJsonPrimitive()) { - String attributeName = jsonKey; - String attributeValue; - if (attributeName.toUpperCase().contains("DATETIME")) { - attributeValue = epochTimeToString(Long.parseLong(jsonElement.getAsString())); - } else { - attributeValue = jsonElement.getAsString(); - } - sb.append(NEW_LINE).append(String.format("%s%s = %s", startIndent, attributeName, attributeValue)); - } else if (jsonElement.isJsonNull()) { - sb.append(NEW_LINE).append(String.format("%s%s = null", startIndent, jsonKey)); - } - } - - /** - * Converts epoch time to readable string. - * - * @param epochTime epoch time value to be converted to string. - * @return String with human readable time. - */ - private String epochTimeToString(long epochTime) { - String dateTimeString = "0000-00-00 00:00:00"; - if (null != content && 0 != epochTime) { - dateFormatter.setTimeZone(ContentUtils.getTimeZone(content)); - dateTimeString = dateFormatter.format(new java.util.Date(epochTime * 1000)); - } - return dateTimeString; - } - } /** @@ -750,18 +386,21 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat int numberOfPages; int currentPage; - ResultsTableArtifact tableContents; + BlackboardArtifact artifact; + String errorMsg; - ViewUpdate(int numberOfPages, int currentPage, ResultsTableArtifact contents) { + ViewUpdate(int numberOfPages, int currentPage, BlackboardArtifact artifact) { this.currentPage = currentPage; this.numberOfPages = numberOfPages; - this.tableContents = contents; + this.artifact = artifact; + this.errorMsg = null; } ViewUpdate(int numberOfPages, int currentPage, String errorMsg) { this.currentPage = currentPage; this.numberOfPages = numberOfPages; - this.tableContents = new ResultsTableArtifact(errorMsg); + this.errorMsg = errorMsg; + this.artifact = null; } } @@ -780,21 +419,23 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat currentPage = viewUpdate.currentPage; totalPageLabel.setText(Integer.toString(viewUpdate.numberOfPages)); currentPageLabel.setText(Integer.toString(currentPage)); - artifactLabel.setText(viewUpdate.tableContents.getArtifactDisplayName()); - DefaultTableModel tModel = ((DefaultTableModel) resultsTable.getModel()); - tModel.setDataVector(viewUpdate.tableContents.getRows(), COLUMN_HEADERS); - updateColumnSizes(); - updateRowHeights(); - resultsTable.clearSelection(); - - BlackboardArtifact artifact = viewUpdate.tableContents.getArtifact(); - ArtifactContentViewer viewer = this.getSupportingViewer(artifact); - viewer.setArtifact(artifact); + artifactContentPanel.removeAll(); - artifactContentPanel.add(viewer.getComponent()); - artifactContentPanel.revalidate(); + if (viewUpdate.artifact != null) { + artifactLabel.setText(viewUpdate.artifact.getDisplayName()); + + BlackboardArtifact artifact = viewUpdate.artifact; + ArtifactContentViewer viewer = this.getSupportingViewer(artifact); + viewer.setArtifact(artifact); + + artifactContentPanel.add(viewer.getComponent()); + } else { + artifactLabel.setText(viewUpdate.errorMsg); + } + + artifactContentPanel.revalidate(); this.setCursor(null); this.revalidate(); @@ -807,13 +448,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat * @param task A new SwingWorker object to execute as a background thread. */ private synchronized void startNewTask(SwingWorker task) { - String[][] waitRow = new String[1][3]; - waitRow[0] = new String[]{"", WAIT_TEXT, ""}; - DefaultTableModel tModel = ((DefaultTableModel) resultsTable.getModel()); - tModel.setDataVector(waitRow, COLUMN_HEADERS); - updateColumnSizes(); - updateRowHeights(); - resultsTable.clearSelection(); + // The output of the previous task is no longer relevant. if (currentTask != null) { // This call sets a cancellation flag. It does not terminate the background thread running the task. @@ -827,12 +462,12 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat } /** - * Populate the cache of artifact represented as ResultsTableArtifacts. + * Populate the cache of artifacts represented as ResultsTableArtifacts. * * @param artifactList A list of ResultsTableArtifact representations of * artifacts. */ - private void setArtifactContents(List artifactList) { + private void setArtifactContents(List artifactList) { synchronized (lock) { this.artifactTableContents = artifactList; } @@ -841,11 +476,11 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat /** * Retrieve the cache of artifact represented as ResultsTableArtifacts. * - * @return A list of ResultsTableArtifact representations of artifacts. + * @return A list of artifacts. */ - private List getArtifactContents() { + private List getArtifactContents() { synchronized (lock) { - return artifactTableContents; + return Collections.unmodifiableList(artifactTableContents); } } @@ -895,9 +530,9 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat } // Build the new artifact contents cache. - ArrayList artifactContents = new ArrayList<>(); + ArrayList artifactContents = new ArrayList<>(); for (BlackboardArtifact artifact : artifacts) { - artifactContents.add(new ResultsTableArtifact(artifact, underlyingContent)); + artifactContents.add(artifact); } // If the node has an underlying blackboard artifact, show it. If not, @@ -984,8 +619,8 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat protected ViewUpdate doInBackground() { // Get the artifact content to display from the cache. Note that one must be subtracted from the // page index to get the corresponding artifact content index. - List artifactContents = getArtifactContents(); - ResultsTableArtifact artifactContent = artifactContents.get(pageIndex - 1); + List artifactContents = getArtifactContents(); + BlackboardArtifact artifactContent = artifactContents.get(pageIndex - 1); // It may take a considerable amount of time to fetch the attributes of the selected artifact so check for cancellation. if (isCancelled()) { @@ -1009,27 +644,4 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat } } } - - /** - * TableCellRenderer for displaying multiline text. - */ - private class MultiLineTableCellRenderer implements javax.swing.table.TableCellRenderer { - - @Override - public Component getTableCellRendererComponent(javax.swing.JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - javax.swing.JTextArea jtex = new javax.swing.JTextArea(); - if (value instanceof String) { - jtex.setText((String) value); - jtex.setLineWrap(true); - jtex.setWrapStyleWord(false); - } - //cell backgroud color when selected - if (isSelected) { - jtex.setBackground(javax.swing.UIManager.getColor("Table.selectionBackground")); - } else { - jtex.setBackground(javax.swing.UIManager.getColor("Table.background")); - } - return jtex; - } - } } From 028237f1dc92415629004356dd718f5ece24af2c Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Mon, 11 May 2020 18:22:16 -0400 Subject: [PATCH 5/8] Removed the interim DummyArtifactContentViewer. --- .../DummyArtifactContentViewer.form | 85 -------------- .../DummyArtifactContentViewer.java | 108 ------------------ 2 files changed, 193 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.form delete mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.java diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.form deleted file mode 100644 index b7cef5505b..0000000000 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.form +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.java deleted file mode 100644 index edc793f98b..0000000000 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.sleuthkit.autopsy.contentviewers; - -import java.awt.Component; -import org.sleuthkit.datamodel.BlackboardArtifact; - -/** - * - * @author raman - */ -public class DummyArtifactContentViewer extends javax.swing.JPanel implements ArtifactContentViewer { - - /** - * Creates new form DummyArtifactContentViewer - */ - public DummyArtifactContentViewer() { - initComponents(); - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - - jLabel1 = new javax.swing.JLabel(); - artifactTypeTextField = new javax.swing.JTextField(); - jLabel2 = new javax.swing.JLabel(); - artifactIdTextField = new javax.swing.JTextField(); - - org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(DummyArtifactContentViewer.class, "DummyArtifactContentViewer.jLabel1.text")); // NOI18N - - artifactTypeTextField.setText(org.openide.util.NbBundle.getMessage(DummyArtifactContentViewer.class, "DummyArtifactContentViewer.artifactTypeTextField.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(DummyArtifactContentViewer.class, "DummyArtifactContentViewer.jLabel2.text")); // NOI18N - - artifactIdTextField.setText(org.openide.util.NbBundle.getMessage(DummyArtifactContentViewer.class, "DummyArtifactContentViewer.artifactIdTextField.text")); // NOI18N - artifactIdTextField.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - artifactIdTextFieldActionPerformed(evt); - } - }); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabel1) - .addComponent(jLabel2)) - .addGap(18, 18, 18) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(artifactTypeTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 133, Short.MAX_VALUE) - .addComponent(artifactIdTextField)) - .addContainerGap(165, Short.MAX_VALUE)) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(16, 16, 16) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabel1) - .addComponent(artifactTypeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(18, 18, 18) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabel2) - .addComponent(artifactIdTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap(218, Short.MAX_VALUE)) - ); - }// //GEN-END:initComponents - - private void artifactIdTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_artifactIdTextFieldActionPerformed - // TODO add your handling code here: - }//GEN-LAST:event_artifactIdTextFieldActionPerformed - - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JTextField artifactIdTextField; - private javax.swing.JTextField artifactTypeTextField; - private javax.swing.JLabel jLabel1; - private javax.swing.JLabel jLabel2; - // End of variables declaration//GEN-END:variables - - @Override - public void setArtifact(BlackboardArtifact artifact) { - artifactTypeTextField.setText(artifact.getArtifactTypeName()); - artifactIdTextField.setText(String.format("%d", artifact.getId())); - } - - @Override - public Component getComponent() { - return this; - } - - @Override - public boolean isSupported(BlackboardArtifact artifact) { - return true; - } -} From d8eb4009f2f2c6ebb25386bacba4ec20c0418577 Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Mon, 11 May 2020 19:23:34 -0400 Subject: [PATCH 6/8] Removed unused strings. Fixed comments. --- .../autopsy/contentviewers/ArtifactContentViewer.java | 5 ++--- .../org/sleuthkit/autopsy/contentviewers/Bundle.properties | 4 ---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/ArtifactContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/ArtifactContentViewer.java index 4e3dae286b..985ca96879 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/ArtifactContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/ArtifactContentViewer.java @@ -33,8 +33,7 @@ public interface ArtifactContentViewer { /** * Called to display the contents of the given artifact. * - * @param artifact the node which is used to obtain and display the - * artifacts. + * @param artifact the artifact to display. */ void setArtifact(BlackboardArtifact artifact); @@ -50,7 +49,7 @@ public interface ArtifactContentViewer { * * @param artifact Artifact to check. * - * @return True if the node can be displayed / processed, else false + * @return True if the artifact can be displayed by the viewer, false otherwise. */ boolean isSupported(BlackboardArtifact artifact); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties index eeb46367d5..60afbe4051 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties @@ -956,7 +956,3 @@ manager.properties.brokenProperty = Broken default property {0} value: {1} manager.properties.missingProperty = Missing default property {0} value: {1} DefaultArtifactContentViewer.copyMenuItem.text=Copy DefaultArtifactContentViewer.selectAllMenuItem.text=Select All -DummyArtifactContentViewer.jLabel1.text=Artifact Type: -DummyArtifactContentViewer.artifactTypeTextField.text=jTextField1 -DummyArtifactContentViewer.jLabel2.text=Artifact Id: -DummyArtifactContentViewer.artifactIdTextField.text=jTextField1 From 1760444f397f151accb00e0df14431ec39600b73 Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Mon, 11 May 2020 19:55:03 -0400 Subject: [PATCH 7/8] Address Codacy comments. --- .../DefaultArtifactContentViewer.java | 28 +++++++++++-------- .../DataContentViewerArtifact.java | 4 +-- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java index 7cbb279b21..660f67a516 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java @@ -51,6 +51,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonArray; +import java.util.Locale; import java.util.Map; import javax.swing.SwingUtilities; @@ -109,15 +110,17 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements @Override public void columnAdded(TableColumnModelEvent e) { + // do nothing } @Override public void columnRemoved(TableColumnModelEvent e) { + // do nothing } @Override public void columnMoved(TableColumnModelEvent e) { - + // do nothing } @Override @@ -127,6 +130,7 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements @Override public void columnSelectionChanged(ListSelectionEvent e) { + // do nothing } }); resultsTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_NEXT_COLUMN); @@ -255,7 +259,7 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements for (int row : resultsTable.getSelectedRows()) { for (int col : resultsTable.getSelectedColumns()) { selectedText.append((String) resultsTable.getValueAt(row, col)); - selectedText.append("\t"); + selectedText.append('\t'); } //if its the last row selected don't add a new line if (row != resultsTable.getSelectedRows()[resultsTable.getSelectedRows().length - 1]) { @@ -316,7 +320,7 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements */ private class ResultsTableArtifact { - private final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + private final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US); private String[][] rowData = null; private final String artifactDisplayName; private final Content content; @@ -350,14 +354,7 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements */ String value; switch (attr.getAttributeType().getValueType()) { - case STRING: - case INTEGER: - case LONG: - case DOUBLE: - case BYTE: - default: - value = attr.getDisplayString(); - break; + // Use Autopsy date formatting settings, not TSK defaults case DATETIME: value = epochTimeToString(attr.getValueLong()); @@ -370,6 +367,15 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements value = toJsonDisplayString(json, ""); break; + + case STRING: + case INTEGER: + case LONG: + case DOUBLE: + case BYTE: + default: + value = attr.getDisplayString(); + break; } /* * Attribute sources column. diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java index bb6fc2e1b3..23116a5d11 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java @@ -620,13 +620,13 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat // Get the artifact content to display from the cache. Note that one must be subtracted from the // page index to get the corresponding artifact content index. List artifactContents = getArtifactContents(); - BlackboardArtifact artifactContent = artifactContents.get(pageIndex - 1); - + // It may take a considerable amount of time to fetch the attributes of the selected artifact so check for cancellation. if (isCancelled()) { return null; } + BlackboardArtifact artifactContent = artifactContents.get(pageIndex - 1); return new ViewUpdate(artifactContents.size(), pageIndex, artifactContent); } From d30bcda8a942aa152656104898c0b7d3994d8ab3 Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Tue, 12 May 2020 12:35:29 -0400 Subject: [PATCH 8/8] Removed an unused subpanel that was causing extra white space. --- .../DefaultArtifactContentViewer.form | 28 ++----------------- .../DefaultArtifactContentViewer.java | 19 ++----------- 2 files changed, 4 insertions(+), 43 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.form index 37ea0f00fa..eb1f729611 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.form @@ -45,40 +45,16 @@ - - + - - - - - + - - - - - - - - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java index 660f67a516..d77ca887d8 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java @@ -199,8 +199,6 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements rightClickMenu = new javax.swing.JPopupMenu(); copyMenuItem = new javax.swing.JMenuItem(); selectAllMenuItem = new javax.swing.JMenuItem(); - jScrollPane1 = new javax.swing.JScrollPane(); - jPanel1 = new javax.swing.JPanel(); resultsTableScrollPane = new javax.swing.JScrollPane(); copyMenuItem.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.copyMenuItem.text")); // NOI18N @@ -211,13 +209,6 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements setPreferredSize(new java.awt.Dimension(100, 58)); - jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - jScrollPane1.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); - - jPanel1.setPreferredSize(new java.awt.Dimension(620, 58)); - jPanel1.setLayout(new java.awt.GridBagLayout()); - jScrollPane1.setViewportView(jPanel1); - resultsTableScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); resultsTableScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); resultsTableScrollPane.setPreferredSize(new java.awt.Dimension(620, 34)); @@ -226,22 +217,16 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1) - .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 100, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 58, Short.MAX_VALUE) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JMenuItem copyMenuItem; - private javax.swing.JPanel jPanel1; - private javax.swing.JScrollPane jScrollPane1; private javax.swing.JScrollPane resultsTableScrollPane; private javax.swing.JPopupMenu rightClickMenu; private javax.swing.JMenuItem selectAllMenuItem;