From 6156016bf5798d04acab6e1dbbb95a7f226913b0 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 25 May 2021 08:52:22 -0400 Subject: [PATCH 01/33] annotations styling updates --- .../AnnotationsContentViewer.java | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java index 5d109438c3..304300cec4 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.contentviewers; +import java.awt.Color; import java.awt.Component; import java.util.concurrent.ExecutionException; import java.util.logging.Level; @@ -49,13 +50,15 @@ import org.jsoup.nodes.Document; }) public class AnnotationsContentViewer extends javax.swing.JPanel implements DataContentViewer { + private static final String DEFAULT_FONT_FAMILY = new JLabel().getFont().getFamily(); private static final int DEFAULT_FONT_SIZE = new JLabel().getFont().getSize(); + private static final Color DEFAULT_BACKGROUND = new JLabel().getBackground(); // how big the subheader should be - private static final int SUBHEADER_FONT_SIZE = DEFAULT_FONT_SIZE * 12 / 11; + private static final int SUBHEADER_FONT_SIZE = DEFAULT_FONT_SIZE + 1; // how big the header should be - private static final int HEADER_FONT_SIZE = DEFAULT_FONT_SIZE * 14 / 11; + private static final int HEADER_FONT_SIZE = DEFAULT_FONT_SIZE + 2; // the subsection indent private static final int DEFAULT_SUBSECTION_LEFT_PAD = DEFAULT_FONT_SIZE; @@ -67,12 +70,16 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data // additional styling for components private static final String STYLE_SHEET_RULE - = String.format(" .%s { font-size: %dpx;font-style:italic; margin: 0px; padding: 0px; } ", Annotations.MESSAGE_CLASSNAME, DEFAULT_FONT_SIZE) - + String.format(" .%s {font-size:%dpx;font-weight:bold; margin: 0px; margin-top: %dpx; padding: 0px; } ", - Annotations.SUBHEADER_CLASSNAME, SUBHEADER_FONT_SIZE, DEFAULT_SUBSECTION_SPACING) - + String.format(" .%s { font-size:%dpx;font-weight:bold; margin: 0px; padding: 0px; } ", Annotations.HEADER_CLASSNAME, HEADER_FONT_SIZE) - + String.format(" td { vertical-align: top; font-size:%dpx; text-align: left; margin: 0px; padding: 0px %dpx 0px 0px;} ", DEFAULT_FONT_SIZE, CELL_SPACING) - + String.format(" th { vertical-align: top; text-align: left; margin: 0px; padding: 0px %dpx 0px 0px} ", DEFAULT_FONT_SIZE, CELL_SPACING) + = String.format(" .%s { font-family: %s; font-size: %dpt; font-style:italic; margin: 0px; padding: 0px; } ", + Annotations.MESSAGE_CLASSNAME, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE) + + String.format(" .%s { font-family: %s; font-size:%dpt;font-weight:bold; margin: 0px; margin-top: %dpx; padding: 0px; } ", + Annotations.SUBHEADER_CLASSNAME, DEFAULT_FONT_FAMILY, SUBHEADER_FONT_SIZE, DEFAULT_SUBSECTION_SPACING) + + String.format(" .%s { font-family: %s; font-size:%dpt;font-weight:bold; margin: 0px; padding: 0px; } ", + Annotations.HEADER_CLASSNAME, DEFAULT_FONT_FAMILY, HEADER_FONT_SIZE) + + String.format(" td { vertical-align: top; font-family: %s; font-size:%dpt; text-align: left; margin: 0px; padding: 0px %dpx 0px 0px;} ", + DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, CELL_SPACING) + + String.format(" th { vertical-align: top; text-align: left; margin: 0px; padding: 0px %dpx 0px 0px} ", + DEFAULT_FONT_SIZE, CELL_SPACING) + String.format(" .%s { margin: %dpx 0px; padding-left: %dpx; } ", Annotations.SUBSECTION_CLASSNAME, DEFAULT_SUBSECTION_SPACING, DEFAULT_SUBSECTION_LEFT_PAD) + String.format(" .%s { margin-bottom: %dpx; } ", Annotations.SECTION_CLASSNAME, DEFAULT_SECTION_SPACING); @@ -87,6 +94,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data public AnnotationsContentViewer() { initComponents(); Utilities.configureTextPaneAsHtml(textPanel); + textPanel.setBackground(DEFAULT_BACKGROUND); // get html editor kit and apply additional style rules EditorKit editorKit = textPanel.getEditorKit(); if (editorKit instanceof HTMLEditorKit) { From 54ec1393a0886f7679a7fab74776dca5afb646e6 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 2 Jun 2021 09:49:54 -0400 Subject: [PATCH 02/33] added defaults class --- .../defaults/ContentViewerDefaults.java | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/defaults/ContentViewerDefaults.java diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/defaults/ContentViewerDefaults.java b/Core/src/org/sleuthkit/autopsy/contentviewers/defaults/ContentViewerDefaults.java new file mode 100644 index 0000000000..19ad989969 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/defaults/ContentViewerDefaults.java @@ -0,0 +1,79 @@ +/* + * 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.defaults; + +import java.awt.Font; +import java.awt.Insets; +import java.awt.Toolkit; +import java.util.function.Supplier; +import javax.swing.UIManager; + +/** + * + * @author gregd + */ +public class ContentViewerDefaults { + + private static class Cacheable { + + private final Supplier itemProvider; + private T item = null; + + Cacheable(Supplier itemProvider) { + this.itemProvider = itemProvider; + } + + T get() { + if (item == null) { + item = itemProvider.get(); + } + + return item; + } + } + + private static final Cacheable DEFAULT_FONT = new Cacheable<>(() -> UIManager.getDefaults().getFont("Label.font")); + + private static final Cacheable DEFAULT_FONT_PX = new Cacheable<>(() -> { + // based on https://stackoverflow.com/questions/5829703/java-getting-a-font-with-a-specific-height-in-pixels/26564924#26564924 + return (int) Math.round(DEFAULT_FONT.get().getSize() * Toolkit.getDefaultToolkit().getScreenResolution() / 72.0); + }); + + private static final Cacheable HEADER_FONT = new Cacheable<>(() -> { + Font defaultFont = DEFAULT_FONT.get(); + return defaultFont.deriveFont(Font.BOLD, defaultFont.getSize() + 2); + }); + + private static final Cacheable DEFAULT_PANEL_INSETS = new Cacheable<>(() -> UIManager.getDefaults().getInsets("TextPane.margin")); + + private static final Cacheable DEFAULT_INDENT = new Cacheable<>(() -> DEFAULT_FONT_PX.get()); + private static final Cacheable DEFAULT_SECTION_SPACING = new Cacheable<>(() -> DEFAULT_FONT_PX.get()); + + + + + public static Font getFont() { + return DEFAULT_FONT.get(); + } + + public static Font getHeaderFont() { + return HEADER_FONT.get(); + } + + public static Insets getPanelInsets() { + return DEFAULT_PANEL_INSETS.get(); + } + + public static Integer getSectionIndent() { + return DEFAULT_INDENT.get(); + } + + public static Integer getSectionSpacing() { + return DEFAULT_SECTION_SPACING.get(); + } + + // line spacing??? +} From 31ee21d2ca265e9742d7766579134303ed0daf75 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 2 Jun 2021 14:56:05 -0400 Subject: [PATCH 03/33] supplier fix --- .../defaults/ContentViewerDefaults.java | 34 +++++-------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/defaults/ContentViewerDefaults.java b/Core/src/org/sleuthkit/autopsy/contentviewers/defaults/ContentViewerDefaults.java index 19ad989969..267be2d302 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/defaults/ContentViewerDefaults.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/defaults/ContentViewerDefaults.java @@ -5,10 +5,11 @@ */ package org.sleuthkit.autopsy.contentviewers.defaults; +import com.google.common.base.Suppliers; import java.awt.Font; import java.awt.Insets; import java.awt.Toolkit; -import java.util.function.Supplier; +import com.google.common.base.Supplier; import javax.swing.UIManager; /** @@ -16,41 +17,22 @@ import javax.swing.UIManager; * @author gregd */ public class ContentViewerDefaults { - - private static class Cacheable { - - private final Supplier itemProvider; - private T item = null; - - Cacheable(Supplier itemProvider) { - this.itemProvider = itemProvider; - } - - T get() { - if (item == null) { - item = itemProvider.get(); - } - - return item; - } - } - - private static final Cacheable DEFAULT_FONT = new Cacheable<>(() -> UIManager.getDefaults().getFont("Label.font")); + private static final Supplier DEFAULT_FONT = Suppliers.memoize(() -> UIManager.getDefaults().getFont("Label.font")); - private static final Cacheable DEFAULT_FONT_PX = new Cacheable<>(() -> { + private static final Supplier DEFAULT_FONT_PX = Suppliers.memoize(() -> { // based on https://stackoverflow.com/questions/5829703/java-getting-a-font-with-a-specific-height-in-pixels/26564924#26564924 return (int) Math.round(DEFAULT_FONT.get().getSize() * Toolkit.getDefaultToolkit().getScreenResolution() / 72.0); }); - private static final Cacheable HEADER_FONT = new Cacheable<>(() -> { + private static final Supplier HEADER_FONT = Suppliers.memoize(() -> { Font defaultFont = DEFAULT_FONT.get(); return defaultFont.deriveFont(Font.BOLD, defaultFont.getSize() + 2); }); - private static final Cacheable DEFAULT_PANEL_INSETS = new Cacheable<>(() -> UIManager.getDefaults().getInsets("TextPane.margin")); + private static final Supplier DEFAULT_PANEL_INSETS = Suppliers.memoize(() -> UIManager.getDefaults().getInsets("TextPane.margin")); - private static final Cacheable DEFAULT_INDENT = new Cacheable<>(() -> DEFAULT_FONT_PX.get()); - private static final Cacheable DEFAULT_SECTION_SPACING = new Cacheable<>(() -> DEFAULT_FONT_PX.get()); + private static final Supplier DEFAULT_INDENT = Suppliers.memoize(() -> DEFAULT_FONT_PX.get()); + private static final Supplier DEFAULT_SECTION_SPACING = Suppliers.memoize(() -> DEFAULT_FONT_PX.get()); From 658516059f4e65fd25980e8e8fc0838351663558 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 3 Jun 2021 13:22:54 -0400 Subject: [PATCH 04/33] working through general purpose artifact viewer --- .../GeneralPurposeArtifactViewer.java | 177 +++++++++++------- .../ContentViewerDefaults.java | 12 +- .../osaccount/OsAccountDataPanel.java | 20 +- 3 files changed, 131 insertions(+), 78 deletions(-) rename Core/src/org/sleuthkit/autopsy/contentviewers/{defaults => layout}/ContentViewerDefaults.java (80%) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/GeneralPurposeArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/GeneralPurposeArtifactViewer.java index d8150a91a2..aa1ca8d732 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/GeneralPurposeArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/GeneralPurposeArtifactViewer.java @@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.contentviewers.artifactviewers; import java.awt.Component; import java.awt.Dimension; -import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; @@ -39,9 +38,12 @@ import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.JTextPane; import javax.swing.SwingUtilities; +import javax.swing.border.EmptyBorder; import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerDefaults; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; @@ -55,13 +57,18 @@ import org.sleuthkit.datamodel.TskCoreException; */ @ServiceProvider(service = ArtifactContentViewer.class) public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel implements ArtifactContentViewer { - + private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(GeneralPurposeArtifactViewer.class.getName()); // Number of columns in the gridbag layout. private final static int MAX_COLS = 4; - private final static Insets ROW_INSETS = new java.awt.Insets(0, 12, 0, 0); - private final static Insets HEADER_INSETS = new java.awt.Insets(0, 0, 0, 0); + private final static Insets ROW_INSETS = new java.awt.Insets(0, 0, 0, 0); + + private final static Insets FIRST_HEADER_INSETS = new Insets(0, 0, 0, 0); + private final static Insets HEADER_INSETS = new Insets(ContentViewerDefaults.getSectionSpacing(), 0, ContentViewerDefaults.getLineSpacing(), 0); + private final static Insets VALUE_COLUMN_INSETS = new Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getLineSpacing(), 0); + private final static Insets KEY_COLUMN_INSETS = new Insets(0, ContentViewerDefaults.getSectionIndent(), ContentViewerDefaults.getLineSpacing(), 0); + private final static double GLUE_WEIGHT_X = 1.0; private final static double TEXT_WEIGHT_X = 0.0; private final static int LABEL_COLUMN = 0; @@ -78,7 +85,6 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i BlackboardAttribute.ATTRIBUTE_TYPE.TSK_HEADERS.getTypeID()}; private static final List TYPES_WITH_DATE_SECTION = Arrays.asList(new Integer[]{BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID()}); private final GridBagLayout gridBagLayout = new GridBagLayout(); - private final GridBagConstraints gridBagConstraints = new GridBagConstraints(); private final Map orderingMap = new HashMap<>(); private final javax.swing.JPanel detailsPanel = new javax.swing.JPanel(); @@ -89,8 +95,8 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i public GeneralPurposeArtifactViewer() { addOrderings(); initComponents(); - gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; detailsPanel.setLayout(gridBagLayout); + detailsPanel.setBorder(new EmptyBorder(ContentViewerDefaults.getPanelInsets())); } /** @@ -134,7 +140,7 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i BlackboardAttribute.ATTRIBUTE_TYPE.TSK_VALUE.getTypeID(), BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID()}); } - + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @NbBundle.Messages({"GeneralPurposeArtifactViewer.unknown.text=Unknown"}) @Override @@ -175,14 +181,8 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i detailsPanel.removeAll(); detailsPanel.setLayout(gridBagLayout); detailsPanel.revalidate(); - gridBagConstraints.gridy = 0; - gridBagConstraints.gridx = LABEL_COLUMN; - gridBagConstraints.weighty = 0.0; - gridBagConstraints.weightx = TEXT_WEIGHT_X; // keep components fixed horizontally. - gridBagConstraints.fill = GridBagConstraints.NONE; - gridBagConstraints.insets = ROW_INSETS; } - + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @Override public boolean isSupported(BlackboardArtifact artifact) { @@ -197,7 +197,7 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i || artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID() || artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_FORM_AUTOFILL.getTypeID()); } - + @NbBundle.Messages({"GeneralPurposeArtifactViewer.details.attrHeader=Details", "GeneralPurposeArtifactViewer.details.sourceHeader=Source", "GeneralPurposeArtifactViewer.details.dataSource=Data Source", @@ -250,8 +250,10 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i @ThreadConfined(type = ThreadConfined.ThreadType.AWT) private void updateView(BlackboardArtifact artifact, Map> attributeMap, String dataSourceName, String sourceFilePath) { final Integer artifactTypeId = artifact.getArtifactTypeID(); + int curRow = 0; if (!(artifactTypeId < 1 || artifactTypeId >= Integer.MAX_VALUE)) { - JTextPane firstTextPane = addDetailsHeader(artifactTypeId); + JTextPane firstTextPane = addDetailsHeader(artifactTypeId, curRow); + curRow++; Integer[] orderingArray = orderingMap.get(artifactTypeId); if (orderingArray == null) { orderingArray = DEFAULT_ORDERING; @@ -262,27 +264,39 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i for (BlackboardAttribute bba : attrList) { if (bba.getAttributeType().getTypeName().startsWith("TSK_DATETIME")) { if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID()) { - addNameValueRow(Bundle.GeneralPurposeArtifactViewer_dates_time(), TimeZoneUtils.getFormattedTime(bba.getValueLong())); + addNameValueRow(Bundle.GeneralPurposeArtifactViewer_dates_time(), TimeZoneUtils.getFormattedTime(bba.getValueLong()), curRow); } else { - addNameValueRow(bba.getAttributeType().getDisplayName(), TimeZoneUtils.getFormattedTime(bba.getValueLong())); + addNameValueRow(bba.getAttributeType().getDisplayName(), TimeZoneUtils.getFormattedTime(bba.getValueLong()), curRow); } } else if (bba.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT.getTypeID() && artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID()) { - addNameValueRow(Bundle.GeneralPurposeArtifactViewer_term_label(), bba.getDisplayString()); + addNameValueRow(Bundle.GeneralPurposeArtifactViewer_term_label(), bba.getDisplayString(), curRow); } else if (bba.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID()) { String displayString = bba.getDisplayString(); if (!attributeMap.containsKey(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID())) { displayString += Bundle.GeneralPurposeArtifactViewer_noFile_text(); } - addNameValueRow(bba.getAttributeType().getDisplayName(), displayString); + addNameValueRow(bba.getAttributeType().getDisplayName(), displayString, curRow); } else { - addNameValueRow(bba.getAttributeType().getDisplayName(), bba.getDisplayString()); + addNameValueRow(bba.getAttributeType().getDisplayName(), bba.getDisplayString(), curRow); } + curRow++; } } } if (TYPES_WITH_DATE_SECTION.contains(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID())) { boolean headerAdded = false; - headerAdded = addDates(Bundle.GeneralPurposeArtifactViewer_dates_created(), attributeMap.remove(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID()), headerAdded); + List> dateKeyValuePairs = Stream.of( + Pair.of(Bundle.GeneralPurposeArtifactViewer_dates_created(), + attributeMap.remove(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID())), + Pair.of(Bundle.GeneralPurposeArtifactViewer_dates_start(), + attributeMap.remove(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID())), + Pair.of(Bundle.GeneralPurposeArtifactViewer_dates_end(), + attributeMap.remove(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID())), + Pair.of(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME.getDisplayName(), + attributeMap.remove(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID())) + ) + ) + headerAdded = addDates(Bundle.GeneralPurposeArtifactViewer_dates_created(), , headerAdded); headerAdded = addDates(Bundle.GeneralPurposeArtifactViewer_dates_start(), attributeMap.remove(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START.getTypeID()), headerAdded); headerAdded = addDates(Bundle.GeneralPurposeArtifactViewer_dates_end(), attributeMap.remove(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_END.getTypeID()), headerAdded); addDates(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME.getDisplayName(), attributeMap.remove(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID()), headerAdded); @@ -311,21 +325,25 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i detailsPanel.revalidate(); } + /** * Private helper method to add all dates in a given attribute list. * * @param label Specific String to use in place of attributes display * name. * @param attrList List of attributes to add dates for. + * @param rowStart The starting row of these dates. * @param headerExists If the "Dates" header has already been displayed. * - * @return True if the "Dates" header has been displayed, false otherwise. + * @return The next empty row. */ - private boolean addDates(String label, List attrList, boolean headerExists) { + private int addDates(String label, List attrList, int rowStart, boolean headerExists) { + int curRow = rowStart; boolean headerAdded = headerExists; if (attrList != null) { if (!headerAdded) { - addHeader(Bundle.GeneralPurposeArtifactViewer_details_datesHeader()); + addHeader(Bundle.GeneralPurposeArtifactViewer_details_datesHeader(), curRow); + curRow++; headerAdded = true; } String labelToUse = label; @@ -333,16 +351,18 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i if (StringUtils.isBlank(label)) { labelToUse = bba.getAttributeType().getDisplayName(); } - addNameValueRow(labelToUse, bba.getDisplayString()); + addNameValueRow(labelToUse, bba.getDisplayString(), curRow); + curRow++; } } - return headerAdded; + return new AddDatesData(); } /** * Helper method to add an artifact specific details header. * * @param artifactTypeId ID of artifact type to add header for. + * @param row The row of the header. */ @NbBundle.Messages({"GeneralPurposeArtifactViewer.details.bookmarkHeader=Bookmark Details", "GeneralPurposeArtifactViewer.details.historyHeader=Visit Details", @@ -350,7 +370,7 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i "GeneralPurposeArtifactViewer.details.searchHeader=Web Search", "GeneralPurposeArtifactViewer.details.cachedHeader=Cached File", "GeneralPurposeArtifactViewer.details.cookieHeader=Cookie Details",}) - private JTextPane addDetailsHeader(int artifactTypeId) { + private JTextPane addDetailsHeader(int artifactTypeId, int row) { String header; if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID()) { header = Bundle.GeneralPurposeArtifactViewer_details_historyHeader(); @@ -367,48 +387,58 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i } else { header = Bundle.GeneralPurposeArtifactViewer_details_attrHeader(); } - return addHeader(header); + return addHeader(header, row); + } + + private GridBagConstraints getDefaultConstraints(int row, int col) { + GridBagConstraints gridBagConstraints = new GridBagConstraints(); + gridBagConstraints.gridy = row; + gridBagConstraints.gridx = col; + gridBagConstraints.weighty = 0.0; + gridBagConstraints.weightx = TEXT_WEIGHT_X; // keep components fixed horizontally. + gridBagConstraints.fill = GridBagConstraints.NONE; + gridBagConstraints.insets = ROW_INSETS; + gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; + return gridBagConstraints; } /** * Adds a new heading to the panel. * * @param headerString Heading string to display. + * @param row The grid row to add this header. * * @return JLabel Heading label added. */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) - private JTextPane addHeader(String headerString) { + private JTextPane addHeader(String headerString, int row) { // create label for heading javax.swing.JTextPane headingLabel = new javax.swing.JTextPane(); headingLabel.setOpaque(false); headingLabel.setFocusable(false); headingLabel.setEditable(false); - // add a blank line before the start of new section, unless it's - // the first section - if (gridBagConstraints.gridy != 0) { - gridBagConstraints.gridy++; - // add to panel - addToPanel(new javax.swing.JLabel(" ")); - addLineEndGlue(); - headingLabel.setFocusable(false); - } - gridBagConstraints.gridy++; - gridBagConstraints.gridx = LABEL_COLUMN;; + + GridBagConstraints gridBagConstraints = getDefaultConstraints(row, LABEL_COLUMN); + + gridBagConstraints.insets = (row == 0) + ? FIRST_HEADER_INSETS + : HEADER_INSETS; + // let the header span all of the row gridBagConstraints.gridwidth = MAX_COLS; gridBagConstraints.insets = HEADER_INSETS; + gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; // set text headingLabel.setText(headerString); // make it large and bold - headingLabel.setFont(headingLabel.getFont().deriveFont(Font.BOLD, headingLabel.getFont().getSize() + 2)); + headingLabel.setFont(ContentViewerDefaults.getHeaderFont()); // add to panel - addToPanel(headingLabel); + addToPanel(headingLabel, gridBagConstraints); // reset constraints to normal gridBagConstraints.gridwidth = LABEL_WIDTH; // add line end glue - addLineEndGlue(); - gridBagConstraints.insets = ROW_INSETS; + addLineEndGlue(row); + return headingLabel; } @@ -418,63 +448,68 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i * * @param keyString Key name to display. * @param valueString Value string to display. + * @param row The row index. */ - private JTextPane addNameValueRow(String keyString, String valueString) { - addKeyAtCol(keyString); - return addValueAtCol(valueString); + private JTextPane addNameValueRow(String keyString, String valueString, int row) { + addKeyAtCol(keyString, row); + return addValueAtCol(valueString, row); } /** * Adds a filler/glue at the end of the line to keep the other columns * aligned, in case the panel is resized. + * + * @param row The row for the line end glue. */ - private void addLineEndGlue() { + private void addLineEndGlue(int row) { // Place the filler just past the last column. - gridBagConstraints.gridx = MAX_COLS; + GridBagConstraints gridBagConstraints = getDefaultConstraints(row, MAX_COLS); gridBagConstraints.weightx = GLUE_WEIGHT_X; // take up all the horizontal space - gridBagConstraints.fill = GridBagConstraints.BOTH; + gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; javax.swing.Box.Filler horizontalFiller = new javax.swing.Box.Filler(new Dimension(0, 0), new Dimension(0, 0), new Dimension(32767, 0)); // add to panel - addToPanel(horizontalFiller); - // restore fill & weight - gridBagConstraints.fill = GridBagConstraints.NONE; - gridBagConstraints.weightx = TEXT_WEIGHT_X; + addToPanel(horizontalFiller, gridBagConstraints); } /** * Adds a filler/glue at the bottom of the panel to keep the data rows * aligned, in case the panel is resized. + * + * @param row The row for the line end glue. */ - private void addPageEndGlue() { + private void addPageEndGlue(int row) { + GridBagConstraints gridBagConstraints = getDefaultConstraints(row, 0); gridBagConstraints.weighty = 1.0; // take up all the vertical space gridBagConstraints.fill = GridBagConstraints.VERTICAL; javax.swing.Box.Filler vertFiller = new javax.swing.Box.Filler(new Dimension(0, 0), new Dimension(0, 0), new Dimension(0, 32767)); // add to panel - addToPanel(vertFiller); + addToPanel(vertFiller, gridBagConstraints); } /** * Adds a label/key to the panel. * * @param keyString Key name to display. + * @param row The row for this column. * * @return Label added. */ - private JLabel addKeyAtCol(String keyString) { + private JLabel addKeyAtCol(String keyString, int row) { // create label javax.swing.JLabel keyLabel = new javax.swing.JLabel(); keyLabel.setFocusable(false); - gridBagConstraints.gridy++; - gridBagConstraints.gridx = LABEL_COLUMN; + + GridBagConstraints gridBagConstraints = getDefaultConstraints(row, LABEL_COLUMN); gridBagConstraints.gridwidth = LABEL_WIDTH; + gridBagConstraints.insets = KEY_COLUMN_INSETS; // set text - keyLabel.setText(keyString + ": "); + keyLabel.setText(keyString + ":"); // add to panel - addToPanel(keyLabel); + addToPanel(keyLabel, gridBagConstraints); return keyLabel; } - private void addToPanel(Component comp) { + private void addToPanel(Component comp, GridBagConstraints gridBagConstraints) { detailsPanel.add(comp, gridBagConstraints); detailsPanel.revalidate(); } @@ -483,20 +518,22 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i * Adds a value string to the panel at specified column. * * @param valueString Value string to display. + * @param row The row for this column. * * @return Label added. */ - private JTextPane addValueAtCol(String valueString) { + private JTextPane addValueAtCol(String valueString, int row) { // create label, JTextPane valueField = new JTextPane(); valueField.setFocusable(false); valueField.setEditable(false); valueField.setOpaque(false); - gridBagConstraints.gridx = VALUE_COLUMN; - GridBagConstraints cloneConstraints = (GridBagConstraints) gridBagConstraints.clone(); + + GridBagConstraints gridBagConstraints = getDefaultConstraints(row, VALUE_COLUMN); // let the value span 2 cols - cloneConstraints.gridwidth = VALUE_WIDTH; - cloneConstraints.fill = GridBagConstraints.BOTH; + gridBagConstraints.gridwidth = VALUE_WIDTH; + gridBagConstraints.insets = VALUE_COLUMN_INSETS; + // set text valueField.setText(valueString); // attach a right click menu with Copy option @@ -507,10 +544,10 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i } }); // add label to panel with cloned contraintsF - detailsPanel.add(valueField, cloneConstraints); + detailsPanel.add(valueField, gridBagConstraints); revalidate(); // end the line - addLineEndGlue(); + addLineEndGlue(row); return valueField; } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/defaults/ContentViewerDefaults.java b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java similarity index 80% rename from Core/src/org/sleuthkit/autopsy/contentviewers/defaults/ContentViewerDefaults.java rename to Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java index 267be2d302..b221e1f522 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/defaults/ContentViewerDefaults.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package org.sleuthkit.autopsy.contentviewers.defaults; +package org.sleuthkit.autopsy.contentviewers.layout; import com.google.common.base.Suppliers; import java.awt.Font; @@ -34,8 +34,12 @@ public class ContentViewerDefaults { private static final Supplier DEFAULT_INDENT = Suppliers.memoize(() -> DEFAULT_FONT_PX.get()); private static final Supplier DEFAULT_SECTION_SPACING = Suppliers.memoize(() -> DEFAULT_FONT_PX.get()); - + private static final Supplier DEFAULT_COLUMN_SPACING = Suppliers.memoize(() -> (int)(DEFAULT_FONT_PX.get() / 3)); + private static final Supplier DEFAULT_LINE_SPACING = Suppliers.memoize(() -> (int)(DEFAULT_FONT_PX.get() / 5)); + public static int getColumnSpacing() { + return DEFAULT_COLUMN_SPACING.get(); + } public static Font getFont() { return DEFAULT_FONT.get(); @@ -57,5 +61,9 @@ public class ContentViewerDefaults { return DEFAULT_SECTION_SPACING.get(); } + public static Integer getLineSpacing() { + return DEFAULT_LINE_SPACING.get(); + } + // line spacing??? } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/osaccount/OsAccountDataPanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/osaccount/OsAccountDataPanel.java index 2c88660cb0..3ab02ed4d7 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/osaccount/OsAccountDataPanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/osaccount/OsAccountDataPanel.java @@ -19,7 +19,6 @@ package org.sleuthkit.autopsy.contentviewers.osaccount; import java.awt.BorderLayout; -import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; @@ -38,8 +37,10 @@ import javax.swing.Box; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingWorker; +import javax.swing.border.EmptyBorder; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerDefaults; import org.sleuthkit.autopsy.contentviewers.osaccount.SectionData.RowData; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.DataSource; @@ -61,7 +62,11 @@ public class OsAccountDataPanel extends JPanel { private static final int KEY_COLUMN = 0; private static final int VALUE_COLUMN = 1; - + + private final static Insets FIRST_HEADER_INSETS = new Insets(0, 0, 0, 0); + private final static Insets HEADER_INSETS = new Insets(ContentViewerDefaults.getSectionSpacing(), 0, ContentViewerDefaults.getLineSpacing(), 0); + private final static Insets VALUE_COLUMN_INSETS = new Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getLineSpacing(), 0); + private final static Insets KEY_COLUMN_INSETS = new Insets(0, ContentViewerDefaults.getSectionIndent(), ContentViewerDefaults.getLineSpacing(), 0); private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MMM dd yyyy", US); private PanelDataFetcher dataFetcher = null; @@ -76,6 +81,7 @@ public class OsAccountDataPanel extends JPanel { */ private void initialize() { this.setLayout(new GridBagLayout()); + this.setBorder(new EmptyBorder(ContentViewerDefaults.getPanelInsets())); } /** @@ -269,7 +275,7 @@ public class OsAccountDataPanel extends JPanel { private void addTitle(String title, int row) { JLabel label = new JLabel(title); // Make the title bold. - label.setFont(label.getFont().deriveFont(Font.BOLD)); + label.setFont(ContentViewerDefaults.getHeaderFont()); add(label, getTitleContraints(row)); } @@ -312,7 +318,9 @@ public class OsAccountDataPanel extends JPanel { constraints.anchor = GridBagConstraints.NORTHWEST; constraints.fill = GridBagConstraints.HORIZONTAL; constraints.weightx = 1; - constraints.insets = new Insets(5, 5, 5, 9); + constraints.insets = (row == 0) + ? FIRST_HEADER_INSETS + : HEADER_INSETS; return constraints; } @@ -332,7 +340,7 @@ public class OsAccountDataPanel extends JPanel { constraints.gridwidth = 1; // The title goes across the other columns constraints.gridheight = 1; constraints.anchor = GridBagConstraints.WEST; - constraints.insets = new Insets(0, 13, 5, 5); + constraints.insets = KEY_COLUMN_INSETS; return constraints; } @@ -352,8 +360,8 @@ public class OsAccountDataPanel extends JPanel { constraints.gridwidth = 1; // The title goes across the other columns constraints.gridheight = 1; constraints.fill = GridBagConstraints.HORIZONTAL; + constraints.insets = VALUE_COLUMN_INSETS; constraints.weightx = 1; - constraints.insets = new Insets(0, 5, 5, 5); return constraints; } From 32dd9fe4e53f87361db9045ba106aefa4fa96c3a Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 3 Jun 2021 14:35:20 -0400 Subject: [PATCH 05/33] changes for general purpose viewer --- .../GeneralPurposeArtifactViewer.java | 165 ++++++++---------- 1 file changed, 70 insertions(+), 95 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/GeneralPurposeArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/GeneralPurposeArtifactViewer.java index aa1ca8d732..e81b6705c6 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/GeneralPurposeArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/GeneralPurposeArtifactViewer.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.contentviewers.artifactviewers; +import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.GridBagConstraints; @@ -29,10 +30,13 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; +import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; @@ -62,9 +66,9 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i private static final Logger logger = Logger.getLogger(GeneralPurposeArtifactViewer.class.getName()); // Number of columns in the gridbag layout. private final static int MAX_COLS = 4; - private final static Insets ROW_INSETS = new java.awt.Insets(0, 0, 0, 0); + private final static Insets ZERO_INSETS = new java.awt.Insets(0, 0, 0, 0); - private final static Insets FIRST_HEADER_INSETS = new Insets(0, 0, 0, 0); + private final static Insets FIRST_HEADER_INSETS = ZERO_INSETS; private final static Insets HEADER_INSETS = new Insets(ContentViewerDefaults.getSectionSpacing(), 0, ContentViewerDefaults.getLineSpacing(), 0); private final static Insets VALUE_COLUMN_INSETS = new Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getLineSpacing(), 0); private final static Insets KEY_COLUMN_INSETS = new Insets(0, ContentViewerDefaults.getSectionIndent(), ContentViewerDefaults.getLineSpacing(), 0); @@ -85,6 +89,7 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i BlackboardAttribute.ATTRIBUTE_TYPE.TSK_HEADERS.getTypeID()}; private static final List TYPES_WITH_DATE_SECTION = Arrays.asList(new Integer[]{BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID()}); private final GridBagLayout gridBagLayout = new GridBagLayout(); + private final GridBagConstraints gridBagConstraints = new GridBagConstraints(); private final Map orderingMap = new HashMap<>(); private final javax.swing.JPanel detailsPanel = new javax.swing.JPanel(); @@ -95,6 +100,7 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i public GeneralPurposeArtifactViewer() { addOrderings(); initComponents(); + gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; detailsPanel.setLayout(gridBagLayout); detailsPanel.setBorder(new EmptyBorder(ContentViewerDefaults.getPanelInsets())); } @@ -140,7 +146,7 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i BlackboardAttribute.ATTRIBUTE_TYPE.TSK_VALUE.getTypeID(), BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID()}); } - + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @NbBundle.Messages({"GeneralPurposeArtifactViewer.unknown.text=Unknown"}) @Override @@ -181,8 +187,14 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i detailsPanel.removeAll(); detailsPanel.setLayout(gridBagLayout); detailsPanel.revalidate(); + gridBagConstraints.gridy = 0; + gridBagConstraints.gridx = LABEL_COLUMN; + gridBagConstraints.weighty = 0.0; + gridBagConstraints.weightx = TEXT_WEIGHT_X; // keep components fixed horizontally. + gridBagConstraints.fill = GridBagConstraints.NONE; + gridBagConstraints.insets = ZERO_INSETS; } - + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @Override public boolean isSupported(BlackboardArtifact artifact) { @@ -197,7 +209,7 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i || artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID() || artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_FORM_AUTOFILL.getTypeID()); } - + @NbBundle.Messages({"GeneralPurposeArtifactViewer.details.attrHeader=Details", "GeneralPurposeArtifactViewer.details.sourceHeader=Source", "GeneralPurposeArtifactViewer.details.dataSource=Data Source", @@ -250,10 +262,8 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i @ThreadConfined(type = ThreadConfined.ThreadType.AWT) private void updateView(BlackboardArtifact artifact, Map> attributeMap, String dataSourceName, String sourceFilePath) { final Integer artifactTypeId = artifact.getArtifactTypeID(); - int curRow = 0; if (!(artifactTypeId < 1 || artifactTypeId >= Integer.MAX_VALUE)) { - JTextPane firstTextPane = addDetailsHeader(artifactTypeId, curRow); - curRow++; + JTextPane firstTextPane = addDetailsHeader(artifactTypeId); Integer[] orderingArray = orderingMap.get(artifactTypeId); if (orderingArray == null) { orderingArray = DEFAULT_ORDERING; @@ -264,39 +274,27 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i for (BlackboardAttribute bba : attrList) { if (bba.getAttributeType().getTypeName().startsWith("TSK_DATETIME")) { if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID()) { - addNameValueRow(Bundle.GeneralPurposeArtifactViewer_dates_time(), TimeZoneUtils.getFormattedTime(bba.getValueLong()), curRow); + addNameValueRow(Bundle.GeneralPurposeArtifactViewer_dates_time(), TimeZoneUtils.getFormattedTime(bba.getValueLong())); } else { - addNameValueRow(bba.getAttributeType().getDisplayName(), TimeZoneUtils.getFormattedTime(bba.getValueLong()), curRow); + addNameValueRow(bba.getAttributeType().getDisplayName(), TimeZoneUtils.getFormattedTime(bba.getValueLong())); } } else if (bba.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT.getTypeID() && artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID()) { - addNameValueRow(Bundle.GeneralPurposeArtifactViewer_term_label(), bba.getDisplayString(), curRow); + addNameValueRow(Bundle.GeneralPurposeArtifactViewer_term_label(), bba.getDisplayString()); } else if (bba.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID()) { String displayString = bba.getDisplayString(); if (!attributeMap.containsKey(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID())) { displayString += Bundle.GeneralPurposeArtifactViewer_noFile_text(); } - addNameValueRow(bba.getAttributeType().getDisplayName(), displayString, curRow); + addNameValueRow(bba.getAttributeType().getDisplayName(), displayString); } else { - addNameValueRow(bba.getAttributeType().getDisplayName(), bba.getDisplayString(), curRow); + addNameValueRow(bba.getAttributeType().getDisplayName(), bba.getDisplayString()); } - curRow++; } } } if (TYPES_WITH_DATE_SECTION.contains(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID())) { boolean headerAdded = false; - List> dateKeyValuePairs = Stream.of( - Pair.of(Bundle.GeneralPurposeArtifactViewer_dates_created(), - attributeMap.remove(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID())), - Pair.of(Bundle.GeneralPurposeArtifactViewer_dates_start(), - attributeMap.remove(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID())), - Pair.of(Bundle.GeneralPurposeArtifactViewer_dates_end(), - attributeMap.remove(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID())), - Pair.of(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME.getDisplayName(), - attributeMap.remove(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID())) - ) - ) - headerAdded = addDates(Bundle.GeneralPurposeArtifactViewer_dates_created(), , headerAdded); + headerAdded = addDates(Bundle.GeneralPurposeArtifactViewer_dates_created(), attributeMap.remove(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID()), headerAdded); headerAdded = addDates(Bundle.GeneralPurposeArtifactViewer_dates_start(), attributeMap.remove(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START.getTypeID()), headerAdded); headerAdded = addDates(Bundle.GeneralPurposeArtifactViewer_dates_end(), attributeMap.remove(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_END.getTypeID()), headerAdded); addDates(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME.getDisplayName(), attributeMap.remove(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID()), headerAdded); @@ -325,25 +323,21 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i detailsPanel.revalidate(); } - /** * Private helper method to add all dates in a given attribute list. * * @param label Specific String to use in place of attributes display * name. * @param attrList List of attributes to add dates for. - * @param rowStart The starting row of these dates. * @param headerExists If the "Dates" header has already been displayed. * - * @return The next empty row. + * @return True if the "Dates" header has been displayed, false otherwise. */ - private int addDates(String label, List attrList, int rowStart, boolean headerExists) { - int curRow = rowStart; + private boolean addDates(String label, List attrList, boolean headerExists) { boolean headerAdded = headerExists; if (attrList != null) { if (!headerAdded) { - addHeader(Bundle.GeneralPurposeArtifactViewer_details_datesHeader(), curRow); - curRow++; + addHeader(Bundle.GeneralPurposeArtifactViewer_details_datesHeader()); headerAdded = true; } String labelToUse = label; @@ -351,18 +345,16 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i if (StringUtils.isBlank(label)) { labelToUse = bba.getAttributeType().getDisplayName(); } - addNameValueRow(labelToUse, bba.getDisplayString(), curRow); - curRow++; + addNameValueRow(labelToUse, bba.getDisplayString()); } } - return new AddDatesData(); + return headerAdded; } /** * Helper method to add an artifact specific details header. * * @param artifactTypeId ID of artifact type to add header for. - * @param row The row of the header. */ @NbBundle.Messages({"GeneralPurposeArtifactViewer.details.bookmarkHeader=Bookmark Details", "GeneralPurposeArtifactViewer.details.historyHeader=Visit Details", @@ -370,7 +362,7 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i "GeneralPurposeArtifactViewer.details.searchHeader=Web Search", "GeneralPurposeArtifactViewer.details.cachedHeader=Cached File", "GeneralPurposeArtifactViewer.details.cookieHeader=Cookie Details",}) - private JTextPane addDetailsHeader(int artifactTypeId, int row) { + private JTextPane addDetailsHeader(int artifactTypeId) { String header; if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID()) { header = Bundle.GeneralPurposeArtifactViewer_details_historyHeader(); @@ -387,58 +379,45 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i } else { header = Bundle.GeneralPurposeArtifactViewer_details_attrHeader(); } - return addHeader(header, row); - } - - private GridBagConstraints getDefaultConstraints(int row, int col) { - GridBagConstraints gridBagConstraints = new GridBagConstraints(); - gridBagConstraints.gridy = row; - gridBagConstraints.gridx = col; - gridBagConstraints.weighty = 0.0; - gridBagConstraints.weightx = TEXT_WEIGHT_X; // keep components fixed horizontally. - gridBagConstraints.fill = GridBagConstraints.NONE; - gridBagConstraints.insets = ROW_INSETS; - gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; - return gridBagConstraints; + return addHeader(header); } /** * Adds a new heading to the panel. * * @param headerString Heading string to display. - * @param row The grid row to add this header. * * @return JLabel Heading label added. */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) - private JTextPane addHeader(String headerString, int row) { + private JTextPane addHeader(String headerString) { // create label for heading javax.swing.JTextPane headingLabel = new javax.swing.JTextPane(); headingLabel.setOpaque(false); headingLabel.setFocusable(false); headingLabel.setEditable(false); - - GridBagConstraints gridBagConstraints = getDefaultConstraints(row, LABEL_COLUMN); - - gridBagConstraints.insets = (row == 0) + // add a blank line before the start of new section, unless it's + // the first section + gridBagConstraints.insets = (gridBagConstraints.gridy == 0) ? FIRST_HEADER_INSETS : HEADER_INSETS; - + + gridBagConstraints.gridy++; + gridBagConstraints.gridx = LABEL_COLUMN;; // let the header span all of the row gridBagConstraints.gridwidth = MAX_COLS; - gridBagConstraints.insets = HEADER_INSETS; - gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; // set text headingLabel.setText(headerString); // make it large and bold headingLabel.setFont(ContentViewerDefaults.getHeaderFont()); + headingLabel.setMargin(ZERO_INSETS); // add to panel - addToPanel(headingLabel, gridBagConstraints); + addToPanel(headingLabel); // reset constraints to normal gridBagConstraints.gridwidth = LABEL_WIDTH; // add line end glue - addLineEndGlue(row); - + addLineEndGlue(); + gridBagConstraints.insets = ZERO_INSETS; return headingLabel; } @@ -448,68 +427,64 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i * * @param keyString Key name to display. * @param valueString Value string to display. - * @param row The row index. */ - private JTextPane addNameValueRow(String keyString, String valueString, int row) { - addKeyAtCol(keyString, row); - return addValueAtCol(valueString, row); + private JTextPane addNameValueRow(String keyString, String valueString) { + addKeyAtCol(keyString); + return addValueAtCol(valueString); } /** * Adds a filler/glue at the end of the line to keep the other columns * aligned, in case the panel is resized. - * - * @param row The row for the line end glue. */ - private void addLineEndGlue(int row) { + private void addLineEndGlue() { // Place the filler just past the last column. - GridBagConstraints gridBagConstraints = getDefaultConstraints(row, MAX_COLS); + gridBagConstraints.gridx = MAX_COLS; gridBagConstraints.weightx = GLUE_WEIGHT_X; // take up all the horizontal space - gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; + gridBagConstraints.fill = GridBagConstraints.BOTH; javax.swing.Box.Filler horizontalFiller = new javax.swing.Box.Filler(new Dimension(0, 0), new Dimension(0, 0), new Dimension(32767, 0)); // add to panel - addToPanel(horizontalFiller, gridBagConstraints); + addToPanel(horizontalFiller); + // restore fill & weight + gridBagConstraints.fill = GridBagConstraints.NONE; + gridBagConstraints.weightx = TEXT_WEIGHT_X; } /** * Adds a filler/glue at the bottom of the panel to keep the data rows * aligned, in case the panel is resized. - * - * @param row The row for the line end glue. */ - private void addPageEndGlue(int row) { - GridBagConstraints gridBagConstraints = getDefaultConstraints(row, 0); + private void addPageEndGlue() { gridBagConstraints.weighty = 1.0; // take up all the vertical space gridBagConstraints.fill = GridBagConstraints.VERTICAL; javax.swing.Box.Filler vertFiller = new javax.swing.Box.Filler(new Dimension(0, 0), new Dimension(0, 0), new Dimension(0, 32767)); // add to panel - addToPanel(vertFiller, gridBagConstraints); + addToPanel(vertFiller); } /** * Adds a label/key to the panel. * * @param keyString Key name to display. - * @param row The row for this column. * * @return Label added. */ - private JLabel addKeyAtCol(String keyString, int row) { + private JLabel addKeyAtCol(String keyString) { // create label javax.swing.JLabel keyLabel = new javax.swing.JLabel(); keyLabel.setFocusable(false); - - GridBagConstraints gridBagConstraints = getDefaultConstraints(row, LABEL_COLUMN); - gridBagConstraints.gridwidth = LABEL_WIDTH; + gridBagConstraints.gridy++; gridBagConstraints.insets = KEY_COLUMN_INSETS; + gridBagConstraints.gridx = LABEL_COLUMN; + gridBagConstraints.gridwidth = LABEL_WIDTH; // set text - keyLabel.setText(keyString + ":"); + keyLabel.setText(keyString + ": "); // add to panel - addToPanel(keyLabel, gridBagConstraints); + addToPanel(keyLabel); return keyLabel; } - private void addToPanel(Component comp, GridBagConstraints gridBagConstraints) { + private void addToPanel(Component comp) { detailsPanel.add(comp, gridBagConstraints); detailsPanel.revalidate(); } @@ -518,22 +493,22 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i * Adds a value string to the panel at specified column. * * @param valueString Value string to display. - * @param row The row for this column. * * @return Label added. */ - private JTextPane addValueAtCol(String valueString, int row) { + private JTextPane addValueAtCol(String valueString) { // create label, JTextPane valueField = new JTextPane(); valueField.setFocusable(false); valueField.setEditable(false); valueField.setOpaque(false); - - GridBagConstraints gridBagConstraints = getDefaultConstraints(row, VALUE_COLUMN); - // let the value span 2 cols - gridBagConstraints.gridwidth = VALUE_WIDTH; + valueField.setMargin(ZERO_INSETS); + gridBagConstraints.gridx = VALUE_COLUMN; gridBagConstraints.insets = VALUE_COLUMN_INSETS; - + GridBagConstraints cloneConstraints = (GridBagConstraints) gridBagConstraints.clone(); + // let the value span 2 cols + cloneConstraints.gridwidth = VALUE_WIDTH; + cloneConstraints.fill = GridBagConstraints.BOTH; // set text valueField.setText(valueString); // attach a right click menu with Copy option @@ -544,10 +519,10 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i } }); // add label to panel with cloned contraintsF - detailsPanel.add(valueField, gridBagConstraints); + detailsPanel.add(valueField, cloneConstraints); revalidate(); // end the line - addLineEndGlue(row); + addLineEndGlue(); return valueField; } From 3b9a6f6bb2ee5efca82ddca7083edf436d89d209 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 3 Jun 2021 16:35:18 -0400 Subject: [PATCH 06/33] context viewer --- .../contextviewer/ContextSourcePanel.form | 23 +++-- .../contextviewer/ContextSourcePanel.java | 16 +-- .../contextviewer/ContextUsagePanel.form | 24 +++-- .../contextviewer/ContextUsagePanel.java | 19 ++-- .../contextviewer/ContextViewer.form | 99 ++++--------------- .../contextviewer/ContextViewer.java | 96 +++++++----------- .../layout/ContentViewerDefaults.java | 37 ++++--- 7 files changed, 118 insertions(+), 196 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextSourcePanel.form b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextSourcePanel.form index c57a0990a8..9b2e224b22 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextSourcePanel.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextSourcePanel.form @@ -2,11 +2,17 @@
- - + + + + + + + + - + @@ -24,15 +30,13 @@ - - + - - + - + @@ -41,14 +45,13 @@ - - + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextSourcePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextSourcePanel.java index 02bd3f2ae6..9ca74d06c1 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextSourcePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextSourcePanel.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.contentviewers.contextviewer; import java.util.ArrayList; import java.util.List; import org.sleuthkit.autopsy.contentviewers.contextviewer.ContextViewer.DateTimePanel; +import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerDefaults; import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; import org.sleuthkit.datamodel.BlackboardArtifact; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT; @@ -75,8 +76,10 @@ public final class ContextSourcePanel extends javax.swing.JPanel implements Date jSourceNameLabel = new javax.swing.JLabel(); jSourceTextLabel = new javax.swing.JLabel(); - setBackground(new java.awt.Color(255, 255, 255)); - setPreferredSize(new java.awt.Dimension(495, 75)); + setBackground(ContentViewerDefaults.getPanelBackground()); + setMaximumSize(new java.awt.Dimension(495, 55)); + setMinimumSize(new java.awt.Dimension(300, 55)); + setPreferredSize(new java.awt.Dimension(495, 55)); org.openide.awt.Mnemonics.setLocalizedText(jSourceGoToResultButton, org.openide.util.NbBundle.getMessage(ContextSourcePanel.class, "ContextSourcePanel.jSourceGoToResultButton.text")); // NOI18N jSourceGoToResultButton.addActionListener(new java.awt.event.ActionListener() { @@ -94,26 +97,23 @@ public final class ContextSourcePanel extends javax.swing.JPanel implements Date layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(50, 50, 50) .addComponent(jSourceNameLabel) .addGap(36, 36, 36) - .addComponent(jSourceTextLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGap(260, 260, 260)) + .addComponent(jSourceTextLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 360, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() - .addGap(90, 90, 90) + .addGap(40, 40, 40) .addComponent(jSourceGoToResultButton) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(2, 2, 2) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jSourceNameLabel) .addComponent(jSourceTextLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jSourceGoToResultButton) - .addGap(0, 0, 0)) + .addGap(0, 11, Short.MAX_VALUE)) ); }// //GEN-END:initComponents diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextUsagePanel.form b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextUsagePanel.form index a3e2a90f84..2faf5bf779 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextUsagePanel.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextUsagePanel.form @@ -2,11 +2,17 @@ - - + + + + + + + + - + @@ -24,30 +30,28 @@ - - + - - + - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextUsagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextUsagePanel.java index 4a96dfcffd..3eeb4b4442 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextUsagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextUsagePanel.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.contentviewers.contextviewer; import java.util.ArrayList; import java.util.List; +import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerDefaults; import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; import org.sleuthkit.datamodel.BlackboardArtifact; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT; @@ -74,8 +75,10 @@ public final class ContextUsagePanel extends javax.swing.JPanel implements Conte jUsageNameLabel = new javax.swing.JLabel(); jUsageTextLabel = new javax.swing.JLabel(); - setBackground(new java.awt.Color(255, 255, 255)); - setPreferredSize(new java.awt.Dimension(495, 75)); + setBackground(ContentViewerDefaults.getPanelBackground()); + setMaximumSize(new java.awt.Dimension(32767, 55)); + setMinimumSize(new java.awt.Dimension(300, 55)); + setPreferredSize(new java.awt.Dimension(495, 55)); org.openide.awt.Mnemonics.setLocalizedText(jUsageGoToResultButton, org.openide.util.NbBundle.getMessage(ContextUsagePanel.class, "ContextUsagePanel.jUsageGoToResultButton.text")); // NOI18N jUsageGoToResultButton.addActionListener(new java.awt.event.ActionListener() { @@ -93,25 +96,23 @@ public final class ContextUsagePanel extends javax.swing.JPanel implements Conte layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(50, 50, 50) .addComponent(jUsageNameLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jUsageTextLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 240, Short.MAX_VALUE) - .addGap(36, 36, 36)) + .addComponent(jUsageTextLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 420, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() - .addGap(90, 90, 90) + .addGap(40, 40, 40) .addComponent(jUsageGoToResultButton) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap(275, javax.swing.GroupLayout.PREFERRED_SIZE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(2, 2, 2) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jUsageTextLabel) .addComponent(jUsageNameLabel, javax.swing.GroupLayout.Alignment.TRAILING)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jUsageGoToResultButton)) + .addComponent(jUsageGoToResultButton) + .addGap(0, 11, Short.MAX_VALUE)) ); }// //GEN-END:initComponents diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.form index 01c484ba9e..bb1a78d555 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.form @@ -4,38 +4,19 @@ - - + + - - - - - - - - - - - - - - - - - - - + + - - - - + + @@ -50,38 +31,19 @@ - - + + - - - - - - - - - - - - - - - - - - - + + - - - - + + @@ -95,31 +57,9 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + @@ -127,6 +67,9 @@ + + + @@ -137,9 +80,6 @@ - - - @@ -170,11 +110,6 @@ - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.java index bfa0cfc3e9..dab7a657f9 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.contentviewers.contextviewer; import java.awt.Component; +import java.awt.Insets; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -28,12 +29,14 @@ import java.util.Map; import java.util.logging.Level; import javax.swing.BoxLayout; import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED; +import javax.swing.border.EmptyBorder; import org.apache.commons.lang.StringUtils; import org.openide.nodes.Node; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerDefaults; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; @@ -55,6 +58,10 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte private static final Logger logger = Logger.getLogger(ContextViewer.class.getName()); private static final int ARTIFACT_STR_MAX_LEN = 1024; private static final int ATTRIBUTE_STR_MAX_LEN = 200; + + private final static Insets FIRST_HEADER_INSETS = new Insets(0, 0, 0, 0); + private final static Insets HEADER_INSETS = new Insets(ContentViewerDefaults.getSectionSpacing(), 0, ContentViewerDefaults.getLineSpacing(), 0); + private final static Insets DATA_ROW_INSETS = new Insets(0, ContentViewerDefaults.getSectionIndent(), ContentViewerDefaults.getLineSpacing(), 0); // defines a list of artifacts that provide context for a file private static final List CONTEXT_ARTIFACTS = new ArrayList<>(); @@ -91,76 +98,29 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte javax.swing.JLabel jUnknownLabel = new javax.swing.JLabel(); jScrollPane = new javax.swing.JScrollPane(); - jSourcePanel.setBackground(javax.swing.UIManager.getDefaults().getColor("window")); + jSourcePanel.setBorder(new EmptyBorder(FIRST_HEADER_INSETS)); + jSourcePanel.setLayout(new javax.swing.BoxLayout(jSourcePanel, javax.swing.BoxLayout.PAGE_AXIS)); - jSourceLabel.setFont(jSourceLabel.getFont().deriveFont(jSourceLabel.getFont().getStyle() | java.awt.Font.BOLD, jSourceLabel.getFont().getSize()+1)); + jSourceLabel.setFont(ContentViewerDefaults.getHeaderFont()); org.openide.awt.Mnemonics.setLocalizedText(jSourceLabel, org.openide.util.NbBundle.getMessage(ContextViewer.class, "ContextViewer.jSourceLabel.text")); // NOI18N + jSourcePanel.add(jSourceLabel); - javax.swing.GroupLayout jSourcePanelLayout = new javax.swing.GroupLayout(jSourcePanel); - jSourcePanel.setLayout(jSourcePanelLayout); - jSourcePanelLayout.setHorizontalGroup( - jSourcePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jSourcePanelLayout.createSequentialGroup() - .addGap(40, 40, 40) - .addComponent(jSourceLabel) - .addContainerGap(304, Short.MAX_VALUE)) + jUsagePanel.setBorder(new EmptyBorder(HEADER_INSETS)); + jUsagePanel.setLayout(new javax.swing.BoxLayout(jUsagePanel, javax.swing.BoxLayout.PAGE_AXIS)); + + jUsageLabel.setFont(ContentViewerDefaults.getHeaderFont() ); - jSourcePanelLayout.setVerticalGroup( - jSourcePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jSourcePanelLayout.createSequentialGroup() - .addGap(5, 5, 5) - .addComponent(jSourceLabel) - .addGap(2, 2, 2)) - ); - - jUsagePanel.setBackground(javax.swing.UIManager.getDefaults().getColor("window")); - - jUsageLabel.setFont(jUsageLabel.getFont().deriveFont(jUsageLabel.getFont().getStyle() | java.awt.Font.BOLD, jUsageLabel.getFont().getSize()+1)); org.openide.awt.Mnemonics.setLocalizedText(jUsageLabel, org.openide.util.NbBundle.getMessage(ContextViewer.class, "ContextViewer.jUsageLabel.text")); // NOI18N + jUsagePanel.add(jUsageLabel); - javax.swing.GroupLayout jUsagePanelLayout = new javax.swing.GroupLayout(jUsagePanel); - jUsagePanel.setLayout(jUsagePanelLayout); - jUsagePanelLayout.setHorizontalGroup( - jUsagePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jUsagePanelLayout.createSequentialGroup() - .addGap(40, 40, 40) - .addComponent(jUsageLabel) - .addContainerGap(298, Short.MAX_VALUE)) - ); - jUsagePanelLayout.setVerticalGroup( - jUsagePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jUsagePanelLayout.createSequentialGroup() - .addGap(2, 2, 2) - .addComponent(jUsageLabel) - .addGap(2, 2, 2)) - ); - - jUnknownPanel.setBackground(new java.awt.Color(255, 255, 255)); + jUnknownPanel.setLayout(new javax.swing.BoxLayout(jUnknownPanel, javax.swing.BoxLayout.PAGE_AXIS)); org.openide.awt.Mnemonics.setLocalizedText(jUnknownLabel, org.openide.util.NbBundle.getMessage(ContextViewer.class, "ContextViewer.jUnknownLabel.text")); // NOI18N + jUnknownLabel.setBorder(new EmptyBorder(DATA_ROW_INSETS)); + jUnknownPanel.add(jUnknownLabel); - javax.swing.GroupLayout jUnknownPanelLayout = new javax.swing.GroupLayout(jUnknownPanel); - jUnknownPanel.setLayout(jUnknownPanelLayout); - jUnknownPanelLayout.setHorizontalGroup( - jUnknownPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jUnknownPanelLayout.createSequentialGroup() - .addGap(50, 50, 50) - .addComponent(jUnknownLabel) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - jUnknownPanelLayout.setVerticalGroup( - jUnknownPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jUnknownPanelLayout.createSequentialGroup() - .addGap(2, 2, 2) - .addComponent(jUnknownLabel) - .addGap(2, 2, 2)) - ); - - setBackground(new java.awt.Color(255, 255, 255)); setPreferredSize(new java.awt.Dimension(495, 358)); - jScrollPane.setBackground(new java.awt.Color(255, 255, 255)); - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -275,6 +235,8 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte } } javax.swing.JPanel contextContainer = new javax.swing.JPanel(); + contextContainer.setBorder(new EmptyBorder(ContentViewerDefaults.getPanelInsets())); + contextContainer.add(jSourcePanel); contextContainer.setLayout(new BoxLayout(contextContainer, BoxLayout.Y_AXIS)); if (contextSourcePanels.isEmpty()) { @@ -282,6 +244,7 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte } else { for (javax.swing.JPanel sourcePanel : contextSourcePanels) { contextContainer.add(sourcePanel); + contextContainer.setAlignmentX(0); } } contextContainer.add(jUsagePanel); @@ -290,10 +253,11 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte } else { for (javax.swing.JPanel usagePanel : contextUsagePanels) { contextContainer.add(usagePanel); + contextContainer.setAlignmentX(0); } } - contextContainer.setBackground(javax.swing.UIManager.getDefaults().getColor("window")); + contextContainer.setBackground(ContentViewerDefaults.getPanelBackground()); contextContainer.setEnabled(foundASource); contextContainer.setVisible(foundASource); jScrollPane.getViewport().setView(contextContainer); @@ -346,6 +310,8 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte String sourceName = Bundle.ContextViewer_attachmentSource(); String sourceText = msgArtifactToAbbreviatedString(associatedArtifact); ContextSourcePanel sourcePanel = new ContextSourcePanel(sourceName, sourceText, associatedArtifact, dateTime); + sourcePanel.setBorder(new EmptyBorder(DATA_ROW_INSETS)); + sourcePanel.setAlignmentX(0); contextSourcePanels.add(sourcePanel); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() == associatedArtifact.getArtifactTypeID() @@ -353,18 +319,24 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte String sourceName = Bundle.ContextViewer_downloadSource(); String sourceText = webDownloadArtifactToString(associatedArtifact); ContextSourcePanel sourcePanel = new ContextSourcePanel(sourceName, sourceText, associatedArtifact, dateTime); + sourcePanel.setBorder(new EmptyBorder(DATA_ROW_INSETS)); + sourcePanel.setAlignmentX(0); contextSourcePanels.add(sourcePanel); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID() == associatedArtifact.getArtifactTypeID()) { String sourceName = Bundle.ContextViewer_recentDocs(); String sourceText = recentDocArtifactToString(associatedArtifact); - ContextUsagePanel usagePanel = new ContextUsagePanel(sourceName, sourceText, associatedArtifact, dateTime); + ContextUsagePanel usagePanel = new ContextUsagePanel(sourceName, sourceText, associatedArtifact, dateTime); + usagePanel.setBorder(new EmptyBorder(DATA_ROW_INSETS)); + usagePanel.setAlignmentX(0); contextUsagePanels.add(usagePanel); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID() == associatedArtifact.getArtifactTypeID()) { String sourceName = Bundle.ContextViewer_programExecution(); String sourceText = programExecArtifactToString(associatedArtifact); - ContextUsagePanel usagePanel = new ContextUsagePanel(sourceName, sourceText, associatedArtifact, dateTime); + ContextUsagePanel usagePanel = new ContextUsagePanel(sourceName, sourceText, associatedArtifact, dateTime); + usagePanel.setBorder(new EmptyBorder(DATA_ROW_INSETS)); + usagePanel.setAlignmentX(0); contextUsagePanels.add(usagePanel); } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java index b221e1f522..95c7385023 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java @@ -10,6 +10,7 @@ import java.awt.Font; import java.awt.Insets; import java.awt.Toolkit; import com.google.common.base.Supplier; +import java.awt.Color; import javax.swing.UIManager; /** @@ -17,53 +18,59 @@ import javax.swing.UIManager; * @author gregd */ public class ContentViewerDefaults { + private static final Supplier DEFAULT_FONT = Suppliers.memoize(() -> UIManager.getDefaults().getFont("Label.font")); - + private static final Supplier DEFAULT_FONT_PX = Suppliers.memoize(() -> { // based on https://stackoverflow.com/questions/5829703/java-getting-a-font-with-a-specific-height-in-pixels/26564924#26564924 return (int) Math.round(DEFAULT_FONT.get().getSize() * Toolkit.getDefaultToolkit().getScreenResolution() / 72.0); }); - + private static final Supplier HEADER_FONT = Suppliers.memoize(() -> { Font defaultFont = DEFAULT_FONT.get(); return defaultFont.deriveFont(Font.BOLD, defaultFont.getSize() + 2); }); - + private static final Supplier DEFAULT_PANEL_INSETS = Suppliers.memoize(() -> UIManager.getDefaults().getInsets("TextPane.margin")); - + private static final Supplier DEFAULT_INDENT = Suppliers.memoize(() -> DEFAULT_FONT_PX.get()); private static final Supplier DEFAULT_SECTION_SPACING = Suppliers.memoize(() -> DEFAULT_FONT_PX.get()); - - private static final Supplier DEFAULT_COLUMN_SPACING = Suppliers.memoize(() -> (int)(DEFAULT_FONT_PX.get() / 3)); - private static final Supplier DEFAULT_LINE_SPACING = Suppliers.memoize(() -> (int)(DEFAULT_FONT_PX.get() / 5)); - + + private static final Supplier DEFAULT_COLUMN_SPACING = Suppliers.memoize(() -> (DEFAULT_FONT_PX.get() / 3)); + private static final Supplier DEFAULT_LINE_SPACING = Suppliers.memoize(() -> (DEFAULT_FONT_PX.get() / 5)); + + private static final Supplier DEFAULT_BACKGROUND = Suppliers.memoize(() -> UIManager.getColor("Panel.background")); + public static int getColumnSpacing() { return DEFAULT_COLUMN_SPACING.get(); } - + public static Font getFont() { return DEFAULT_FONT.get(); } - + public static Font getHeaderFont() { return HEADER_FONT.get(); } - + public static Insets getPanelInsets() { return DEFAULT_PANEL_INSETS.get(); } - + public static Integer getSectionIndent() { return DEFAULT_INDENT.get(); } - + public static Integer getSectionSpacing() { return DEFAULT_SECTION_SPACING.get(); } - + public static Integer getLineSpacing() { return DEFAULT_LINE_SPACING.get(); } - + + public static Color getPanelBackground() { + return DEFAULT_BACKGROUND.get(); + } // line spacing??? } From 2f20e841124efb96827b0480f555b019a96464da Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 4 Jun 2021 09:38:27 -0400 Subject: [PATCH 07/33] content viewer common css --- .../layout/ContentViewerHtmlStyles.java | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java new file mode 100644 index 0000000000..b417e3391d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java @@ -0,0 +1,68 @@ +/* + * 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.layout; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Insets; +import javax.swing.JLabel; + +/** + * + * @author gregd + */ +public class ContentViewerHtmlStyles { + + private static final String DEFAULT_FONT_FAMILY = new JLabel().getFont().getFamily(); + private static final int DEFAULT_FONT_SIZE = new JLabel().getFont().getSize(); + private static final Color DEFAULT_BACKGROUND = new JLabel().getBackground(); + + // html stylesheet classnames for components + private static final String ANALYSIS_RESULTS_CLASS_PREFIX = "analysisResult_"; + private static final String SPACED_SECTION_CLASSNAME = ANALYSIS_RESULTS_CLASS_PREFIX + "spacedSection"; + private static final String SUBSECTION_CLASSNAME = ANALYSIS_RESULTS_CLASS_PREFIX + "subsection"; + private static final String HEADER_CLASSNAME = ANALYSIS_RESULTS_CLASS_PREFIX + "header"; + public static final String MESSAGE_CLASSNAME = ANALYSIS_RESULTS_CLASS_PREFIX + "message"; + public static final String TD_CLASSNAME = ANALYSIS_RESULTS_CLASS_PREFIX + "td"; + + // Anchors are inserted into the navigation so that the viewer can navigate to a selection. + // This is the prefix of those anchors. + private static final String CLASSNAME_PREFIX = "ContentViewer_"; + + // how big the header should be + private static final int HEADER_FONT_SIZE = DEFAULT_FONT_SIZE + 2; + + // spacing occurring after an item + private static final int DEFAULT_SECTION_SPACING = DEFAULT_FONT_SIZE / 2; + private static final int CELL_SPACING = DEFAULT_FONT_SIZE / 2; + + // the subsection indent + private static final int DEFAULT_SUBSECTION_LEFT_PAD = DEFAULT_FONT_SIZE; + + + + + private static final Font DEFAULT_FONT = ContentViewerDefaults.getFont(); + private static final Font HEADER_FONT = ContentViewerDefaults.getHeaderFont(); + + + // additional styling for components + private static final String STYLE_SHEET_RULE + = String.format(" .%s { font-family: %s; font-size: %dpt;font-style:italic; margin: 0px; padding: 0px 0px %dpx 0px; } ", + MESSAGE_CLASSNAME, DEFAULT_FONT.getFamily(), DEFAULT_FONT.getSize(), ContentViewerDefaults.getLineSpacing()) + + String.format(" .%s { font-family: %s; font-size: %dpt; font-weight: bold; margin: 0px; padding: 0px 0px %dpx 0px; } ", + HEADER_CLASSNAME, HEADER_FONT.getFamily(), HEADER_FONT.getSize(), ContentViewerDefaults.getLineSpacing()) + + String.format(" .%s { font-family: %s; font-size: %dpt; margin: 0px; padding: 0px 0px %dpx 0px; } ", + TEXT_CLASSNAME, DEFAULT_FONT.getFamily(), DEFAULT_FONT.getSize(), ContentViewerDefaults.getLineSpacing()) + + + String.format(" .%s { padding-left: %dpx } ", + INDENTED_CLASSNAME, ContentViewerDefaults.getSectionIndent()) + + String.format(" .%s { margin-top: %dpx } ", + NOT_FIRST_SECTION_CLASSNAME, ContentViewerDefaults.getSectionSpacing()) + + String.format(" .%s { margin-top: %dpx } ", + KEY_COLUMN_TD_CLASSNAME, ContentViewerDefaults.getColumnSpacing()); + +} From e5a36e9dc8147e9e9e0f9f631105118deafe3f6e Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 4 Jun 2021 14:08:43 -0400 Subject: [PATCH 08/33] annotation viewer and text panes --- .../AnnotationsContentViewer.java | 49 +------- .../autopsy/contentviewers/Metadata.java | 3 +- .../AnalysisResultsContentPanel.form | 3 - .../AnalysisResultsContentPanel.java | 81 +++++-------- .../application/Annotations.java | 81 +++++++------ .../layout/ContentViewerDefaults.java | 10 +- .../layout/ContentViewerHtmlStyles.java | 106 ++++++++++++------ .../corecomponents/AutoWrappingJTextPane.java | 9 +- 8 files changed, 163 insertions(+), 179 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java index 304300cec4..3df51c9e48 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java @@ -18,14 +18,10 @@ */ package org.sleuthkit.autopsy.contentviewers; -import java.awt.Color; import java.awt.Component; import java.util.concurrent.ExecutionException; import java.util.logging.Level; -import javax.swing.JLabel; import javax.swing.SwingWorker; -import javax.swing.text.EditorKit; -import javax.swing.text.html.HTMLEditorKit; import static org.openide.util.NbBundle.Messages; import org.openide.nodes.Node; @@ -37,6 +33,7 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.contentviewers.application.Annotations; import org.sleuthkit.autopsy.coreutils.Logger; import org.jsoup.nodes.Document; +import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerHtmlStyles; /** * Annotations view of file contents. @@ -49,39 +46,6 @@ import org.jsoup.nodes.Document; "AnnotationsContentViewer.onEmpty=No annotations were found for this particular item." }) public class AnnotationsContentViewer extends javax.swing.JPanel implements DataContentViewer { - - private static final String DEFAULT_FONT_FAMILY = new JLabel().getFont().getFamily(); - private static final int DEFAULT_FONT_SIZE = new JLabel().getFont().getSize(); - private static final Color DEFAULT_BACKGROUND = new JLabel().getBackground(); - - // how big the subheader should be - private static final int SUBHEADER_FONT_SIZE = DEFAULT_FONT_SIZE + 1; - - // how big the header should be - private static final int HEADER_FONT_SIZE = DEFAULT_FONT_SIZE + 2; - - // the subsection indent - private static final int DEFAULT_SUBSECTION_LEFT_PAD = DEFAULT_FONT_SIZE; - - // spacing occurring after an item - private static final int DEFAULT_SECTION_SPACING = DEFAULT_FONT_SIZE * 2; - private static final int DEFAULT_SUBSECTION_SPACING = DEFAULT_FONT_SIZE / 2; - private static final int CELL_SPACING = DEFAULT_FONT_SIZE / 2; - - // additional styling for components - private static final String STYLE_SHEET_RULE - = String.format(" .%s { font-family: %s; font-size: %dpt; font-style:italic; margin: 0px; padding: 0px; } ", - Annotations.MESSAGE_CLASSNAME, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE) - + String.format(" .%s { font-family: %s; font-size:%dpt;font-weight:bold; margin: 0px; margin-top: %dpx; padding: 0px; } ", - Annotations.SUBHEADER_CLASSNAME, DEFAULT_FONT_FAMILY, SUBHEADER_FONT_SIZE, DEFAULT_SUBSECTION_SPACING) - + String.format(" .%s { font-family: %s; font-size:%dpt;font-weight:bold; margin: 0px; padding: 0px; } ", - Annotations.HEADER_CLASSNAME, DEFAULT_FONT_FAMILY, HEADER_FONT_SIZE) - + String.format(" td { vertical-align: top; font-family: %s; font-size:%dpt; text-align: left; margin: 0px; padding: 0px %dpx 0px 0px;} ", - DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, CELL_SPACING) - + String.format(" th { vertical-align: top; text-align: left; margin: 0px; padding: 0px %dpx 0px 0px} ", - DEFAULT_FONT_SIZE, CELL_SPACING) - + String.format(" .%s { margin: %dpx 0px; padding-left: %dpx; } ", Annotations.SUBSECTION_CLASSNAME, DEFAULT_SUBSECTION_SPACING, DEFAULT_SUBSECTION_LEFT_PAD) - + String.format(" .%s { margin-bottom: %dpx; } ", Annotations.SECTION_CLASSNAME, DEFAULT_SECTION_SPACING); private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(AnnotationsContentViewer.class.getName()); @@ -93,14 +57,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data */ public AnnotationsContentViewer() { initComponents(); - Utilities.configureTextPaneAsHtml(textPanel); - textPanel.setBackground(DEFAULT_BACKGROUND); - // get html editor kit and apply additional style rules - EditorKit editorKit = textPanel.getEditorKit(); - if (editorKit instanceof HTMLEditorKit) { - HTMLEditorKit htmlKit = (HTMLEditorKit) editorKit; - htmlKit.getStyleSheet().addRule(STYLE_SHEET_RULE); - } + ContentViewerHtmlStyles.setupHtmlJTextPane(textPanel); } @Override @@ -231,7 +188,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data if(doc != null) { return doc.html(); } else { - return Bundle.AnnotationsContentViewer_onEmpty(); + return "" + Bundle.AnnotationsContentViewer_onEmpty() + ""; } } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java index f37cccb028..37edf6d5c0 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java @@ -29,6 +29,7 @@ import org.openide.nodes.Node; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerHtmlStyles; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; @@ -116,7 +117,7 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer { * selectAllMenuItem.addActionListener(actList); */ - Utilities.configureTextPaneAsHtml(jTextPane1); + ContentViewerHtmlStyles.setupHtmlJTextPane(jTextPane1); } private void setText(String str) { diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.form b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.form index 22fbe9e8a1..98fb50c89a 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.form @@ -42,9 +42,6 @@ - - - diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java index 72ab3c6853..aadfe4b677 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java @@ -18,11 +18,9 @@ */ package org.sleuthkit.autopsy.contentviewers.analysisresults; -import java.awt.Color; import java.text.MessageFormat; import java.util.List; import java.util.Optional; -import javax.swing.JLabel; import javax.swing.text.html.HTMLEditorKit; import org.apache.commons.lang3.tuple.Pair; import org.jsoup.Jsoup; @@ -31,6 +29,8 @@ import org.jsoup.nodes.Element; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.contentviewers.analysisresults.AnalysisResultsViewModel.NodeResults; import org.sleuthkit.autopsy.contentviewers.analysisresults.AnalysisResultsViewModel.ResultDisplayAttributes; +import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerDefaults; +import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerHtmlStyles; import org.sleuthkit.datamodel.AnalysisResult; import org.sleuthkit.datamodel.Score; @@ -43,54 +43,16 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel { private static final String EMPTY_HTML = ""; - private static final String DEFAULT_FONT_FAMILY = new JLabel().getFont().getFamily(); - private static final int DEFAULT_FONT_SIZE = new JLabel().getFont().getSize(); - private static final Color DEFAULT_BACKGROUND = new JLabel().getBackground(); - - // html stylesheet classnames for components - private static final String ANALYSIS_RESULTS_CLASS_PREFIX = "analysisResult_"; - private static final String SPACED_SECTION_CLASSNAME = ANALYSIS_RESULTS_CLASS_PREFIX + "spacedSection"; - private static final String SUBSECTION_CLASSNAME = ANALYSIS_RESULTS_CLASS_PREFIX + "subsection"; - private static final String HEADER_CLASSNAME = ANALYSIS_RESULTS_CLASS_PREFIX + "header"; - public static final String MESSAGE_CLASSNAME = ANALYSIS_RESULTS_CLASS_PREFIX + "message"; - public static final String TD_CLASSNAME = ANALYSIS_RESULTS_CLASS_PREFIX + "td"; - // Anchors are inserted into the navigation so that the viewer can navigate to a selection. // This is the prefix of those anchors. private static final String RESULT_ANCHOR_PREFIX = "AnalysisResult_"; - - // how big the header should be - private static final int HEADER_FONT_SIZE = DEFAULT_FONT_SIZE + 2; - - // spacing occurring after an item - private static final int DEFAULT_SECTION_SPACING = DEFAULT_FONT_SIZE / 2; - private static final int CELL_SPACING = DEFAULT_FONT_SIZE / 2; - - // the subsection indent - private static final int DEFAULT_SUBSECTION_LEFT_PAD = DEFAULT_FONT_SIZE; - - // additional styling for components - private static final String STYLE_SHEET_RULE - = String.format(" .%s { font-size: %dpt;font-style:italic; margin: 0px; padding: 0px; } ", MESSAGE_CLASSNAME, DEFAULT_FONT_SIZE) - + String.format(" .%s { font-family: %s; font-size: %dpt; font-weight: bold; margin: 0px; padding: 0px; } ", - HEADER_CLASSNAME, DEFAULT_FONT_FAMILY, HEADER_FONT_SIZE) - + String.format(" .%s { vertical-align: top; font-family: %s; font-size: %dpt; text-align: left; margin: 0pt; padding: 0px %dpt 0px 0px;} ", - TD_CLASSNAME, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, CELL_SPACING) - + String.format(" .%s { margin-top: %dpt; } ", SPACED_SECTION_CLASSNAME, DEFAULT_SECTION_SPACING) - + String.format(" .%s { padding-left: %dpt; }", SUBSECTION_CLASSNAME, DEFAULT_SUBSECTION_LEFT_PAD); - - /** * Creates new form AnalysisResultsContentViewer */ public AnalysisResultsContentPanel() { initComponents(); - - textPanel.setContentType("text/html;charset=UTF-8"); //NON-NLS - HTMLEditorKit kit = new HTMLEditorKit(); - textPanel.setEditorKit(kit); - kit.getStyleSheet().addRule(STYLE_SHEET_RULE); + ContentViewerHtmlStyles.setupHtmlJTextPane(textPanel); } /** @@ -101,7 +63,7 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel { void showMessage(String message) { textPanel.setText("" + MessageFormat.format("

{1}

", - MESSAGE_CLASSNAME, + ContentViewerHtmlStyles.getMessageClassName(), message == null ? "" : message) + ""); } @@ -137,7 +99,10 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel { List displayAttributes = nodeResults.getAnalysisResults(); for (int idx = 0; idx < displayAttributes.size(); idx++) { AnalysisResultsViewModel.ResultDisplayAttributes resultAttrs = displayAttributes.get(idx); - appendResult(body, idx, resultAttrs); + Element sectionDiv = appendResult(body, idx, resultAttrs); + if (idx > 0 || aggregateScore.isPresent()) { + sectionDiv.attr("class", ContentViewerHtmlStyles.getSpacedSectionClassName()); + } } // set the body html @@ -165,11 +130,12 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel { * @param parent The parent element. * @param index The index of the item in the list of all items. * @param attrs The attributes of this item. + * @return The result div. */ @NbBundle.Messages({"# {0} - analysisResultsNumber", "AnalysisResultsContentPanel_result_headerKey=Analysis Result {0}" }) - private void appendResult(Element parent, int index, AnalysisResultsViewModel.ResultDisplayAttributes attrs) { + private Element appendResult(Element parent, int index, AnalysisResultsViewModel.ResultDisplayAttributes attrs) { // create a new section with appropriate header Element sectionDiv = appendSection(parent, Bundle.AnalysisResultsContentPanel_result_headerKey(index + 1), @@ -177,7 +143,7 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel { // create a table Element table = sectionDiv.appendElement("table"); - table.attr("class", SUBSECTION_CLASSNAME); + table.attr("class", ContentViewerHtmlStyles.getIndentedClassName()); Element tableBody = table.appendElement("tbody"); @@ -187,13 +153,15 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel { String keyString = keyVal.getKey() == null ? "" : keyVal.getKey() + ":"; row.appendElement("td") .text(keyString) - .attr("class", TD_CLASSNAME); + .attr("class", ContentViewerHtmlStyles.getTextClassName() + " " + ContentViewerHtmlStyles.getKeyColumnClassName()); String valueString = keyVal.getValue() == null ? "" : keyVal.getValue(); row.appendElement("td") .text(valueString) - .attr("class", TD_CLASSNAME); + .attr("class", ContentViewerHtmlStyles.getTextClassName()); } + + return sectionDiv; } /** @@ -209,18 +177,22 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel { Element sectionDiv = parent.appendElement("div"); // append an anchor tag if there is one + Element anchorEl = null; if (anchorId.isPresent()) { - Element anchorEl = sectionDiv.appendElement("a"); + anchorEl = sectionDiv.appendElement("a"); anchorEl.attr("name", anchorId.get()); + anchorEl.attr("style", "padding: 0px; margin: 0px; display: inline-block;"); } - - // set the class for the section - sectionDiv.attr("class", SPACED_SECTION_CLASSNAME); - + // append the header - Element header = sectionDiv.appendElement("h1"); + Element header = null; + header = (anchorEl == null) + ? sectionDiv.appendElement("h1") + : anchorEl.appendElement("h1"); + header.text(headerText); - header.attr("class", HEADER_CLASSNAME); + header.attr("class", ContentViewerHtmlStyles.getHeaderClassName()); + header.attr("style", "display: inline-block"); // return the section element return sectionDiv; @@ -241,7 +213,6 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel { setPreferredSize(new java.awt.Dimension(100, 58)); textPanel.setEditable(false); - textPanel.setBackground(DEFAULT_BACKGROUND); textPanel.setName(""); // NOI18N textPanel.setPreferredSize(new java.awt.Dimension(600, 52)); scrollPane.setViewportView(textPanel); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/application/Annotations.java b/Core/src/org/sleuthkit/autopsy/contentviewers/application/Annotations.java index feec2703dc..9651ddc518 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/application/Annotations.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/application/Annotations.java @@ -24,7 +24,6 @@ import java.util.List; import java.util.function.Function; import java.util.logging.Level; import java.util.stream.Collectors; -import javax.swing.JLabel; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.jsoup.Jsoup; @@ -39,6 +38,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil; +import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerHtmlStyles; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -80,18 +80,6 @@ public class Annotations { private static final String EMPTY_HTML = ""; - private static final int DEFAULT_FONT_SIZE = new JLabel().getFont().getSize(); - // spacing occurring after an item - private static final int DEFAULT_TABLE_SPACING = DEFAULT_FONT_SIZE; - - // html stylesheet classnames for components - public static final String MESSAGE_CLASSNAME = "message"; - public static final String SUBSECTION_CLASSNAME = "subsection"; - public static final String SUBHEADER_CLASSNAME = "subheader"; - public static final String SECTION_CLASSNAME = "section"; - public static final String HEADER_CLASSNAME = "header"; - public static final String VERTICAL_TABLE_CLASSNAME = "vertical-table"; - // describing table values for a tag private static final List> TAG_ENTRIES = Arrays.asList( new ItemEntry<>(Bundle.Annotations_tagEntryDataLabel_tag(), @@ -200,11 +188,11 @@ public class Annotations { * @return If any content was actually rendered. */ private static boolean renderArtifact(Element parent, BlackboardArtifact bba, Content sourceContent) { - boolean contentRendered = appendEntries(parent, TAG_CONFIG, getTags(bba), false); + boolean contentRendered = appendEntries(parent, TAG_CONFIG, getTags(bba), false, true); if (CentralRepository.isEnabled()) { List centralRepoComments = getCentralRepositoryData(bba); - boolean crRendered = appendEntries(parent, CR_COMMENTS_CONFIG, centralRepoComments, false); + boolean crRendered = appendEntries(parent, CR_COMMENTS_CONFIG, centralRepoComments, false, !contentRendered); contentRendered = contentRendered || crRendered; } @@ -213,12 +201,18 @@ public class Annotations { || BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() == bba.getArtifactTypeID()) && (hasTskComment(bba))) { - boolean filesetRendered = appendEntries(parent, ARTIFACT_COMMENT_CONFIG, Arrays.asList(bba), false); + boolean filesetRendered = appendEntries(parent, ARTIFACT_COMMENT_CONFIG, Arrays.asList(bba), false, !contentRendered); contentRendered = contentRendered || filesetRendered; } Element sourceFileSection = appendSection(parent, Bundle.Annotations_sourceFile_title()); - boolean sourceFileRendered = renderContent(sourceFileSection, sourceContent, true); + sourceFileSection.attr("class", ContentViewerHtmlStyles.getSpacedSectionClassName()); + + Element sourceFileContainer = sourceFileSection.appendElement("div"); + sourceFileContainer.attr("class", ContentViewerHtmlStyles.getIndentedClassName()); + + + boolean sourceFileRendered = renderContent(sourceFileContainer, sourceContent, true); if (!sourceFileRendered) { sourceFileSection.remove(); @@ -238,24 +232,27 @@ public class Annotations { * @return If any content was actually rendered. */ private static boolean renderContent(Element parent, Content sourceContent, boolean isSubheader) { - boolean contentRendered = appendEntries(parent, TAG_CONFIG, getTags(sourceContent), isSubheader); + boolean contentRendered = appendEntries(parent, TAG_CONFIG, getTags(sourceContent), isSubheader, true); if (sourceContent instanceof AbstractFile) { AbstractFile sourceFile = (AbstractFile) sourceContent; if (CentralRepository.isEnabled()) { List centralRepoComments = getCentralRepositoryData(sourceFile); - boolean crRendered = appendEntries(parent, CR_COMMENTS_CONFIG, centralRepoComments, isSubheader); + boolean crRendered = appendEntries(parent, CR_COMMENTS_CONFIG, centralRepoComments, isSubheader, + !contentRendered); contentRendered = contentRendered || crRendered; } boolean hashsetRendered = appendEntries(parent, HASHSET_CONFIG, getFileSetHits(sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT), - isSubheader); + isSubheader, + !contentRendered); boolean interestingFileRendered = appendEntries(parent, INTERESTING_FILE_CONFIG, getFileSetHits(sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT), - isSubheader); + isSubheader, + !contentRendered); contentRendered = contentRendered || hashsetRendered || interestingFileRendered; } @@ -456,24 +453,36 @@ public class Annotations { * will be formatted as a table in the format specified in the * SectionConfig. * - * @param parent The parent element for which the entries will be - * attached. - * @param config The display configuration for this entry type (i.e. - * table type, name, if data is not present). - * @param items The items to display. - * @param isSubsection Whether or not this should be displayed as a - * subsection. If not displayed as a top-level section. + * @param parent The parent element for which the entries will be + * attached. + * @param config The display configuration for this entry type (i.e. + * table type, name, if data is not present). + * @param items The items to display. + * @param isSubsection Whether or not this should be displayed as a + * subsection. If not displayed as a top-level + * section. + * @param isFirstSection Whether or not this is the first section appended. * * @return If there was actual content rendered for this set of entries. */ private static boolean appendEntries(Element parent, Annotations.SectionConfig config, List items, - boolean isSubsection) { + boolean isSubsection, boolean isFirstSection) { if (items == null || items.isEmpty()) { return false; } Element sectionDiv = (isSubsection) ? appendSubsection(parent, config.getTitle()) : appendSection(parent, config.getTitle()); - appendVerticalEntryTables(sectionDiv, items, config.getAttributes()); + if (!isFirstSection) { + sectionDiv.attr("class", ContentViewerHtmlStyles.getSpacedSectionClassName()); + } + + Element sectionContainer = sectionDiv.appendElement("div"); + + if (!isSubsection) { + sectionContainer.attr("class", ContentViewerHtmlStyles.getIndentedClassName()); + } + + appendVerticalEntryTables(sectionContainer, items, config.getAttributes()); return true; } @@ -499,12 +508,11 @@ public class Annotations { .collect(Collectors.toList()); Element childTable = appendTable(parent, 2, tableData, null); - childTable.attr("class", VERTICAL_TABLE_CLASSNAME); if (isFirst) { isFirst = false; } else { - childTable.attr("style", String.format("margin-top: %dpx;", DEFAULT_TABLE_SPACING)); + childTable.attr("class", ContentViewerHtmlStyles.getSpacedSectionClassName()); } } @@ -551,6 +559,7 @@ public class Annotations { Element row = rowParent.appendElement("tr"); for (int i = 0; i < columnNumber; i++) { Element cell = row.appendElement(cellType); + cell.attr("class", ContentViewerHtmlStyles.getTextClassName()); if (data != null && i < data.size()) { cell.text(StringUtils.isEmpty(data.get(i)) ? "" : data.get(i)); } @@ -568,10 +577,9 @@ public class Annotations { */ private static Element appendSection(Element parent, String headerText) { Element sectionDiv = parent.appendElement("div"); - sectionDiv.attr("class", SECTION_CLASSNAME); Element header = sectionDiv.appendElement("h1"); header.text(headerText); - header.attr("class", HEADER_CLASSNAME); + header.attr("class", ContentViewerHtmlStyles.getHeaderClassName()); return sectionDiv; } @@ -585,10 +593,9 @@ public class Annotations { */ private static Element appendSubsection(Element parent, String headerText) { Element subsectionDiv = parent.appendElement("div"); - subsectionDiv.attr("class", SUBSECTION_CLASSNAME); Element header = subsectionDiv.appendElement("h2"); header.text(headerText); - header.attr("class", SUBHEADER_CLASSNAME); + header.attr("class", ContentViewerHtmlStyles.getHeaderClassName()); return subsectionDiv; } @@ -605,7 +612,7 @@ public class Annotations { private static Element appendMessage(Element parent, String message) { Element messageEl = parent.appendElement("p"); messageEl.text(message); - messageEl.attr("class", MESSAGE_CLASSNAME); + messageEl.attr("class", ContentViewerHtmlStyles.getMessageClassName()); return messageEl; } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java index 95c7385023..fc9f7c038c 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java @@ -25,6 +25,11 @@ public class ContentViewerDefaults { // based on https://stackoverflow.com/questions/5829703/java-getting-a-font-with-a-specific-height-in-pixels/26564924#26564924 return (int) Math.round(DEFAULT_FONT.get().getSize() * Toolkit.getDefaultToolkit().getScreenResolution() / 72.0); }); + + private static final Supplier SUB_HEADER_FONT = Suppliers.memoize(() -> { + Font defaultFont = DEFAULT_FONT.get(); + return defaultFont.deriveFont(Font.BOLD); + }); private static final Supplier HEADER_FONT = Suppliers.memoize(() -> { Font defaultFont = DEFAULT_FONT.get(); @@ -72,5 +77,8 @@ public class ContentViewerDefaults { public static Color getPanelBackground() { return DEFAULT_BACKGROUND.get(); } - // line spacing??? + + public static Font getSubHeaderFont() { + return SUB_HEADER_FONT.get(); + } } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java index b417e3391d..0aa5ba98d3 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java @@ -5,64 +5,100 @@ */ package org.sleuthkit.autopsy.contentviewers.layout; -import java.awt.Color; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; import java.awt.Font; -import java.awt.Insets; -import javax.swing.JLabel; +import javax.swing.JTextPane; +import javax.swing.text.html.HTMLEditorKit; +import javax.swing.text.html.StyleSheet; /** * * @author gregd */ public class ContentViewerHtmlStyles { - - private static final String DEFAULT_FONT_FAMILY = new JLabel().getFont().getFamily(); - private static final int DEFAULT_FONT_SIZE = new JLabel().getFont().getSize(); - private static final Color DEFAULT_BACKGROUND = new JLabel().getBackground(); // html stylesheet classnames for components - private static final String ANALYSIS_RESULTS_CLASS_PREFIX = "analysisResult_"; - private static final String SPACED_SECTION_CLASSNAME = ANALYSIS_RESULTS_CLASS_PREFIX + "spacedSection"; - private static final String SUBSECTION_CLASSNAME = ANALYSIS_RESULTS_CLASS_PREFIX + "subsection"; - private static final String HEADER_CLASSNAME = ANALYSIS_RESULTS_CLASS_PREFIX + "header"; - public static final String MESSAGE_CLASSNAME = ANALYSIS_RESULTS_CLASS_PREFIX + "message"; - public static final String TD_CLASSNAME = ANALYSIS_RESULTS_CLASS_PREFIX + "td"; + private static final String CLASS_PREFIX = ContentViewerHtmlStyles.class.getSimpleName(); - // Anchors are inserted into the navigation so that the viewer can navigate to a selection. - // This is the prefix of those anchors. - private static final String CLASSNAME_PREFIX = "ContentViewer_"; + private static final String HEADER_CLASSNAME = CLASS_PREFIX + "header"; + private static final String SUB_HEADER_CLASSNAME = CLASS_PREFIX + "subHeader"; - // how big the header should be - private static final int HEADER_FONT_SIZE = DEFAULT_FONT_SIZE + 2; + private static final String MESSAGE_CLASSNAME = CLASS_PREFIX + "message"; + private static final String TEXT_CLASSNAME = CLASS_PREFIX + "text"; + private static final String INDENTED_CLASSNAME = CLASS_PREFIX + "indent"; + private static final String SPACED_SECTION_CLASSNAME = CLASS_PREFIX + "spacedSection"; + private static final String KEY_COLUMN_TD_CLASSNAME = CLASS_PREFIX + "keyKolumn"; - // spacing occurring after an item - private static final int DEFAULT_SECTION_SPACING = DEFAULT_FONT_SIZE / 2; - private static final int CELL_SPACING = DEFAULT_FONT_SIZE / 2; - - // the subsection indent - private static final int DEFAULT_SUBSECTION_LEFT_PAD = DEFAULT_FONT_SIZE; - - - - private static final Font DEFAULT_FONT = ContentViewerDefaults.getFont(); private static final Font HEADER_FONT = ContentViewerDefaults.getHeaderFont(); - - + private static final Font SUB_HEADER_FONT = ContentViewerDefaults.getSubHeaderFont(); + // additional styling for components private static final String STYLE_SHEET_RULE - = String.format(" .%s { font-family: %s; font-size: %dpt;font-style:italic; margin: 0px; padding: 0px 0px %dpx 0px; } ", + = String.format(" .%s { font-family: %s; font-size: %dpt;font-style:italic; margin: 0px; padding: 0px 0px %dpx 0px; } ", MESSAGE_CLASSNAME, DEFAULT_FONT.getFamily(), DEFAULT_FONT.getSize(), ContentViewerDefaults.getLineSpacing()) + String.format(" .%s { font-family: %s; font-size: %dpt; font-weight: bold; margin: 0px; padding: 0px 0px %dpx 0px; } ", HEADER_CLASSNAME, HEADER_FONT.getFamily(), HEADER_FONT.getSize(), ContentViewerDefaults.getLineSpacing()) + + String.format(" .%s { font-family: %s; font-size: %dpt; font-weight: bold; margin: 0px; padding: 0px 0px %dpx 0px; } ", + SUB_HEADER_CLASSNAME, SUB_HEADER_FONT.getFamily(), SUB_HEADER_FONT.getSize(), ContentViewerDefaults.getLineSpacing()) + String.format(" .%s { font-family: %s; font-size: %dpt; margin: 0px; padding: 0px 0px %dpx 0px; } ", TEXT_CLASSNAME, DEFAULT_FONT.getFamily(), DEFAULT_FONT.getSize(), ContentViewerDefaults.getLineSpacing()) - + String.format(" .%s { padding-left: %dpx } ", INDENTED_CLASSNAME, ContentViewerDefaults.getSectionIndent()) - + String.format(" .%s { margin-top: %dpx } ", - NOT_FIRST_SECTION_CLASSNAME, ContentViewerDefaults.getSectionSpacing()) - + String.format(" .%s { margin-top: %dpx } ", + + String.format(" .%s { padding-top: %dpx } ", + SPACED_SECTION_CLASSNAME, ContentViewerDefaults.getSectionSpacing()) + + String.format(" .%s { padding-right: %dpx } ", KEY_COLUMN_TD_CLASSNAME, ContentViewerDefaults.getColumnSpacing()); + private static final Supplier STYLE_SHEET = Suppliers.memoize(() -> { + StyleSheet stylesheet = new StyleSheet(); + stylesheet.addRule(STYLE_SHEET_RULE); + return stylesheet; + }); + + public static String getHeaderClassName() { + return HEADER_CLASSNAME; + } + + public static String getSubHeaderClassName() { + return SUB_HEADER_CLASSNAME; + } + + public static String getMessageClassName() { + return MESSAGE_CLASSNAME; + } + + public static String getTextClassName() { + return TEXT_CLASSNAME; + } + + public static String getIndentedClassName() { + return INDENTED_CLASSNAME; + } + + public static String getSpacedSectionClassName() { + return SPACED_SECTION_CLASSNAME; + } + + public static String getKeyColumnClassName() { + return KEY_COLUMN_TD_CLASSNAME; + } + + public static String getStyleSheetRule() { + return STYLE_SHEET_RULE; + } + + public static StyleSheet getStyleSheet() { + return STYLE_SHEET.get(); + } + + public static void setupHtmlJTextPane(JTextPane textPane) { + textPane.setContentType("text/html;charset=UTF-8"); //NON-NLS + HTMLEditorKit kit = new HTMLEditorKit(); + textPane.setEditorKit(kit); + kit.setStyleSheet(ContentViewerHtmlStyles.getStyleSheet()); + textPane.setMargin(ContentViewerDefaults.getPanelInsets()); + textPane.setBackground(ContentViewerDefaults.getPanelBackground()); + } } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AutoWrappingJTextPane.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AutoWrappingJTextPane.java index 1e4c1f4c63..4ae8b6f771 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AutoWrappingJTextPane.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AutoWrappingJTextPane.java @@ -27,6 +27,7 @@ import javax.swing.text.ViewFactory; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.InlineView; import javax.swing.text.html.ParagraphView; +import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerDefaults; import org.sleuthkit.autopsy.coreutils.EscapeUtil; /** @@ -96,9 +97,15 @@ public class AutoWrappingJTextPane extends JTextPane { this.setEditorKit(editorKit); } + + @Override public void setText(String text) { - super.setText("
" + EscapeUtil.escapeHtml(text) + "
"); + // setting the text format with style to avoid problems with overridden styles. + String style = String.format("font-family: %s; font-size: %dpt; margin: 0px; padding: 0px 0px %dpx 0px;", + ContentViewerDefaults.getFont().getFamily(), ContentViewerDefaults.getFont().getSize(), ContentViewerDefaults.getLineSpacing()); + + super.setText("
" + EscapeUtil.escapeHtml(text) + "
"); } } From 6226f68a735675b0a258afb47129c74a7bec09e1 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Fri, 4 Jun 2021 15:49:08 -0400 Subject: [PATCH 09/33] Added the call to getUniquePath to the makeKey method --- .../autopsy/datamodel/ContentChildren.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentChildren.java index 44885e1ef8..ce8646563c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentChildren.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.logging.Level; +import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Directory; @@ -103,7 +104,21 @@ class ContentChildren extends AbstractContentChildren { @Override protected List makeKeys() { - return getDisplayChildren(parent); + List contentList = getDisplayChildren(parent); + + // Call the getUniquePath method to cache the value for future use + // in the EDT + contentList.forEach(content->{ + try { + content.getUniquePath(); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Failed attempt to cache the " + + "unique path of the abstract file instance. Name: %s (objID=%d)", + content.getName(), content.getId()), ex); + } + }); + + return contentList; } @Override From 0737e48d51297f5d56685b9e5d985121de2c887a Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 7 Jun 2021 10:18:27 -0400 Subject: [PATCH 10/33] work on communication artifact viewers --- .../CallLogArtifactViewer.java | 9 ++- .../CommunicationArtifactViewerHelper.java | 74 +++++++++---------- .../ContactArtifactViewer.java | 19 +++-- .../layout/ContentViewerDefaults.java | 6 ++ .../layout/ContentViewerHtmlStyles.java | 3 +- 5 files changed, 57 insertions(+), 54 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java index 8d27c6c5be..bcea405c14 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.contentviewers.artifactviewers; import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; +import java.awt.Insets; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -35,6 +36,7 @@ import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerDefaults; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.guiutils.ContactCache; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -444,9 +446,8 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac "CalllogArtifactViewer_cr_disabled_message=Enable Central Repository to view, create and edit personas." }) private void showCRDisabledMessage() { - CommunicationArtifactViewerHelper.addBlankLine(this, m_gridBagLayout, m_constraints); - m_constraints.gridy++; - CommunicationArtifactViewerHelper.addMessageRow(this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_cr_disabled_message()); + Insets messageInsets = new Insets(ContentViewerDefaults.getSectionSpacing(), 0, ContentViewerDefaults.getLineSpacing(), 0); + CommunicationArtifactViewerHelper.addMessageRow(this, m_gridBagLayout, messageInsets, m_constraints, Bundle.ContactArtifactViewer_cr_disabled_message()); m_constraints.gridy++; } @@ -505,7 +506,7 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac m_constraints.gridx = 0; m_constraints.weighty = 0.0; m_constraints.weightx = 0.0; // keep components fixed horizontally. - m_constraints.insets = new java.awt.Insets(0, CommunicationArtifactViewerHelper.LEFT_INSET, 0, 0); + m_constraints.insets = new java.awt.Insets(0, ContentViewerDefaults.getSectionIndent(), 0, 0); m_constraints.fill = GridBagConstraints.NONE; } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CommunicationArtifactViewerHelper.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CommunicationArtifactViewerHelper.java index fe5e19aff5..11a5a8df96 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CommunicationArtifactViewerHelper.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CommunicationArtifactViewerHelper.java @@ -19,7 +19,6 @@ package org.sleuthkit.autopsy.contentviewers.artifactviewers; import java.awt.Dimension; -import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; @@ -38,6 +37,7 @@ import javax.swing.JTextPane; import javax.swing.SwingUtilities; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerDefaults; /** * @@ -49,8 +49,6 @@ final class CommunicationArtifactViewerHelper { // Number of columns in the gridbag layout. private final static int MAX_COLS = 4; - final static int LEFT_INSET = 12; - /** * Empty private constructor */ @@ -75,23 +73,23 @@ final class CommunicationArtifactViewerHelper { // create label for heading javax.swing.JLabel headingLabel = new javax.swing.JLabel(); - // add a blank line before the start of new section, unless it's - // the first section - if (constraints.gridy != 0) { - addBlankLine(panel, gridbagLayout, constraints); - } + constraints.gridy++; constraints.gridx = 0; // let the header span all of the row constraints.gridwidth = MAX_COLS; - constraints.insets = new Insets(0, 0, 0, 0); // No inset for header + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.fill = GridBagConstraints.NONE; + + int sectionSpacing = (constraints.gridy == 0) ? 0 : ContentViewerDefaults.getSectionSpacing(); + constraints.insets = new Insets(sectionSpacing, 0, ContentViewerDefaults.getLineSpacing(), 0); // set text headingLabel.setText(headerString); // make it large and bold - headingLabel.setFont(headingLabel.getFont().deriveFont(Font.BOLD, headingLabel.getFont().getSize() + 2)); + headingLabel.setFont(ContentViewerDefaults.getHeaderFont()); // add to panel gridbagLayout.setConstraints(headingLabel, constraints); @@ -197,24 +195,6 @@ final class CommunicationArtifactViewerHelper { constraints.fill = savedFill; } - /** - * Adds a blank line to the panel. - * - * @param panel Panel to update. - * @param gridbagLayout Layout to use. - * @param constraints Constraints to use. - */ - static void addBlankLine(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints) { - constraints.gridy++; - constraints.gridx = 0; - - javax.swing.JLabel filler = new javax.swing.JLabel(" "); - gridbagLayout.setConstraints(filler, constraints); - panel.add(filler); - - addLineEndGlue(panel, gridbagLayout, constraints); - } - /** * Adds a label/key to the panel at col 0. * @@ -226,7 +206,7 @@ final class CommunicationArtifactViewerHelper { * @return Label added. */ static JLabel addKey(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String keyString) { - return addKeyAtCol(panel, gridbagLayout, constraints, keyString, 0); + return addKeyAtCol(panel, gridbagLayout, constraints, null, keyString, 0); } /** @@ -235,19 +215,24 @@ final class CommunicationArtifactViewerHelper { * @param panel Panel to update. * @param gridbagLayout Layout to use. * @param constraints Constraints to use. + * @param insets Insets to be used. If null, default insets are assumed. * @param keyString Key name to display. * @param gridx column index, must be less than MAX_COLS - 1. * * @return Label added. */ - static JLabel addKeyAtCol(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String keyString, int gridx) { + static JLabel addKeyAtCol(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, Insets insets, String keyString, int gridx) { // create label javax.swing.JLabel keyLabel = new javax.swing.JLabel(); constraints.gridy++; constraints.gridx = gridx < MAX_COLS - 1 ? gridx : MAX_COLS - 2; - + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.insets = (insets == null) + ? new Insets(0, ContentViewerDefaults.getSectionIndent(), ContentViewerDefaults.getLineSpacing(), 0) + : insets; + // set text keyLabel.setText(keyString + ": "); @@ -295,7 +280,8 @@ final class CommunicationArtifactViewerHelper { // let the value span 2 cols cloneConstraints.gridwidth = 2; - cloneConstraints.fill = GridBagConstraints.BOTH; + cloneConstraints.fill = GridBagConstraints.HORIZONTAL; + cloneConstraints.insets = new Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getLineSpacing(), 0); // set text valueField.setText(valueString); @@ -325,13 +311,13 @@ final class CommunicationArtifactViewerHelper { * @param panel Panel to show. * @param gridbagLayout Layout to use. * @param constraints Constraints to use. - * + * @param insets The insets to be used for the grid bag layout constraints. If null, default insets are assumed. * @param messageString Message to display. * * @return Label for message added. */ - static JLabel addMessageRow(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String messageString) { - return addMessageRow(panel, gridbagLayout, constraints, messageString, 0); + static JLabel addMessageRow(JPanel panel, GridBagLayout gridbagLayout, Insets insets, GridBagConstraints constraints, String messageString) { + return addMessageRow(panel, gridbagLayout, constraints, insets, messageString, 0); } /** @@ -340,26 +326,32 @@ final class CommunicationArtifactViewerHelper { * * @param panel Panel to show. * @param gridbagLayout Layout to use. + * @param insets The insets to be used for the grid bag layout constraints. * @param constraints Constraints to use. - * + * @param insets The insets to be used for the grid bag layout constraints. If null, default insets are assumed. * @param messageString Message to display. + * @param gridx The grid x location to use. * * @return Label for message added. */ - static JLabel addMessageRow(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String messageString, int gridx) { + static JLabel addMessageRow(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, Insets insets, String messageString, int gridx) { // create label javax.swing.JLabel messageLabel = new javax.swing.JLabel(); constraints.gridy++; constraints.gridx = gridx < MAX_COLS - 1 ? gridx : MAX_COLS - 2; - + constraints.insets = insets == null + ? new Insets(0, 0, ContentViewerDefaults.getLineSpacing(), 0) : + insets; + int savedGridwidth = constraints.gridwidth; constraints.gridwidth = 3; // set text messageLabel.setText(messageString); + messageLabel.setFont(ContentViewerDefaults.getMessageFont()); // add to panel gridbagLayout.setConstraints(messageLabel, constraints); @@ -406,7 +398,7 @@ final class CommunicationArtifactViewerHelper { Insets savedInsets = constraints.insets; // extra Indent in - constraints.insets = new java.awt.Insets(0, 2 * LEFT_INSET, 0, 0); + constraints.insets = new java.awt.Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getLineSpacing(), 0); // create label javax.swing.JLabel personaLabel = new javax.swing.JLabel(); @@ -422,7 +414,7 @@ final class CommunicationArtifactViewerHelper { panel.add(personaLabel); // restore constraint - constraints.insets = savedInsets; + constraints.insets = new Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getColumnSpacing(), 0); constraints.gridx++; @@ -469,7 +461,7 @@ final class CommunicationArtifactViewerHelper { GridBagConstraints indentedConstraints = (GridBagConstraints) constraints.clone(); // Add an indent to match persona labels - indentedConstraints.insets = new java.awt.Insets(0, 2 * LEFT_INSET, 0, 0); + indentedConstraints.insets = new java.awt.Insets(0, 2 * ContentViewerDefaults.getSectionIndent(), ContentViewerDefaults.getLineSpacing(), 0); String contactInfo = Bundle.CommunicationArtifactViewerHelper_contact_label(contactId != null && !contactId.isEmpty() ? contactId : Bundle.CommunicationArtifactViewerHelper_contact_label_unknown()); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java index b17263a26d..66e669c919 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java @@ -57,6 +57,7 @@ import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsDialog; import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsDialogCallback; import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsMode; import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsPanel; +import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerDefaults; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Account; @@ -245,7 +246,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac Insets savedInsets = contactPanelConstraints.insets; contactPanelConstraints.gridy = 0; contactPanelConstraints.gridx = 0; - contactPanelConstraints.insets = new Insets(0, 0, 0, 0); + contactPanelConstraints.insets = new Insets(0, 0, ContentViewerDefaults.getLineSpacing(), 0); javax.swing.JLabel contactImage = new javax.swing.JLabel(); contactImage.setIcon(getImageFromArtifact(contactArtifact)); @@ -346,7 +347,8 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac this.personaSearchStatusLabel = new javax.swing.JLabel(); personaSearchStatusLabel.setText(personaStatusLabelText); - + personaSearchStatusLabel.setFont(ContentViewerDefaults.getMessageFont()); + m_constraints.gridx = 0; CommunicationArtifactViewerHelper.addComponent(this, m_gridBagLayout, m_constraints, personaSearchStatusLabel); @@ -359,9 +361,8 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac personaHeader.setEnabled(false); personaSearchStatusLabel.setEnabled(false); - CommunicationArtifactViewerHelper.addBlankLine(this, m_gridBagLayout, m_constraints); - m_constraints.gridy++; - CommunicationArtifactViewerHelper.addMessageRow(this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_cr_disabled_message()); + Insets messageInsets = new Insets(ContentViewerDefaults.getSectionSpacing(), 0, ContentViewerDefaults.getLineSpacing(), 0); + CommunicationArtifactViewerHelper.addMessageRow(this, m_gridBagLayout, messageInsets, m_constraints, Bundle.ContactArtifactViewer_cr_disabled_message()); m_constraints.gridy++; CommunicationArtifactViewerHelper.addPageEndGlue(this, m_gridBagLayout, this.m_constraints); @@ -436,7 +437,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac Insets savedInsets = constraints.insets; // some label are indented 2x to appear indented w.r.t column above - Insets extraIndentInsets = new java.awt.Insets(0, 2 * CommunicationArtifactViewerHelper.LEFT_INSET, 0, 0); + Insets extraIndentInsets = new java.awt.Insets(0, 2 * ContentViewerDefaults.getSectionIndent(), ContentViewerDefaults.getLineSpacing(), 0); // Add a Match X label in col 0. constraints.gridx = 0; @@ -461,6 +462,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac //constraints.gridwidth = 1; // TBD: this may not be needed if we use single panel constraints.gridx++; + constraints.insets = new Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getLineSpacing(), 0); personaNameLabel.setText(personaName); gridBagLayout.setConstraints(personaNameLabel, constraints); CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, personaNameLabel); @@ -474,6 +476,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac // Shirnk the button height. personaButton.setMargin(new Insets(0, 5, 0, 5)); + constraints.insets = new Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getLineSpacing(), 0); gridBagLayout.setConstraints(personaButton, constraints); CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, personaButton); CommunicationArtifactViewerHelper.addLineEndGlue(this, gridBagLayout, constraints); @@ -502,7 +505,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac // this needs an extra indent constraints.insets = extraIndentInsets; - CommunicationArtifactViewerHelper.addKeyAtCol(this, gridBagLayout, constraints, Bundle.ContactArtifactViewer_missing_account_label(), 1); + CommunicationArtifactViewerHelper.addKeyAtCol(this, gridBagLayout, constraints, extraIndentInsets, Bundle.ContactArtifactViewer_missing_account_label(), 1); constraints.insets = savedInsets; CommunicationArtifactViewerHelper.addValueAtCol(this, gridBagLayout, constraints, missingAccount.getIdentifier(), 2); @@ -549,7 +552,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac m_constraints.gridx = 0; m_constraints.weighty = 0.0; m_constraints.weightx = 0.0; // keep components fixed horizontally. - m_constraints.insets = new java.awt.Insets(0, CommunicationArtifactViewerHelper.LEFT_INSET, 0, 0); + m_constraints.insets = new java.awt.Insets(0, ContentViewerDefaults.getSectionIndent(), 0, 0); m_constraints.fill = GridBagConstraints.NONE; } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java index fc9f7c038c..6c267892f9 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java @@ -36,6 +36,8 @@ public class ContentViewerDefaults { return defaultFont.deriveFont(Font.BOLD, defaultFont.getSize() + 2); }); + private static final Supplier MESSAGE_FONT = Suppliers.memoize(() -> DEFAULT_FONT.get().deriveFont(Font.ITALIC)); + private static final Supplier DEFAULT_PANEL_INSETS = Suppliers.memoize(() -> UIManager.getDefaults().getInsets("TextPane.margin")); private static final Supplier DEFAULT_INDENT = Suppliers.memoize(() -> DEFAULT_FONT_PX.get()); @@ -54,6 +56,10 @@ public class ContentViewerDefaults { return DEFAULT_FONT.get(); } + public static Font getMessageFont() { + return MESSAGE_FONT.get(); + } + public static Font getHeaderFont() { return HEADER_FONT.get(); } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java index 0aa5ba98d3..6ef8535ce9 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java @@ -31,13 +31,14 @@ public class ContentViewerHtmlStyles { private static final String KEY_COLUMN_TD_CLASSNAME = CLASS_PREFIX + "keyKolumn"; private static final Font DEFAULT_FONT = ContentViewerDefaults.getFont(); + private static final Font MESSAGE_FONT = ContentViewerDefaults.getMessageFont(); private static final Font HEADER_FONT = ContentViewerDefaults.getHeaderFont(); private static final Font SUB_HEADER_FONT = ContentViewerDefaults.getSubHeaderFont(); // additional styling for components private static final String STYLE_SHEET_RULE = String.format(" .%s { font-family: %s; font-size: %dpt;font-style:italic; margin: 0px; padding: 0px 0px %dpx 0px; } ", - MESSAGE_CLASSNAME, DEFAULT_FONT.getFamily(), DEFAULT_FONT.getSize(), ContentViewerDefaults.getLineSpacing()) + MESSAGE_CLASSNAME, MESSAGE_FONT.getFamily(), MESSAGE_FONT.getSize(), ContentViewerDefaults.getLineSpacing()) + String.format(" .%s { font-family: %s; font-size: %dpt; font-weight: bold; margin: 0px; padding: 0px 0px %dpx 0px; } ", HEADER_CLASSNAME, HEADER_FONT.getFamily(), HEADER_FONT.getSize(), ContentViewerDefaults.getLineSpacing()) + String.format(" .%s { font-family: %s; font-size: %dpt; font-weight: bold; margin: 0px; padding: 0px 0px %dpx 0px; } ", From d2347ffa17751395155563ab55b45da2fb1ffe78 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 7 Jun 2021 14:12:50 -0400 Subject: [PATCH 11/33] call log and contact artifact viewer --- .../CallLogArtifactViewer.java | 11 ++-- .../CommunicationArtifactViewerHelper.java | 50 ++++++++++--------- .../ContactArtifactViewer.java | 36 +++++++------ 3 files changed, 53 insertions(+), 44 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java index bcea405c14..4b83bdc565 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java @@ -31,6 +31,7 @@ import java.util.Map; import java.util.Set; import java.util.logging.Level; import javax.swing.JScrollPane; +import javax.swing.border.EmptyBorder; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle; @@ -77,6 +78,7 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac */ public CallLogArtifactViewer() { initComponents(); + this.setBorder(new EmptyBorder(ContentViewerDefaults.getPanelInsets())); } /** @@ -116,6 +118,7 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac currentAccountFetcher = null; } } + // repaint this.revalidate(); } @@ -311,7 +314,7 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac }) private List updateView(CallLogViewData callLogViewData) { - CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_heading_parties()); + CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, 0, Bundle.CallLogArtifactViewer_heading_parties()); List dataList = new ArrayList<>(); // Display "From" if we have non-local device accounts @@ -386,7 +389,7 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac }) private void updateMetadataView(CallLogViewData callLogViewData) { - CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_heading_metadata()); + CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, ContentViewerDefaults.getSectionSpacing(), Bundle.CallLogArtifactViewer_heading_metadata()); CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_label_direction()); if (callLogViewData.getDirection() != null) { @@ -416,7 +419,7 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac "CallLogArtifactViewer_heading_Source=Source", "CallLogArtifactViewer_label_datasource=Data Source",}) private void updateSourceView(CallLogViewData callLogViewData) { - CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_heading_Source()); + CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, ContentViewerDefaults.getSectionSpacing(), Bundle.CallLogArtifactViewer_heading_Source()); CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_label_datasource()); CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, callLogViewData.getDataSourceName()); } @@ -434,7 +437,7 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac if (callLogViewData.getOtherAttributes().isEmpty()) { return; } - CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_heading_others()); + CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, ContentViewerDefaults.getSectionSpacing(), Bundle.CallLogArtifactViewer_heading_others()); for (Map.Entry entry : callLogViewData.getOtherAttributes().entrySet()) { CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, entry.getKey()); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CommunicationArtifactViewerHelper.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CommunicationArtifactViewerHelper.java index 11a5a8df96..3f58c723c5 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CommunicationArtifactViewerHelper.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CommunicationArtifactViewerHelper.java @@ -62,11 +62,12 @@ final class CommunicationArtifactViewerHelper { * @param panel Panel to update. * @param gridbagLayout Layout to use. * @param constraints Constraints to use. + * @param spacing Spacing to add to top insets (in pixels). * @param headerString Heading string to display. * * @return JLabel Heading label added. */ - static JLabel addHeader(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String headerString) { + static JLabel addHeader(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, int topSpacing, String headerString) { Insets savedInsets = constraints.insets; @@ -79,14 +80,13 @@ final class CommunicationArtifactViewerHelper { // let the header span all of the row constraints.gridwidth = MAX_COLS; - constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.anchor = GridBagConstraints.LINE_START; constraints.fill = GridBagConstraints.NONE; - int sectionSpacing = (constraints.gridy == 0) ? 0 : ContentViewerDefaults.getSectionSpacing(); - constraints.insets = new Insets(sectionSpacing, 0, ContentViewerDefaults.getLineSpacing(), 0); + constraints.insets = new Insets(topSpacing, 0, ContentViewerDefaults.getLineSpacing(), 0); // set text - headingLabel.setText(headerString); + headingLabel.setText(headerString.trim()); // make it large and bold headingLabel.setFont(ContentViewerDefaults.getHeaderFont()); @@ -157,7 +157,7 @@ final class CommunicationArtifactViewerHelper { int savedFill = constraints.fill; constraints.weightx = 1.0; // take up all the horizontal space - constraints.fill = GridBagConstraints.BOTH; + constraints.fill = GridBagConstraints.HORIZONTAL; javax.swing.Box.Filler horizontalFiller = new javax.swing.Box.Filler(new Dimension(0, 0), new Dimension(0, 0), new Dimension(32767, 0)); gridbagLayout.setConstraints(horizontalFiller, constraints); @@ -179,6 +179,7 @@ final class CommunicationArtifactViewerHelper { static void addPageEndGlue(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints) { constraints.gridx = 0; + constraints.gridy++; double savedWeighty = constraints.weighty; int savedFill = constraints.fill; @@ -206,7 +207,7 @@ final class CommunicationArtifactViewerHelper { * @return Label added. */ static JLabel addKey(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String keyString) { - return addKeyAtCol(panel, gridbagLayout, constraints, null, keyString, 0); + return addKeyAtCol(panel, gridbagLayout, constraints, keyString, 0); } /** @@ -215,26 +216,24 @@ final class CommunicationArtifactViewerHelper { * @param panel Panel to update. * @param gridbagLayout Layout to use. * @param constraints Constraints to use. - * @param insets Insets to be used. If null, default insets are assumed. * @param keyString Key name to display. * @param gridx column index, must be less than MAX_COLS - 1. * * @return Label added. */ - static JLabel addKeyAtCol(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, Insets insets, String keyString, int gridx) { + static JLabel addKeyAtCol(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String keyString, int gridx) { // create label javax.swing.JLabel keyLabel = new javax.swing.JLabel(); constraints.gridy++; constraints.gridx = gridx < MAX_COLS - 1 ? gridx : MAX_COLS - 2; - constraints.anchor = GridBagConstraints.NORTHWEST; - constraints.insets = (insets == null) - ? new Insets(0, ContentViewerDefaults.getSectionIndent(), ContentViewerDefaults.getLineSpacing(), 0) - : insets; - + constraints.anchor = GridBagConstraints.LINE_START; + constraints.insets = new Insets(0, ContentViewerDefaults.getSectionIndent(), ContentViewerDefaults.getLineSpacing(), 0); + // set text - keyLabel.setText(keyString + ": "); + String preppedKeyString = keyString == null ? null : keyString.trim() + ":"; + keyLabel.setText(preppedKeyString); // add to panel gridbagLayout.setConstraints(keyLabel, constraints); @@ -273,6 +272,7 @@ final class CommunicationArtifactViewerHelper { JTextPane valueField = new JTextPane(); valueField.setEditable(false); valueField.setOpaque(false); + valueField.setMargin(new Insets(0,0,0,0)); constraints.gridx = gridx < MAX_COLS ? gridx : MAX_COLS - 1; @@ -280,7 +280,7 @@ final class CommunicationArtifactViewerHelper { // let the value span 2 cols cloneConstraints.gridwidth = 2; - cloneConstraints.fill = GridBagConstraints.HORIZONTAL; + constraints.anchor = GridBagConstraints.LINE_START; cloneConstraints.insets = new Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getLineSpacing(), 0); // set text @@ -344,13 +344,14 @@ final class CommunicationArtifactViewerHelper { constraints.insets = insets == null ? new Insets(0, 0, ContentViewerDefaults.getLineSpacing(), 0) : insets; + constraints.anchor = GridBagConstraints.LINE_START; int savedGridwidth = constraints.gridwidth; constraints.gridwidth = 3; // set text - messageLabel.setText(messageString); + messageLabel.setText(messageString == null ? null : messageString.trim()); messageLabel.setFont(ContentViewerDefaults.getMessageFont()); // add to panel @@ -399,7 +400,8 @@ final class CommunicationArtifactViewerHelper { // extra Indent in constraints.insets = new java.awt.Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getLineSpacing(), 0); - + constraints.anchor = GridBagConstraints.LINE_START; + // create label javax.swing.JLabel personaLabel = new javax.swing.JLabel(); String personaLabelText = Bundle.CommunicationArtifactViewerHelper_persona_label(); @@ -407,15 +409,12 @@ final class CommunicationArtifactViewerHelper { ? Bundle.CommunicationArtifactViewerHelper_persona_searching() : Bundle.CommunicationArtifactViewerHelper_persona_unknown()); - personaLabel.setText(personaLabelText); - + personaLabel.setText(personaLabelText == null ? null : personaLabelText.trim()); + // add to panel gridbagLayout.setConstraints(personaLabel, constraints); panel.add(personaLabel); - // restore constraint - constraints.insets = new Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getColumnSpacing(), 0); - constraints.gridx++; // Place a button as place holder. It will be enabled when persona is available. @@ -433,6 +432,9 @@ final class CommunicationArtifactViewerHelper { } else { personaLabel.setEnabled(false); } + + // restore constraint + constraints.insets = savedInsets; addLineEndGlue(panel, gridbagLayout, constraints); @@ -461,7 +463,7 @@ final class CommunicationArtifactViewerHelper { GridBagConstraints indentedConstraints = (GridBagConstraints) constraints.clone(); // Add an indent to match persona labels - indentedConstraints.insets = new java.awt.Insets(0, 2 * ContentViewerDefaults.getSectionIndent(), ContentViewerDefaults.getLineSpacing(), 0); + indentedConstraints.insets = new java.awt.Insets(0, ContentViewerDefaults.getSectionIndent(), ContentViewerDefaults.getLineSpacing(), 0); String contactInfo = Bundle.CommunicationArtifactViewerHelper_contact_label(contactId != null && !contactId.isEmpty() ? contactId : Bundle.CommunicationArtifactViewerHelper_contact_label_unknown()); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java index 66e669c919..06e4a37d87 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java @@ -41,9 +41,9 @@ import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JLabel; -import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.SwingWorker; +import javax.swing.border.EmptyBorder; import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; @@ -108,7 +108,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac */ public ContactArtifactViewer() { initComponents(); - + this.setBorder(new EmptyBorder(ContentViewerDefaults.getPanelInsets())); defaultImage = new ImageIcon(ContactArtifactViewer.class.getResource(DEFAULT_IMAGE_PATH)); } @@ -247,7 +247,10 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac contactPanelConstraints.gridy = 0; contactPanelConstraints.gridx = 0; contactPanelConstraints.insets = new Insets(0, 0, ContentViewerDefaults.getLineSpacing(), 0); - + int prevGridWidth = contactPanelConstraints.gridwidth; + contactPanelConstraints.gridwidth = 3; + contactPanelConstraints.anchor = GridBagConstraints.LINE_START; + javax.swing.JLabel contactImage = new javax.swing.JLabel(); contactImage.setIcon(getImageFromArtifact(contactArtifact)); contactImage.setText(Bundle.ContactArtifactViewer_contactImage_text()); @@ -257,6 +260,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac CommunicationArtifactViewerHelper.addLineEndGlue(this, contactPanelLayout, contactPanelConstraints); contactPanelConstraints.gridy++; + contactPanelConstraints.gridwidth = prevGridWidth; contactPanelConstraints.insets = savedInsets; } @@ -276,13 +280,13 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac if (StringUtils.isEmpty(bba.getValueString()) == false) { contactName = bba.getDisplayString(); - CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, contactName); + CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, 0, contactName); foundName = true; break; } } if (foundName == false) { - CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, Bundle.ContactArtifactViewer_contactname_unknown()); + CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, ContentViewerDefaults.getSectionSpacing(), Bundle.ContactArtifactViewer_contactname_unknown()); } } @@ -303,7 +307,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac return; } - CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, sectionHeader); + CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, ContentViewerDefaults.getSectionSpacing(), sectionHeader); for (BlackboardAttribute bba : sectionAttributesList) { CommunicationArtifactViewerHelper.addKey(this, contactPanelLayout, contactPanelConstraints, bba.getAttributeType().getDisplayName()); CommunicationArtifactViewerHelper.addValue(this, contactPanelLayout, contactPanelConstraints, bba.getDisplayString()); @@ -317,7 +321,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac "ContactArtifactViewer_heading_Source=Source", "ContactArtifactViewer_label_datasource=Data Source",}) private void updateSource() { - CommunicationArtifactViewerHelper.addHeader(this, this.m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_heading_Source()); + CommunicationArtifactViewerHelper.addHeader(this, this.m_gridBagLayout, m_constraints, ContentViewerDefaults.getSectionSpacing(), Bundle.ContactArtifactViewer_heading_Source()); CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_label_datasource()); CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, m_constraints, datasourceName); } @@ -336,7 +340,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac private void initiatePersonasSearch() { // add a section header - JLabel personaHeader = CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_persona_header()); + JLabel personaHeader = CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, m_constraints, ContentViewerDefaults.getSectionSpacing(), Bundle.ContactArtifactViewer_persona_header()); m_constraints.gridy++; @@ -350,6 +354,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac personaSearchStatusLabel.setFont(ContentViewerDefaults.getMessageFont()); m_constraints.gridx = 0; + m_constraints.anchor = GridBagConstraints.LINE_START; CommunicationArtifactViewerHelper.addComponent(this, m_gridBagLayout, m_constraints, personaSearchStatusLabel); @@ -436,12 +441,9 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac // save the original insets Insets savedInsets = constraints.insets; - // some label are indented 2x to appear indented w.r.t column above - Insets extraIndentInsets = new java.awt.Insets(0, 2 * ContentViewerDefaults.getSectionIndent(), ContentViewerDefaults.getLineSpacing(), 0); - // Add a Match X label in col 0. constraints.gridx = 0; - javax.swing.JLabel matchNumberLabel = CommunicationArtifactViewerHelper.addKey(this, gridBagLayout, constraints, String.format("%s %d", Bundle.ContactArtifactViewer_persona_match_num(), matchNumber)); + javax.swing.JLabel matchNumberLabel = CommunicationArtifactViewerHelper.addKey(this, gridBagLayout, constraints, String.format("%s %d", Bundle.ContactArtifactViewer_persona_match_num(), matchNumber).trim()); javax.swing.JLabel personaNameLabel = new javax.swing.JLabel(); javax.swing.JButton personaButton = new javax.swing.JButton(); @@ -463,6 +465,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac //constraints.gridwidth = 1; // TBD: this may not be needed if we use single panel constraints.gridx++; constraints.insets = new Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getLineSpacing(), 0); + constraints.anchor = GridBagConstraints.LINE_START; personaNameLabel.setText(personaName); gridBagLayout.setConstraints(personaNameLabel, constraints); CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, personaNameLabel); @@ -477,6 +480,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac // Shirnk the button height. personaButton.setMargin(new Insets(0, 5, 0, 5)); constraints.insets = new Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getLineSpacing(), 0); + constraints.anchor = GridBagConstraints.LINE_START; gridBagLayout.setConstraints(personaButton, constraints); CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, personaButton); CommunicationArtifactViewerHelper.addLineEndGlue(this, gridBagLayout, constraints); @@ -491,7 +495,8 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac //constraints.insets = labelInsets; javax.swing.JLabel accountsStatus = new javax.swing.JLabel(Bundle.ContactArtifactViewer_found_all_accounts_label()); - constraints.insets = extraIndentInsets; + constraints.insets = new Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getLineSpacing(), 0); + constraints.anchor = GridBagConstraints.LINE_START; CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, accountsStatus); constraints.insets = savedInsets; @@ -504,8 +509,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac constraints.gridy++; // this needs an extra indent - constraints.insets = extraIndentInsets; - CommunicationArtifactViewerHelper.addKeyAtCol(this, gridBagLayout, constraints, extraIndentInsets, Bundle.ContactArtifactViewer_missing_account_label(), 1); + CommunicationArtifactViewerHelper.addKeyAtCol(this, gridBagLayout, constraints, Bundle.ContactArtifactViewer_missing_account_label(), 1); constraints.insets = savedInsets; CommunicationArtifactViewerHelper.addValueAtCol(this, gridBagLayout, constraints, missingAccount.getIdentifier(), 2); @@ -547,7 +551,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac m_gridBagLayout = new GridBagLayout(); m_constraints = new GridBagConstraints(); - m_constraints.anchor = GridBagConstraints.FIRST_LINE_START; + m_constraints.anchor = GridBagConstraints.LINE_START; m_constraints.gridy = 0; m_constraints.gridx = 0; m_constraints.weighty = 0.0; From 21961f3d32902da26c0346a9c4621ab271db1953 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 7 Jun 2021 15:58:19 -0400 Subject: [PATCH 12/33] message account panel changes --- .../artifactviewers/MessageAccountPanel.java | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/MessageAccountPanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/MessageAccountPanel.java index fbf1ada856..fb2088c31a 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/MessageAccountPanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/MessageAccountPanel.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.contentviewers.artifactviewers; import java.awt.Dimension; +import java.awt.Insets; import java.awt.Toolkit; import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; @@ -44,6 +45,7 @@ import javax.swing.JTextPane; import javax.swing.LayoutStyle.ComponentPlacement; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; +import javax.swing.border.EmptyBorder; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; @@ -56,6 +58,7 @@ import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsDialog; import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsDialogCallback; import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsMode; import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsPanel; +import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerDefaults; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.guiutils.ContactCache; import org.sleuthkit.datamodel.Account; @@ -77,6 +80,15 @@ final class MessageAccountPanel extends JPanel { private AccountFetcher currentFetcher = null; + + + /** + * Main constructor. + */ + MessageAccountPanel() { + this.setBorder(new EmptyBorder(ContentViewerDefaults.getPanelInsets())); + } + /** * Set the new artifact for the panel. * @@ -170,9 +182,7 @@ final class MessageAccountPanel extends JPanel { layout.setHorizontalGroup( layout.createParallelGroup(Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(getMainHorizontalGroup(layout, dataList)) - .addContainerGap(158, Short.MAX_VALUE))); + .addGroup(getMainHorizontalGroup(layout, dataList)))); layout.setVerticalGroup(getMainVerticalGroup(layout, dataList)); setLayout(layout); @@ -186,6 +196,7 @@ final class MessageAccountPanel extends JPanel { messageLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); messageLabel.setText(Bundle.MessageAccountPanel_no_matches()); + messageLabel.setFont(ContentViewerDefaults.getMessageFont()); messageLabel.setEnabled(false); messagePanel.add(messageLabel, java.awt.BorderLayout.CENTER); @@ -224,14 +235,12 @@ final class MessageAccountPanel extends JPanel { private ParallelGroup getMainVerticalGroup(GroupLayout layout, List data) { SequentialGroup group = layout.createSequentialGroup(); for (AccountContainer o : data) { - group.addGap(5) - .addComponent(o.getAccountLabel()) + group.addComponent(o.getAccountLabel()) .addGroup(o.getContactLineVerticalGroup(layout)) .addGroup(o.getPersonLineVerticalGroup(layout)); + group.addGap(ContentViewerDefaults.getSectionSpacing()); } - group.addContainerGap(83, Short.MAX_VALUE); - return layout.createParallelGroup().addGroup(group); } @@ -259,12 +268,11 @@ final class MessageAccountPanel extends JPanel { private SequentialGroup getPersonaHorizontalGroup(GroupLayout layout, List data) { SequentialGroup group = layout.createSequentialGroup(); ParallelGroup pgroup = layout.createParallelGroup(Alignment.LEADING); - group.addGap(10); for (AccountContainer o : data) { pgroup.addGroup(o.getPersonaSequentialGroup(layout)); pgroup.addGroup(o.getContactSequentialGroup(layout)); } - group.addGap(10) + group.addGap(ContentViewerDefaults.getSectionIndent()) .addGroup(pgroup) .addPreferredGap(ComponentPlacement.RELATED) .addGroup(getButtonGroup(layout, data)); @@ -343,7 +351,9 @@ final class MessageAccountPanel extends JPanel { button = new JButton(); button.addActionListener(new PersonaButtonListener(this)); + accountLabel.setMargin(new Insets(0, 0, 0, 0)); accountLabel.setText(account.getTypeSpecificID()); + accountLabel.setFont(ContentViewerDefaults.getHeaderFont()); contactDisplayName.setText(contactName); personaDisplayName.setText(persona != null ? persona.getName() : Bundle.MessageAccountPanel_unknown_label()); From e402f792c084317c9eee5a97f697b06959bc9599 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 7 Jun 2021 16:33:27 -0400 Subject: [PATCH 13/33] fix for html components --- .../layout/ContentViewerDefaults.java | 8 ++++- .../layout/ContentViewerHtmlStyles.java | 32 +++++++++++-------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java index 6c267892f9..86d306d636 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java @@ -21,9 +21,11 @@ public class ContentViewerDefaults { private static final Supplier DEFAULT_FONT = Suppliers.memoize(() -> UIManager.getDefaults().getFont("Label.font")); + private static final Supplier PT_TO_PX = Suppliers.memoize(() -> Toolkit.getDefaultToolkit().getScreenResolution() / 72.0); + private static final Supplier DEFAULT_FONT_PX = Suppliers.memoize(() -> { // based on https://stackoverflow.com/questions/5829703/java-getting-a-font-with-a-specific-height-in-pixels/26564924#26564924 - return (int) Math.round(DEFAULT_FONT.get().getSize() * Toolkit.getDefaultToolkit().getScreenResolution() / 72.0); + return (int) Math.round(DEFAULT_FONT.get().getSize() * PT_TO_PX.get()); }); private static final Supplier SUB_HEADER_FONT = Suppliers.memoize(() -> { @@ -87,4 +89,8 @@ public class ContentViewerDefaults { public static Font getSubHeaderFont() { return SUB_HEADER_FONT.get(); } + + public static Double getPtToPx() { + return PT_TO_PX.get(); + } } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java index 6ef8535ce9..728fbfdadb 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java @@ -37,26 +37,30 @@ public class ContentViewerHtmlStyles { // additional styling for components private static final String STYLE_SHEET_RULE - = String.format(" .%s { font-family: %s; font-size: %dpt;font-style:italic; margin: 0px; padding: 0px 0px %dpx 0px; } ", - MESSAGE_CLASSNAME, MESSAGE_FONT.getFamily(), MESSAGE_FONT.getSize(), ContentViewerDefaults.getLineSpacing()) - + String.format(" .%s { font-family: %s; font-size: %dpt; font-weight: bold; margin: 0px; padding: 0px 0px %dpx 0px; } ", - HEADER_CLASSNAME, HEADER_FONT.getFamily(), HEADER_FONT.getSize(), ContentViewerDefaults.getLineSpacing()) - + String.format(" .%s { font-family: %s; font-size: %dpt; font-weight: bold; margin: 0px; padding: 0px 0px %dpx 0px; } ", - SUB_HEADER_CLASSNAME, SUB_HEADER_FONT.getFamily(), SUB_HEADER_FONT.getSize(), ContentViewerDefaults.getLineSpacing()) - + String.format(" .%s { font-family: %s; font-size: %dpt; margin: 0px; padding: 0px 0px %dpx 0px; } ", - TEXT_CLASSNAME, DEFAULT_FONT.getFamily(), DEFAULT_FONT.getSize(), ContentViewerDefaults.getLineSpacing()) - + String.format(" .%s { padding-left: %dpx } ", - INDENTED_CLASSNAME, ContentViewerDefaults.getSectionIndent()) - + String.format(" .%s { padding-top: %dpx } ", - SPACED_SECTION_CLASSNAME, ContentViewerDefaults.getSectionSpacing()) - + String.format(" .%s { padding-right: %dpx } ", - KEY_COLUMN_TD_CLASSNAME, ContentViewerDefaults.getColumnSpacing()); + = String.format(" .%s { font-family: %s; font-size: %dpt;font-style:italic; margin: 0px; padding: 0px 0px %dpt 0px; } ", + MESSAGE_CLASSNAME, MESSAGE_FONT.getFamily(), MESSAGE_FONT.getSize(), pxToPt(ContentViewerDefaults.getLineSpacing())) + + String.format(" .%s { font-family: %s; font-size: %dpt; font-weight: bold; margin: 0px; padding: 0px 0px %dpt 0px; } ", + HEADER_CLASSNAME, HEADER_FONT.getFamily(), HEADER_FONT.getSize(), pxToPt(ContentViewerDefaults.getLineSpacing())) + + String.format(" .%s { font-family: %s; font-size: %dpt; font-weight: bold; margin: 0px; padding: 0px 0px %dpt 0px; } ", + SUB_HEADER_CLASSNAME, SUB_HEADER_FONT.getFamily(), SUB_HEADER_FONT.getSize(), pxToPt(ContentViewerDefaults.getLineSpacing())) + + String.format(" .%s { font-family: %s; font-size: %dpt; margin: 0px; padding: 0px 0px %dpt 0px; } ", + TEXT_CLASSNAME, DEFAULT_FONT.getFamily(), DEFAULT_FONT.getSize(), pxToPt(ContentViewerDefaults.getLineSpacing())) + + String.format(" .%s { padding-left: %dpt } ", + INDENTED_CLASSNAME, pxToPt(ContentViewerDefaults.getSectionIndent())) + + String.format(" .%s { padding-top: %dpt } ", + SPACED_SECTION_CLASSNAME, pxToPt(ContentViewerDefaults.getSectionSpacing())) + + String.format(" .%s { padding-right: %dpt } ", + KEY_COLUMN_TD_CLASSNAME, pxToPt(ContentViewerDefaults.getColumnSpacing())); private static final Supplier STYLE_SHEET = Suppliers.memoize(() -> { StyleSheet stylesheet = new StyleSheet(); stylesheet.addRule(STYLE_SHEET_RULE); return stylesheet; }); + + private static int pxToPt(int px) { + return (int) Math.round(((double) px) / ContentViewerDefaults.getPtToPx()); + } public static String getHeaderClassName() { return HEADER_CLASSNAME; From 38b26df41ebaf3e1967f2fb8da22b10cb8ac13a3 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 8 Jun 2021 13:01:31 -0400 Subject: [PATCH 14/33] pane text --- .../autopsy/corecomponents/AutoWrappingJTextPane.java | 4 +++- .../autopsy/keywordsearch/ExtractedContentPanel.java | 10 ++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AutoWrappingJTextPane.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AutoWrappingJTextPane.java index 4ae8b6f771..94b3cc68ad 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AutoWrappingJTextPane.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AutoWrappingJTextPane.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.corecomponents; +import java.text.MessageFormat; import javax.swing.JTextPane; import javax.swing.SizeRequirements; import javax.swing.text.Element; @@ -27,6 +28,7 @@ import javax.swing.text.ViewFactory; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.InlineView; import javax.swing.text.html.ParagraphView; +import javax.swing.text.html.StyleSheet; import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerDefaults; import org.sleuthkit.autopsy.coreutils.EscapeUtil; @@ -106,6 +108,6 @@ public class AutoWrappingJTextPane extends JTextPane { String style = String.format("font-family: %s; font-size: %dpt; margin: 0px; padding: 0px 0px %dpx 0px;", ContentViewerDefaults.getFont().getFamily(), ContentViewerDefaults.getFont().getSize(), ContentViewerDefaults.getLineSpacing()); - super.setText("
" + EscapeUtil.escapeHtml(text) + "
"); + super.setText(MessageFormat.format("
{1}
", style, EscapeUtil.escapeHtml(text))); } } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentPanel.java index 8ff9c0fdcc..5d6d7689f2 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentPanel.java @@ -29,10 +29,10 @@ import java.util.List; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.logging.Level; -import javax.swing.JLabel; import javax.swing.SizeRequirements; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; +import javax.swing.UIManager; import javax.swing.text.Element; import javax.swing.text.View; import javax.swing.text.ViewFactory; @@ -59,7 +59,7 @@ class ExtractedContentPanel extends javax.swing.JPanel implements ResizableTextP private static final Logger logger = Logger.getLogger(ExtractedContentPanel.class.getName()); // set font as close as possible to default - private static final Font DEFAULT_FONT = new JLabel().getFont(); + private static final Font DEFAULT_FONT = UIManager.getDefaults().getFont("Label.font"); private static final long serialVersionUID = 1L; private String contentName; @@ -135,8 +135,9 @@ class ExtractedContentPanel extends javax.swing.JPanel implements ResizableTextP }; } }; - // get the style sheet for editing font size + // set new style sheet to clear default styles styleSheet = editorKit.getStyleSheet(); + setStyleSheetSize(styleSheet, DEFAULT_FONT.getSize()); sourceComboBox.addItemListener(itemEvent -> { if (itemEvent.getStateChange() == ItemEvent.SELECTED) { @@ -144,6 +145,7 @@ class ExtractedContentPanel extends javax.swing.JPanel implements ResizableTextP } }); extractedTextPane.setComponentPopupMenu(rightClickMenu); + copyMenuItem.addActionListener(actionEvent -> extractedTextPane.copy()); selectAllMenuItem.addActionListener(actionEvent -> extractedTextPane.selectAll()); @@ -160,7 +162,7 @@ class ExtractedContentPanel extends javax.swing.JPanel implements ResizableTextP private void setStyleSheetSize(StyleSheet styleSheet, int size) { - styleSheet.addRule("body {font-family:\"" + DEFAULT_FONT.getFamily() + "\"; font-size:" + size + "pt; } "); + styleSheet.addRule("body { font-family:\"" + DEFAULT_FONT.getFamily() + "\"; font-size:" + size + "pt; } "); } From e4f6bb53b32910898450aa7750a49a9837cd08c6 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 8 Jun 2021 13:50:32 -0400 Subject: [PATCH 15/33] context and metadata fixes --- .../sleuthkit/autopsy/contentviewers/Metadata.java | 12 +++++++----- .../analysisresults/AnalysisResultsContentPanel.java | 2 -- .../contentviewers/contextviewer/ContextViewer.form | 7 ++++++- .../contentviewers/contextviewer/ContextViewer.java | 7 +++++-- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java index 37edf6d5c0..488c96c4df 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.contentviewers; import java.awt.Component; import java.awt.Cursor; +import java.text.MessageFormat; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.logging.Level; @@ -133,11 +134,12 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer { } private void addRow(StringBuilder sb, String key, String value) { - sb.append(""); //NON-NLS - sb.append(key); - sb.append(""); //NON-NLS - sb.append(value); - sb.append(""); //NON-NLS + sb.append(MessageFormat.format("{1}{3}", + ContentViewerHtmlStyles.getTextClassName() + " " + ContentViewerHtmlStyles.getKeyColumnClassName(), + key, + ContentViewerHtmlStyles.getTextClassName(), + value + )); } @Messages({ diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java index aadfe4b677..fb56971f57 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.contentviewers.analysisresults; import java.text.MessageFormat; import java.util.List; import java.util.Optional; -import javax.swing.text.html.HTMLEditorKit; import org.apache.commons.lang3.tuple.Pair; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; @@ -29,7 +28,6 @@ import org.jsoup.nodes.Element; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.contentviewers.analysisresults.AnalysisResultsViewModel.NodeResults; import org.sleuthkit.autopsy.contentviewers.analysisresults.AnalysisResultsViewModel.ResultDisplayAttributes; -import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerDefaults; import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerHtmlStyles; import org.sleuthkit.datamodel.AnalysisResult; import org.sleuthkit.datamodel.Score; diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.form index bb1a78d555..47c452eccb 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.form @@ -81,7 +81,7 @@ - + @@ -110,6 +110,11 @@
+ + + + + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.java index dab7a657f9..74ac4919cb 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.java @@ -119,7 +119,9 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte jUnknownLabel.setBorder(new EmptyBorder(DATA_ROW_INSETS)); jUnknownPanel.add(jUnknownLabel); - setPreferredSize(new java.awt.Dimension(495, 358)); + setPreferredSize(new java.awt.Dimension(0, 0)); + + jScrollPane.setPreferredSize(new java.awt.Dimension(16, 16)); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -235,10 +237,11 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte } } javax.swing.JPanel contextContainer = new javax.swing.JPanel(); + contextContainer.setLayout(new BoxLayout(contextContainer, BoxLayout.Y_AXIS)); contextContainer.setBorder(new EmptyBorder(ContentViewerDefaults.getPanelInsets())); contextContainer.add(jSourcePanel); - contextContainer.setLayout(new BoxLayout(contextContainer, BoxLayout.Y_AXIS)); + if (contextSourcePanels.isEmpty()) { contextContainer.add(jUnknownPanel); } else { From 1ea0efd6ce3918361220cc7b6fcc3792162d97f8 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 8 Jun 2021 15:16:43 -0400 Subject: [PATCH 16/33] commenting --- .../AnnotationsContentViewer.java | 2 +- .../CallLogArtifactViewer.java | 2 +- .../CommunicationArtifactViewerHelper.java | 2 +- .../ContactArtifactViewer.java | 2 +- .../artifactviewers/MessageAccountPanel.java | 2 +- .../contextviewer/ContextSourcePanel.java | 2 +- .../contextviewer/ContextUsagePanel.java | 2 +- .../contextviewer/ContextViewer.java | 2 +- .../layout/ContentViewerDefaults.java | 176 ++++++++++++------ .../layout/ContentViewerHtmlStyles.java | 108 ++++++++--- .../corecomponents/AutoWrappingJTextPane.java | 2 +- .../keywordsearch/ExtractedContentPanel.java | 2 +- 12 files changed, 211 insertions(+), 93 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java index 3df51c9e48..7a20a7c2ce 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2018-2020 Basis Technology Corp. + * Copyright 2018-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java index 4b83bdc565..553c139c55 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CommunicationArtifactViewerHelper.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CommunicationArtifactViewerHelper.java index 3f58c723c5..6f7e4cff2f 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CommunicationArtifactViewerHelper.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CommunicationArtifactViewerHelper.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java index 06e4a37d87..b9ebee5c67 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/MessageAccountPanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/MessageAccountPanel.java index fb2088c31a..c2847223e6 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/MessageAccountPanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/MessageAccountPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextSourcePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextSourcePanel.java index 9ca74d06c1..0f7d2855bf 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextSourcePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextSourcePanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextUsagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextUsagePanel.java index 3eeb4b4442..c3c74da190 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextUsagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextUsagePanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.java index 74ac4919cb..eae47348d2 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java index 86d306d636..8f7b077233 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java @@ -1,96 +1,156 @@ /* - * 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. + * Autopsy Forensic Browser + * + * Copyright 2021 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.layout; -import com.google.common.base.Suppliers; import java.awt.Font; import java.awt.Insets; import java.awt.Toolkit; -import com.google.common.base.Supplier; import java.awt.Color; import javax.swing.UIManager; /** - * - * @author gregd + * Default values for layout of content values. */ public class ContentViewerDefaults { - private static final Supplier DEFAULT_FONT = Suppliers.memoize(() -> UIManager.getDefaults().getFont("Label.font")); + private static final Font DEFAULT_FONT = UIManager.getDefaults().getFont("Label.font"); - private static final Supplier PT_TO_PX = Suppliers.memoize(() -> Toolkit.getDefaultToolkit().getScreenResolution() / 72.0); - - private static final Supplier DEFAULT_FONT_PX = Suppliers.memoize(() -> { - // based on https://stackoverflow.com/questions/5829703/java-getting-a-font-with-a-specific-height-in-pixels/26564924#26564924 - return (int) Math.round(DEFAULT_FONT.get().getSize() * PT_TO_PX.get()); - }); - - private static final Supplier SUB_HEADER_FONT = Suppliers.memoize(() -> { - Font defaultFont = DEFAULT_FONT.get(); - return defaultFont.deriveFont(Font.BOLD); - }); + // based on https://stackoverflow.com/questions/5829703/java-getting-a-font-with-a-specific-height-in-pixels/26564924#26564924 + private static final Double PT_TO_PX = Toolkit.getDefaultToolkit().getScreenResolution() / 72.0; - private static final Supplier HEADER_FONT = Suppliers.memoize(() -> { - Font defaultFont = DEFAULT_FONT.get(); - return defaultFont.deriveFont(Font.BOLD, defaultFont.getSize() + 2); - }); + private static final int DEFAULT_FONT_PX = (int) Math.round(DEFAULT_FONT.getSize() * PT_TO_PX); - private static final Supplier MESSAGE_FONT = Suppliers.memoize(() -> DEFAULT_FONT.get().deriveFont(Font.ITALIC)); - - private static final Supplier DEFAULT_PANEL_INSETS = Suppliers.memoize(() -> UIManager.getDefaults().getInsets("TextPane.margin")); + private static final Font SUB_HEADER_FONT = DEFAULT_FONT.deriveFont(Font.BOLD); - private static final Supplier DEFAULT_INDENT = Suppliers.memoize(() -> DEFAULT_FONT_PX.get()); - private static final Supplier DEFAULT_SECTION_SPACING = Suppliers.memoize(() -> DEFAULT_FONT_PX.get()); + private static final Font HEADER_FONT = DEFAULT_FONT.deriveFont(Font.BOLD, DEFAULT_FONT.getSize() + 2); - private static final Supplier DEFAULT_COLUMN_SPACING = Suppliers.memoize(() -> (DEFAULT_FONT_PX.get() / 3)); - private static final Supplier DEFAULT_LINE_SPACING = Suppliers.memoize(() -> (DEFAULT_FONT_PX.get() / 5)); + private static final Font MESSAGE_FONT = DEFAULT_FONT.deriveFont(Font.ITALIC); - private static final Supplier DEFAULT_BACKGROUND = Suppliers.memoize(() -> UIManager.getColor("Panel.background")); + private static final Insets DEFAULT_PANEL_INSETS = UIManager.getDefaults().getInsets("TextPane.margin"); + private static final int DEFAULT_INDENT = DEFAULT_FONT_PX; + private static final int DEFAULT_SECTION_SPACING = DEFAULT_FONT_PX; + + private static final int DEFAULT_COLUMN_SPACING = (int) Math.round((double) DEFAULT_FONT_PX / 3); + + private static final int DEFAULT_LINE_SPACING = (int) Math.round((double) DEFAULT_FONT_PX / 5); + + private static final Color DEFAULT_BACKGROUND = UIManager.getColor("Panel.background"); + + /** + * Returns the horizontal spacing between columns in a table in pixels. + * + * @return The horizontal spacing between columns in a table in pixels. + */ public static int getColumnSpacing() { - return DEFAULT_COLUMN_SPACING.get(); + return DEFAULT_COLUMN_SPACING; } + /** + * Returns the default font to be used. + * + * @return the default font to be used. + */ public static Font getFont() { - return DEFAULT_FONT.get(); + return DEFAULT_FONT; } + /** + * Returns the font to be displayed for messages. + * + * @return The font to be displayed for messages. + */ public static Font getMessageFont() { - return MESSAGE_FONT.get(); + return MESSAGE_FONT; } + /** + * Returns the font to be displayed for messages. + * + * @return The font to be displayed for messages. + */ public static Font getHeaderFont() { - return HEADER_FONT.get(); + return HEADER_FONT; } - public static Insets getPanelInsets() { - return DEFAULT_PANEL_INSETS.get(); - } - - public static Integer getSectionIndent() { - return DEFAULT_INDENT.get(); - } - - public static Integer getSectionSpacing() { - return DEFAULT_SECTION_SPACING.get(); - } - - public static Integer getLineSpacing() { - return DEFAULT_LINE_SPACING.get(); - } - - public static Color getPanelBackground() { - return DEFAULT_BACKGROUND.get(); - } - + /** + * Returns the font to be displayed for sub headers. + * + * @return The font to be displayed for sub headers. + */ public static Font getSubHeaderFont() { - return SUB_HEADER_FONT.get(); + return SUB_HEADER_FONT; } - + + /** + * Returns the insets of the content within the parent content viewer panel. + * + * @return The insets of the content within the parent content viewer panel. + */ + public static Insets getPanelInsets() { + return DEFAULT_PANEL_INSETS; + } + + /** + * Returns the size in pixels that sections should be indented. + * + * @return The size in pixels that sections should be indented. + */ + public static Integer getSectionIndent() { + return DEFAULT_INDENT; + } + + /** + * Returns the spacing between sections in pixels. + * + * @return The spacing between sections in pixels. + */ + public static Integer getSectionSpacing() { + return DEFAULT_SECTION_SPACING; + } + + /** + * Returns the spacing between lines of text in pixels. + * + * @return The spacing between lines of text in pixels. + */ + public static Integer getLineSpacing() { + return DEFAULT_LINE_SPACING; + } + + /** + * Returns the color to be used as the background of the panel. + * + * @return The color to be used as the background of the panel. + */ + public static Color getPanelBackground() { + return DEFAULT_BACKGROUND; + } + + /** + * Returns the ratio of point size to pixel size for the user's screen + * resolution. + * + * @return The ratio of point size to pixel size for the user's screen + * resolution. + */ public static Double getPtToPx() { - return PT_TO_PX.get(); + return PT_TO_PX; } } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java index 728fbfdadb..fa1ae8ee0d 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java @@ -1,20 +1,31 @@ /* - * 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. + * Autopsy Forensic Browser + * + * Copyright 2021 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.layout; -import com.google.common.base.Supplier; -import com.google.common.base.Suppliers; import java.awt.Font; import javax.swing.JTextPane; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.StyleSheet; /** - * - * @author gregd + * The style sheet an class names to be used with content viewers using html + * rendering. */ public class ContentViewerHtmlStyles { @@ -52,57 +63,104 @@ public class ContentViewerHtmlStyles { + String.format(" .%s { padding-right: %dpt } ", KEY_COLUMN_TD_CLASSNAME, pxToPt(ContentViewerDefaults.getColumnSpacing())); - private static final Supplier STYLE_SHEET = Suppliers.memoize(() -> { - StyleSheet stylesheet = new StyleSheet(); - stylesheet.addRule(STYLE_SHEET_RULE); - return stylesheet; - }); - - private static int pxToPt(int px) { - return (int) Math.round(((double) px) / ContentViewerDefaults.getPtToPx()); + private static final StyleSheet STYLE_SHEET = new StyleSheet(); + + static { + // add the style rule to the style sheet. + STYLE_SHEET.addRule(STYLE_SHEET_RULE); } + /** + * Converts pixel size to point size. The html rendering seems more + * consistent with point size versus pixel size. + * + * @param px The pixel size. + * + * @return The point size. + */ + private static int pxToPt(int px) { + return (int) Math.round(((double) px) / ContentViewerDefaults.getPtToPx()); + } + + /** + * Returns the class name to use for header text. + * + * @return The class name to use for header text. + */ public static String getHeaderClassName() { return HEADER_CLASSNAME; } + /** + * Returns the class name to use for sub header text. + * + * @return The class name to use for sub header text. + */ public static String getSubHeaderClassName() { return SUB_HEADER_CLASSNAME; } - + + /** + * Returns the class name to use for message text. + * + * @return The class name to use for message text. + */ public static String getMessageClassName() { return MESSAGE_CLASSNAME; } + /** + * Returns the class name to use for regular text. + * + * @return The class name to use for regular text. + */ public static String getTextClassName() { return TEXT_CLASSNAME; } + /** + * Returns the class name to use for an indented (left padding) section. + * + * @return The class name to use for an indented (left padding) section. + */ public static String getIndentedClassName() { return INDENTED_CLASSNAME; } + /** + * Returns the class name to use for a section with spacing (top padding) + * section. + * + * @return The class name to use for a section with spacing (top padding) + * section. + */ public static String getSpacedSectionClassName() { return SPACED_SECTION_CLASSNAME; } + /** + * Returns the class name to use for a key column with right spacing (right + * padding). + * + * @return The class name to use for a key column with right spacing (right + * padding). + */ public static String getKeyColumnClassName() { return KEY_COLUMN_TD_CLASSNAME; } - public static String getStyleSheetRule() { - return STYLE_SHEET_RULE; - } - - public static StyleSheet getStyleSheet() { - return STYLE_SHEET.get(); - } - + /** + * Sets up a JTextPane for html rendering using the css class names + * specified in this class. + * + * @param textPane The JTextPane to set up for content viewer html + * rendering. + */ public static void setupHtmlJTextPane(JTextPane textPane) { textPane.setContentType("text/html;charset=UTF-8"); //NON-NLS HTMLEditorKit kit = new HTMLEditorKit(); textPane.setEditorKit(kit); - kit.setStyleSheet(ContentViewerHtmlStyles.getStyleSheet()); + kit.setStyleSheet(STYLE_SHEET); textPane.setMargin(ContentViewerDefaults.getPanelInsets()); textPane.setBackground(ContentViewerDefaults.getPanelBackground()); } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AutoWrappingJTextPane.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AutoWrappingJTextPane.java index 94b3cc68ad..652034dacc 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AutoWrappingJTextPane.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AutoWrappingJTextPane.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentPanel.java index 5d6d7689f2..0e716c8168 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2020 Basis Technology Corp. + * Copyright 2011-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); From 003d391ad376a8bf46a84e9ca789c2ec5c58cbb5 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 8 Jun 2021 17:02:32 -0400 Subject: [PATCH 17/33] Removed db calls from ImageNode createSheet --- .../sleuthkit/autopsy/datamodel/ImageNode.java | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java index ea0e2bb347..5df888052b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java @@ -20,8 +20,6 @@ package org.sleuthkit.autopsy.datamodel; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.sql.ResultSet; -import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; @@ -35,7 +33,6 @@ import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.DeleteDataSourceAction; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.datasourcesummary.ui.ViewSummaryInformationAction; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; @@ -48,7 +45,6 @@ import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Image; -import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.VirtualDirectory; import org.sleuthkit.autopsy.datamodel.BaseChildFactory.NoSuchEventBusException; @@ -171,17 +167,10 @@ public class ImageNode extends AbstractContentNode { Bundle.ImageNode_createSheet_timezone_desc(), this.content.getTimeZone())); - try (CaseDbQuery query = Case.getCurrentCaseThrows().getSleuthkitCase().executeQuery("SELECT device_id FROM data_source_info WHERE obj_id = " + this.content.getId());) { - ResultSet deviceIdSet = query.getResultSet(); - if (deviceIdSet.next()) { - sheetSet.put(new NodeProperty<>(Bundle.ImageNode_createSheet_deviceId_name(), + sheetSet.put(new NodeProperty<>(Bundle.ImageNode_createSheet_deviceId_name(), Bundle.ImageNode_createSheet_deviceId_displayName(), Bundle.ImageNode_createSheet_deviceId_desc(), - deviceIdSet.getString("device_id"))); - } - } catch (SQLException | TskCoreException | NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Failed to get device id for the following image: " + this.content.getId(), ex); - } + content.getDeviceId())); return sheet; } From 8d35b95c5f4126fd3bbbbd963d2d42073a89e0fa Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 8 Jun 2021 21:03:19 -0400 Subject: [PATCH 18/33] updated metadata viewer --- .../AnnotationsContentViewer.java | 1 + .../autopsy/contentviewers/Metadata.java | 119 ++++++++++++------ .../AnalysisResultsContentPanel.java | 40 +++--- .../layout/ContentViewerHtmlStyles.java | 10 ++ 4 files changed, 113 insertions(+), 57 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java index 7a20a7c2ce..aad1fe79a8 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java @@ -200,6 +200,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data try { String text = get(); + ContentViewerHtmlStyles.setStyles(textPanel); textPanel.setText(text); textPanel.setCaretPosition(0); } catch (InterruptedException | ExecutionException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java index 488c96c4df..72691afe64 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java @@ -21,9 +21,12 @@ package org.sleuthkit.autopsy.contentviewers; import java.awt.Component; import java.awt.Cursor; import java.text.MessageFormat; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.logging.Level; +import java.util.stream.Stream; import javax.swing.SwingWorker; import org.apache.commons.lang3.StringUtils; import org.openide.nodes.Node; @@ -65,6 +68,7 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer { public Metadata() { initComponents(); customizeComponents(); + ContentViewerHtmlStyles.setupHtmlJTextPane(jTextPane1); } /** @@ -118,31 +122,59 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer { * selectAllMenuItem.addActionListener(actList); */ - ContentViewerHtmlStyles.setupHtmlJTextPane(jTextPane1); } private void setText(String str) { - jTextPane1.setText("" + str + ""); //NON-NLS + ContentViewerHtmlStyles.setupHtmlJTextPane(jTextPane1); + jTextPane1.setText("" + str + ""); //NON-NLS + } + + private void addHeader(StringBuilder sb, String header, boolean spaced) { + sb.append(MessageFormat.format("

{2}

", + (spaced) ? ContentViewerHtmlStyles.getSpacedSectionClassName() : "", + ContentViewerHtmlStyles.getHeaderClassName(), + header)); } private void startTable(StringBuilder sb) { - sb.append(""); //NON-NLS + sb.append(MessageFormat.format("
", + ContentViewerHtmlStyles.getIndentedClassName())); //NON-NLS } private void endTable(StringBuilder sb) { - sb.append("
"); //NON-NLS + sb.append(""); //NON-NLS } private void addRow(StringBuilder sb, String key, String value) { - sb.append(MessageFormat.format("{1}{3}", - ContentViewerHtmlStyles.getTextClassName() + " " + ContentViewerHtmlStyles.getKeyColumnClassName(), - key, - ContentViewerHtmlStyles.getTextClassName(), - value - )); + sb.append(MessageFormat.format("{2}:{4}", + ContentViewerHtmlStyles.getKeyColumnClassName(), + ContentViewerHtmlStyles.getTextClassName(), + key, + ContentViewerHtmlStyles.getTextClassName(), + value + )); + } + + private void addRow(StringBuilder sb, String key) { + sb.append(MessageFormat.format("{2}", + ContentViewerHtmlStyles.getKeyColumnClassName(), + ContentViewerHtmlStyles.getTextClassName(), + key + )); + } + + private void addRowWithMultipleValues(StringBuilder sb, String key, String[] values) { + String[] safeValues = values == null || values.length < 1 ? new String[]{""} : values; + + addRow(sb, key, safeValues[0]); + Stream.of(safeValues) + .skip(1) + .filter(line -> line != null) + .forEach(line -> addRow(sb, line)); } @Messages({ + "Metadata.headerTitle=Metadata", "Metadata.tableRowTitle.mimeType=MIME Type", "Metadata.nodeText.truncated=(results truncated)", "Metadata.tableRowTitle.sha1=SHA1", @@ -222,8 +254,11 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer { if (StringUtils.isEmpty(details)) { details = Bundle.Metadata_nodeText_unknown(); } - details = details.replaceAll("\n", "
"); - addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.acquisitionDetails"), details); + String[] lines = (details != null) ? details.split("\n") : new String[]{""}; + addRowWithMultipleValues(sb, + NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.acquisitionDetails"), + lines); + } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error reading acquisition details from case database", ex); //NON-NLS } @@ -243,11 +278,9 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer { if (node != null && !node.getLookup().lookupAll(DataArtifact.class).isEmpty()) { return Bundle.Metadata_dataArtifactTitle(); } else { - return NbBundle.getMessage(this.getClass(), "Metadata.title"); + return NbBundle.getMessage(this.getClass(), "Metadata.title"); } } - - @Override public String getToolTip() { @@ -302,6 +335,7 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer { } StringBuilder sb = new StringBuilder(); + addHeader(sb, Bundle.Metadata_headerTitle(), false); startTable(sb); if (file != null) { @@ -360,30 +394,35 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer { * If we have a file system file, grab the more detailed * metadata text too */ - try { - if (file instanceof FsContent) { - FsContent fsFile = (FsContent) file; + if (file instanceof FsContent) { + FsContent fsFile = (FsContent) file; - sb.append("
\n"); //NON-NLS
-                        sb.append(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.text"));
-                        sb.append(" 

"); // NON-NLS - for (String str : fsFile.getMetaDataText()) { - sb.append(str).append("
"); //NON-NLS + addHeader(sb, NbBundle.getMessage(this.getClass(), "Metadata.nodeText.text"), true); + startTable(sb); - /* + List istatStrings = Collections.emptyList(); + try { + istatStrings = fsFile.getMetaDataText(); + } catch (TskCoreException ex) { + istatStrings = Arrays.asList(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.exceptionNotice.text") + ex.getLocalizedMessage()); + } + + for (String str : istatStrings) { + addRow(sb, str); + + /* * Very long results can cause the UI to hang before * displaying, so truncate the results if necessary. - */ - if (sb.length() > 50000) { - sb.append(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.truncated")); - break; - } + */ + if (sb.length() > 50000) { + addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.nodeText.truncated")); + break; } - sb.append("
\n"); //NON-NLS } - } catch (TskCoreException ex) { - sb.append(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.exceptionNotice.text")).append(ex.getLocalizedMessage()); + + endTable(sb); } + } else { try { addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.name"), image.getUniquePath()); @@ -422,20 +461,18 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer { // Add all the data source paths to the "Local Path" value cell. String[] imagePaths = image.getPaths(); + + if (imagePaths.length > 0) { - StringBuilder pathValues = new StringBuilder("
"); - pathValues.append(imagePaths[0]); - pathValues.append("
"); - for (int i = 1; i < imagePaths.length; i++) { - pathValues.append("
"); - pathValues.append(imagePaths[i]); - pathValues.append("
"); - } - addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.localPath"), pathValues.toString()); + addRowWithMultipleValues(sb, + NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.localPath"), + imagePaths); } else { addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.localPath"), NbBundle.getMessage(this.getClass(), "Metadata.nodeText.none")); } + + endTable(sb); } if (isCancelled()) { diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java index fb56971f57..924be963dd 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java @@ -36,15 +36,15 @@ import org.sleuthkit.datamodel.Score; * Displays a list of analysis results in a panel. */ public class AnalysisResultsContentPanel extends javax.swing.JPanel { - + private static final long serialVersionUID = 1L; - + private static final String EMPTY_HTML = ""; // Anchors are inserted into the navigation so that the viewer can navigate to a selection. // This is the prefix of those anchors. private static final String RESULT_ANCHOR_PREFIX = "AnalysisResult_"; - + /** * Creates new form AnalysisResultsContentViewer */ @@ -59,8 +59,9 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel { * @param message The message to be displayed. */ void showMessage(String message) { + ContentViewerHtmlStyles.setStyles(textPanel); textPanel.setText("" - + MessageFormat.format("

{1}

", + + MessageFormat.format("

{1}

", ContentViewerHtmlStyles.getMessageClassName(), message == null ? "" : message) + ""); @@ -104,8 +105,9 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel { } // set the body html + ContentViewerHtmlStyles.setStyles(textPanel); textPanel.setText(document.html()); - + // if there is a selected result scroll to it Optional selectedResult = nodeResults.getSelectedResult(); if (selectedResult.isPresent()) { @@ -115,19 +117,22 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel { /** * Returns the anchor id to use with the analysis result (based on the id). + * * @param analysisResult The analysis result. + * * @return The anchor id. */ private String getAnchor(AnalysisResult analysisResult) { return RESULT_ANCHOR_PREFIX + analysisResult.getId(); } - /** * Appends a result item to the parent element of an html document. + * * @param parent The parent element. - * @param index The index of the item in the list of all items. - * @param attrs The attributes of this item. + * @param index The index of the item in the list of all items. + * @param attrs The attributes of this item. + * * @return The result div. */ @NbBundle.Messages({"# {0} - analysisResultsNumber", @@ -138,20 +143,23 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel { Element sectionDiv = appendSection(parent, Bundle.AnalysisResultsContentPanel_result_headerKey(index + 1), Optional.ofNullable(getAnchor(attrs.getAnalysisResult()))); - + // create a table Element table = sectionDiv.appendElement("table"); table.attr("class", ContentViewerHtmlStyles.getIndentedClassName()); - + Element tableBody = table.appendElement("tbody"); // append a row for each item for (Pair keyVal : attrs.getAttributesToDisplay()) { Element row = tableBody.appendElement("tr"); String keyString = keyVal.getKey() == null ? "" : keyVal.getKey() + ":"; - row.appendElement("td") + Element keyTd = row.appendElement("td") + .attr("class", ContentViewerHtmlStyles.getTextClassName()); + + keyTd.appendElement("span") .text(keyString) - .attr("class", ContentViewerHtmlStyles.getTextClassName() + " " + ContentViewerHtmlStyles.getKeyColumnClassName()); + .attr("class", ContentViewerHtmlStyles.getKeyColumnClassName()); String valueString = keyVal.getValue() == null ? "" : keyVal.getValue(); row.appendElement("td") @@ -173,7 +181,7 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel { */ private Element appendSection(Element parent, String headerText, Optional anchorId) { Element sectionDiv = parent.appendElement("div"); - + // append an anchor tag if there is one Element anchorEl = null; if (anchorId.isPresent()) { @@ -181,17 +189,17 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel { anchorEl.attr("name", anchorId.get()); anchorEl.attr("style", "padding: 0px; margin: 0px; display: inline-block;"); } - + // append the header Element header = null; - header = (anchorEl == null) + header = (anchorEl == null) ? sectionDiv.appendElement("h1") : anchorEl.appendElement("h1"); header.text(headerText); header.attr("class", ContentViewerHtmlStyles.getHeaderClassName()); header.attr("style", "display: inline-block"); - + // return the section element return sectionDiv; } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java index fa1ae8ee0d..04c417354b 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.contentviewers.layout; import java.awt.Font; import javax.swing.JTextPane; +import javax.swing.text.EditorKit; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.StyleSheet; @@ -148,6 +149,15 @@ public class ContentViewerHtmlStyles { public static String getKeyColumnClassName() { return KEY_COLUMN_TD_CLASSNAME; } + + + public static void setStyles(JTextPane textPane) { + EditorKit editorKit = textPane.getEditorKit(); + if (editorKit instanceof HTMLEditorKit) { + ((HTMLEditorKit) editorKit).setStyleSheet(STYLE_SHEET); + } + } + /** * Sets up a JTextPane for html rendering using the css class names From 73700b3eb84404cf009780bb83a30ad490f1cf55 Mon Sep 17 00:00:00 2001 From: apriestman Date: Wed, 9 Jun 2021 07:39:55 -0400 Subject: [PATCH 19/33] Do MIME type detection for zip bomb test during file extraction --- .../SevenZipExtractor.java | 67 ++++++++++++------- 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index 35b5a7e560..b7a5f6e545 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -46,6 +46,7 @@ import net.sf.sevenzipjbinding.PropID; import net.sf.sevenzipjbinding.SevenZip; import net.sf.sevenzipjbinding.SevenZipException; import net.sf.sevenzipjbinding.SevenZipNativeInitializationException; +import org.apache.tika.Tika; import org.apache.tika.parser.txt.CharsetDetector; import org.apache.tika.parser.txt.CharsetMatch; import org.netbeans.api.progress.ProgressHandle; @@ -194,6 +195,15 @@ class SevenZipExtractor { } return false; } + + boolean isSevenZipExtractionSupported(String mimeType) { + for (SupportedArchiveExtractionFormats supportedMimeType : SupportedArchiveExtractionFormats.values()) { + if (mimeType.contains(supportedMimeType.toString())) { + return true; + } + } + return false; + } /** * Private helper method to standardize the cancellation check that is @@ -789,28 +799,10 @@ class SevenZipExtractor { // add them to the DB. We wait until the end so that we have the metadata on all of the // intermediate nodes since the order is not guaranteed try { - unpackedTree.updateOrAddFileToCaseRec(statusMap, archiveFilePath); + unpackedTree.updateOrAddFileToCaseRec(statusMap, archiveFilePath, parentAr, archiveFile, depthMap); if (checkForIngestCancellation(archiveFile)) { return false; } - unpackedFiles = unpackedTree.getAllFileObjects(); - //check if children are archives, update archive depth tracking - for (int i = 0; i < unpackedFiles.size(); i++) { - if (checkForIngestCancellation(archiveFile)) { - return false; - } - progress.progress(String.format("%s: Searching for nested archives (%d of %d)", currentArchiveName, i + 1, unpackedFiles.size())); - AbstractFile unpackedFile = unpackedFiles.get(i); - if (unpackedFile == null) { - continue; - } - if (isSevenZipExtractionSupported(unpackedFile)) { - Archive child = new Archive(parentAr.getDepth() + 1, parentAr.getRootArchiveId(), archiveFile); - parentAr.addChild(child); - depthMap.put(unpackedFile.getId(), child); - } - unpackedFile.close(); - } } catch (TskCoreException | NoCurrentCaseException e) { logger.log(Level.SEVERE, "Error populating complete derived file hierarchy from the unpacked dir structure", e); //NON-NLS @@ -991,6 +983,8 @@ class SevenZipExtractor { private EncodedFileOutputStream output; private String localAbsPath; private int bytesWritten; + private static final Tika tika = new Tika(); + private String mimeType = ""; UnpackStream(String localAbsPath) throws IOException { this.output = new EncodedFileOutputStream(new FileOutputStream(localAbsPath), TskData.EncodingType.XOR1); @@ -1003,6 +997,7 @@ class SevenZipExtractor { this.output = new EncodedFileOutputStream(new FileOutputStream(localAbsPath), TskData.EncodingType.XOR1); this.localAbsPath = localAbsPath; this.bytesWritten = 0; + this.mimeType = ""; } public int getSize() { @@ -1012,6 +1007,10 @@ class SevenZipExtractor { @Override public int write(byte[] bytes) throws SevenZipException { try { + // Detect MIME type now while the file is in memory + if (bytesWritten == 0) { + mimeType = tika.detect(bytes); + } output.write(bytes); this.bytesWritten += bytes.length; } catch (IOException ex) { @@ -1023,6 +1022,10 @@ class SevenZipExtractor { return bytes.length; } + public String getMIMEType() { + return mimeType; + } + public void close() throws IOException { try (EncodedFileOutputStream out = output) { out.flush(); @@ -1196,6 +1199,8 @@ class SevenZipExtractor { 0L, createTimeInSeconds, accessTimeInSeconds, modTimeInSeconds, localRelPath); return; + } else { + unpackedNode.setMimeType(unpackStream.getMIMEType()); } final String localAbsPath = archiveDetailsMap.get( @@ -1413,10 +1418,10 @@ class SevenZipExtractor { * Traverse the tree top-down after unzipping is done and create derived * files for the entire hierarchy */ - void updateOrAddFileToCaseRec(HashMap statusMap, String archiveFilePath) throws TskCoreException, NoCurrentCaseException { + void updateOrAddFileToCaseRec(HashMap statusMap, String archiveFilePath, Archive parentAr, AbstractFile archiveFile, ConcurrentHashMap depthMap) throws TskCoreException, NoCurrentCaseException { final FileManager fileManager = Case.getCurrentCaseThrows().getServices().getFileManager(); for (UnpackedNode child : rootNode.getChildren()) { - updateOrAddFileToCaseRec(child, fileManager, statusMap, archiveFilePath); + updateOrAddFileToCaseRec(child, fileManager, statusMap, archiveFilePath, parentAr, archiveFile, depthMap); } } @@ -1434,7 +1439,7 @@ class SevenZipExtractor { * * @throws TskCoreException */ - private void updateOrAddFileToCaseRec(UnpackedNode node, FileManager fileManager, HashMap statusMap, String archiveFilePath) throws TskCoreException { + private void updateOrAddFileToCaseRec(UnpackedNode node, FileManager fileManager, HashMap statusMap, String archiveFilePath, Archive parentAr, AbstractFile archiveFile, ConcurrentHashMap depthMap) throws TskCoreException { DerivedFile df; progress.progress(String.format("%s: Adding/updating files in case database (%d of %d)", currentArchiveName, ++nodesProcessed, numItems)); try { @@ -1497,10 +1502,17 @@ class SevenZipExtractor { } } } + + // Check for zip bombs + if (isSevenZipExtractionSupported(node.getMimeType())) { + Archive child = new Archive(parentAr.getDepth() + 1, parentAr.getRootArchiveId(), archiveFile); + parentAr.addChild(child); + depthMap.put(node.getFile().getId(), child); + } //recurse adding the children if this file was incomplete the children presumably need to be added for (UnpackedNode child : node.getChildren()) { - updateOrAddFileToCaseRec(child, fileManager, statusMap, getKeyFromUnpackedNode(node, archiveFilePath)); + updateOrAddFileToCaseRec(child, fileManager, statusMap, getKeyFromUnpackedNode(node, archiveFilePath), parentAr, archiveFile, depthMap); } } @@ -1517,6 +1529,7 @@ class SevenZipExtractor { private long size; private long ctime, crtime, atime, mtime; private boolean isFile; + private String mimeType = ""; private UnpackedNode parent; //root constructor @@ -1593,6 +1606,14 @@ class SevenZipExtractor { void setFile(AbstractFile file) { this.file = file; } + + void setMimeType(String mimeType) { + this.mimeType = mimeType; + } + + String getMimeType() { + return mimeType; + } /** * get child by name or null if it doesn't exist From 56968ec0df35db566175e55c4a339ef62dba5ba6 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 9 Jun 2021 08:34:46 -0400 Subject: [PATCH 20/33] updates in metadata --- .../autopsy/contentviewers/Metadata.form | 2 -- .../autopsy/contentviewers/Metadata.java | 19 ++++++++------- .../AnalysisResultsContentPanel.java | 3 ++- .../layout/ContentViewerDefaults.java | 11 +++++++++ .../layout/ContentViewerHtmlStyles.java | 23 ++++++++++++++++--- .../keywordsearch/ExtractedContentPanel.java | 11 ++++++--- 6 files changed, 50 insertions(+), 19 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.form b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.form index b175b6b512..8e6f123911 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.form @@ -41,8 +41,6 @@ - - diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java index 72691afe64..bd3671e44b 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java @@ -35,6 +35,7 @@ import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerHtmlStyles; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; +import org.sleuthkit.autopsy.coreutils.EscapeUtil; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; import org.sleuthkit.datamodel.AbstractFile; @@ -86,8 +87,6 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer { setPreferredSize(new java.awt.Dimension(100, 52)); - jScrollPane2.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); - jScrollPane2.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); jScrollPane2.setPreferredSize(new java.awt.Dimension(610, 52)); jTextPane1.setEditable(false); @@ -149,17 +148,17 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer { sb.append(MessageFormat.format("{2}:{4}", ContentViewerHtmlStyles.getKeyColumnClassName(), ContentViewerHtmlStyles.getTextClassName(), - key, + EscapeUtil.escapeHtml(key), ContentViewerHtmlStyles.getTextClassName(), - value + EscapeUtil.escapeHtml(key) )); } - private void addRow(StringBuilder sb, String key) { + private void addMonospacedRow(StringBuilder sb, String key) { sb.append(MessageFormat.format("{2}", ContentViewerHtmlStyles.getKeyColumnClassName(), - ContentViewerHtmlStyles.getTextClassName(), - key + ContentViewerHtmlStyles.getMonospacedClassName(), + EscapeUtil.escapeHtml(key) )); } @@ -170,7 +169,7 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer { Stream.of(safeValues) .skip(1) .filter(line -> line != null) - .forEach(line -> addRow(sb, line)); + .forEach(line -> addRow(sb, "", EscapeUtil.escapeHtml(line))); } @Messages({ @@ -408,14 +407,14 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer { } for (String str : istatStrings) { - addRow(sb, str); + addMonospacedRow(sb, str); /* * Very long results can cause the UI to hang before * displaying, so truncate the results if necessary. */ if (sb.length() > 50000) { - addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.nodeText.truncated")); + addMonospacedRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.nodeText.truncated")); break; } } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java index 924be963dd..13857de887 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java @@ -29,6 +29,7 @@ import org.openide.util.NbBundle; import org.sleuthkit.autopsy.contentviewers.analysisresults.AnalysisResultsViewModel.NodeResults; import org.sleuthkit.autopsy.contentviewers.analysisresults.AnalysisResultsViewModel.ResultDisplayAttributes; import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerHtmlStyles; +import org.sleuthkit.autopsy.coreutils.EscapeUtil; import org.sleuthkit.datamodel.AnalysisResult; import org.sleuthkit.datamodel.Score; @@ -63,7 +64,7 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel { textPanel.setText("" + MessageFormat.format("

{1}

", ContentViewerHtmlStyles.getMessageClassName(), - message == null ? "" : message) + message == null ? "" : EscapeUtil.escapeHtml(message)) + ""); } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java index 8f7b077233..65023b9110 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerDefaults.java @@ -41,6 +41,8 @@ public class ContentViewerDefaults { private static final Font HEADER_FONT = DEFAULT_FONT.deriveFont(Font.BOLD, DEFAULT_FONT.getSize() + 2); private static final Font MESSAGE_FONT = DEFAULT_FONT.deriveFont(Font.ITALIC); + + private static final Font MONOSPACED_FONT = new Font(Font.MONOSPACED, Font.PLAIN, DEFAULT_FONT.getSize()); private static final Insets DEFAULT_PANEL_INSETS = UIManager.getDefaults().getInsets("TextPane.margin"); @@ -98,6 +100,15 @@ public class ContentViewerDefaults { return SUB_HEADER_FONT; } + /** + * Returns the font to be used for normal monospace. + * + * @return The font to be used for normal monospace. + */ + public static Font getMonospacedFont() { + return MONOSPACED_FONT; + } + /** * Returns the insets of the content within the parent content viewer panel. * diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java index 04c417354b..437b67bf1b 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java @@ -38,6 +38,7 @@ public class ContentViewerHtmlStyles { private static final String MESSAGE_CLASSNAME = CLASS_PREFIX + "message"; private static final String TEXT_CLASSNAME = CLASS_PREFIX + "text"; + private static final String MONOSPACED_CLASSNAME = CLASS_PREFIX + "monospaced"; private static final String INDENTED_CLASSNAME = CLASS_PREFIX + "indent"; private static final String SPACED_SECTION_CLASSNAME = CLASS_PREFIX + "spacedSection"; private static final String KEY_COLUMN_TD_CLASSNAME = CLASS_PREFIX + "keyKolumn"; @@ -46,6 +47,7 @@ public class ContentViewerHtmlStyles { private static final Font MESSAGE_FONT = ContentViewerDefaults.getMessageFont(); private static final Font HEADER_FONT = ContentViewerDefaults.getHeaderFont(); private static final Font SUB_HEADER_FONT = ContentViewerDefaults.getSubHeaderFont(); + private static final Font MONOSPACED_FONT = ContentViewerDefaults.getMonospacedFont(); // additional styling for components private static final String STYLE_SHEET_RULE @@ -57,6 +59,8 @@ public class ContentViewerHtmlStyles { SUB_HEADER_CLASSNAME, SUB_HEADER_FONT.getFamily(), SUB_HEADER_FONT.getSize(), pxToPt(ContentViewerDefaults.getLineSpacing())) + String.format(" .%s { font-family: %s; font-size: %dpt; margin: 0px; padding: 0px 0px %dpt 0px; } ", TEXT_CLASSNAME, DEFAULT_FONT.getFamily(), DEFAULT_FONT.getSize(), pxToPt(ContentViewerDefaults.getLineSpacing())) + + String.format(" .%s { font-family: %s; font-size: %dpt; margin: 0px; padding: 0px 0px %dpt 0px; } ", + MONOSPACED_CLASSNAME, "Monospaced", MONOSPACED_FONT.getSize(), pxToPt(ContentViewerDefaults.getLineSpacing())) + String.format(" .%s { padding-left: %dpt } ", INDENTED_CLASSNAME, pxToPt(ContentViewerDefaults.getSectionIndent())) + String.format(" .%s { padding-top: %dpt } ", @@ -119,6 +123,15 @@ public class ContentViewerHtmlStyles { return TEXT_CLASSNAME; } + /** + * Returns the class name to use for monospaced text. + * + * @return The class name to use for monospaced text. + */ + public static String getMonospacedClassName() { + return MONOSPACED_CLASSNAME; + } + /** * Returns the class name to use for an indented (left padding) section. * @@ -149,15 +162,19 @@ public class ContentViewerHtmlStyles { public static String getKeyColumnClassName() { return KEY_COLUMN_TD_CLASSNAME; } - - + + /** + * If the textPane has an HTMLEditorKit, specifies the + * ContentViewerHTMLStyles styles to use refreshing the styles. + * + * @param textPane The text pane. + */ public static void setStyles(JTextPane textPane) { EditorKit editorKit = textPane.getEditorKit(); if (editorKit instanceof HTMLEditorKit) { ((HTMLEditorKit) editorKit).setStyleSheet(STYLE_SHEET); } } - /** * Sets up a JTextPane for html rendering using the css class names diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentPanel.java index 0e716c8168..c64cee2565 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentPanel.java @@ -72,7 +72,6 @@ class ExtractedContentPanel extends javax.swing.JPanel implements ResizableTextP ExtractedContentPanel() { initComponents(); additionalInit(); - setSources("", new ArrayList<>()); hitPreviousButton.setEnabled(false); hitNextButton.setEnabled(false); @@ -137,7 +136,6 @@ class ExtractedContentPanel extends javax.swing.JPanel implements ResizableTextP }; // set new style sheet to clear default styles styleSheet = editorKit.getStyleSheet(); - setStyleSheetSize(styleSheet, DEFAULT_FONT.getSize()); sourceComboBox.addItemListener(itemEvent -> { if (itemEvent.getStateChange() == ItemEvent.SELECTED) { @@ -158,11 +156,16 @@ class ExtractedContentPanel extends javax.swing.JPanel implements ResizableTextP if (zoomPanel instanceof TextZoomPanel) ((TextZoomPanel) this.zoomPanel).resetSize(); }); + + setSources("", new ArrayList<>()); } private void setStyleSheetSize(StyleSheet styleSheet, int size) { - styleSheet.addRule("body { font-family:\"" + DEFAULT_FONT.getFamily() + "\"; font-size:" + size + "pt; } "); + styleSheet.addRule( + "body { font-family:\"" + DEFAULT_FONT.getFamily() + "\"; font-size:" + size + "pt; } " + + "pre { font-family:\"" + DEFAULT_FONT.getFamily() + "\"; font-size:" + size + "pt; } " + ); } @@ -501,6 +504,8 @@ class ExtractedContentPanel extends javax.swing.JPanel implements ResizableTextP extractedTextPane.applyComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); } + // refresh style + setStyleSheetSize(styleSheet, curSize); extractedTextPane.setText(safeText); extractedTextPane.setCaretPosition(0); } From b3f8a878793242ea1fb13358308e368169bec86f Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 9 Jun 2021 08:44:23 -0400 Subject: [PATCH 21/33] monospace fix --- .../autopsy/contentviewers/layout/ContentViewerHtmlStyles.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java index 437b67bf1b..17632dc802 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java @@ -60,7 +60,7 @@ public class ContentViewerHtmlStyles { + String.format(" .%s { font-family: %s; font-size: %dpt; margin: 0px; padding: 0px 0px %dpt 0px; } ", TEXT_CLASSNAME, DEFAULT_FONT.getFamily(), DEFAULT_FONT.getSize(), pxToPt(ContentViewerDefaults.getLineSpacing())) + String.format(" .%s { font-family: %s; font-size: %dpt; margin: 0px; padding: 0px 0px %dpt 0px; } ", - MONOSPACED_CLASSNAME, "Monospaced", MONOSPACED_FONT.getSize(), pxToPt(ContentViewerDefaults.getLineSpacing())) + MONOSPACED_CLASSNAME, Font.MONOSPACED, MONOSPACED_FONT.getSize(), pxToPt(ContentViewerDefaults.getLineSpacing())) + String.format(" .%s { padding-left: %dpt } ", INDENTED_CLASSNAME, pxToPt(ContentViewerDefaults.getSectionIndent())) + String.format(" .%s { padding-top: %dpt } ", From 5a1879217c5150cc650ac17713969dab05546b1c Mon Sep 17 00:00:00 2001 From: apriestman Date: Thu, 10 Jun 2021 10:03:00 -0400 Subject: [PATCH 22/33] Use more efficient version of findFiles() --- .../autopsy/casemodule/services/FileManager.java | 3 +-- .../autopsy/recentactivity/ChromeCacheExtractor.java | 5 +++-- .../org/sleuthkit/autopsy/recentactivity/Chromium.java | 2 +- .../recentactivity/DataSourceUsageAnalyzer.java | 10 +++++----- .../sleuthkit/autopsy/recentactivity/ExtractOs.java | 4 ++-- .../autopsy/recentactivity/ExtractRegistry.java | 3 +-- .../autopsy/recentactivity/ExtractSafari.java | 5 ++--- .../org/sleuthkit/autopsy/recentactivity/Firefox.java | 7 +++++-- .../autopsy/recentactivity/RecentDocumentsByLnk.java | 3 +-- .../src/org/sleuthkit/autopsy/recentactivity/Util.java | 3 +-- 10 files changed, 22 insertions(+), 23 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java index deaa0d1ca8..34f26eb1ac 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java @@ -130,8 +130,7 @@ public class FileManager implements Closeable { * @throws TskCoreException */ public List findFilesExactName(long parentId, String name) throws TskCoreException{ - String whereClause = "name = '%s'"; - return caseDb.findAllFilesInFolderWhere(parentId, String.format(whereClause, name)); + return caseDb.getFileManager().findFilesExactName(parentId, name); } /** diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ChromeCacheExtractor.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ChromeCacheExtractor.java index 9435161a23..f3e073e7f9 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ChromeCacheExtractor.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ChromeCacheExtractor.java @@ -596,8 +596,9 @@ final class ChromeCacheExtractor { if (fileCopyCache.containsKey(fileTableKey)) { return Optional.of(fileCopyCache.get(fileTableKey).getAbstractFile()); } - - List cacheFiles = fileManager.findFiles(dataSource, cacheFileName, cacheFolderName); //NON-NLS + + List cacheFiles = currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, + cacheFileName, cacheFolderName); if (!cacheFiles.isEmpty()) { // Sort the list for consistency. Preference is: // - In correct subfolder and allocated diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Chromium.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Chromium.java index a3db639b32..371394ff10 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Chromium.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Chromium.java @@ -633,7 +633,7 @@ class Chromium extends Extract { BlackboardArtifact webDownloadArtifact = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadFile, bbattributes); bbartifacts.add(webDownloadArtifact); String normalizedFullPath = FilenameUtils.normalize(fullPath, true); - for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(normalizedFullPath), FilenameUtils.getPath(normalizedFullPath))) { + for (AbstractFile downloadedFile : currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, FilenameUtils.getName(normalizedFullPath), FilenameUtils.getPath(normalizedFullPath))) { bbartifacts.add(createAssociatedArtifact(downloadedFile, webDownloadArtifact)); break; } diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/DataSourceUsageAnalyzer.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/DataSourceUsageAnalyzer.java index bd6b5836d5..2c05beb967 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/DataSourceUsageAnalyzer.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/DataSourceUsageAnalyzer.java @@ -163,8 +163,9 @@ class DataSourceUsageAnalyzer extends Extract { private void checkIfOsSpecificVolume(ExtractOs.OS_TYPE osType) throws TskCoreException { FileManager fileManager = currentCase.getServices().getFileManager(); for (String filePath : osType.getFilePaths()) { - for (AbstractFile file : fileManager.findFiles(dataSource, FilenameUtils.getName(filePath), FilenameUtils.getPath(filePath))) { - if ((file.getParentPath() + file.getName()).equals(filePath)) { + for (AbstractFile file : currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, + FilenameUtils.getName(filePath), FilenameUtils.getPath(filePath))) { + if ((file.getParentPath() + file.getName()).equals(filePath)) { createDataSourceUsageArtifact(osType.getDsUsageLabel()); return; } @@ -224,10 +225,9 @@ class DataSourceUsageAnalyzer extends Extract { * @throws TskCoreException */ private boolean hasAndroidMediaCardRootNames() throws TskCoreException{ - FileManager fileManager = currentCase.getServices().getFileManager(); for (String fileName : ANDROID_MEDIACARD_ROOT_FILENAMES) { - for (AbstractFile file : fileManager.findFiles(dataSource, fileName, "/")) { // NON-NLS - if (file.getParentPath().equals("/") && file.getName().equalsIgnoreCase(fileName)) { // NON-NLS + for (AbstractFile file : currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, fileName, "/")) { // NON-NLS + if (file.getParentPath().equals("/") && file.getName().equalsIgnoreCase(fileName)) { // NON-NLS createDataSourceUsageArtifact(Bundle.DataSourceUsage_AndroidMedia()); return true; } diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractOs.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractOs.java index a76c1652dd..b6ea418672 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractOs.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractOs.java @@ -117,9 +117,9 @@ class ExtractOs extends Extract { * search for */ private AbstractFile getFirstFileFound(List pathsToSearchFor) throws TskCoreException{ - FileManager fileManager = currentCase.getServices().getFileManager(); for (String filePath : pathsToSearchFor) { - for (AbstractFile file : fileManager.findFiles(dataSource, FilenameUtils.getName(filePath), FilenameUtils.getPath(filePath))) { + + for (AbstractFile file : currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, FilenameUtils.getName(filePath), FilenameUtils.getPath(filePath))) { if ((file.getParentPath() + file.getName()).equals(filePath)) { return file; } diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java index cd2eefc4f4..6dcd977f78 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java @@ -1684,12 +1684,11 @@ class ExtractRegistry extends Extract { * @returnv BlackboardArtifact or a null value */ private BlackboardArtifact createAssociatedArtifact(String filePathName, BlackboardArtifact bba) { - org.sleuthkit.autopsy.casemodule.services.FileManager fileManager = currentCase.getServices().getFileManager(); String fileName = FilenameUtils.getName(filePathName); String filePath = FilenameUtils.getPath(filePathName); List sourceFiles; try { - sourceFiles = fileManager.findFiles(dataSource, fileName, filePath); //NON-NLS + sourceFiles = currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, fileName, filePath); if (!sourceFiles.isEmpty()) { for (AbstractFile sourceFile : sourceFiles) { if (sourceFile.getParentPath().endsWith(filePath)) { diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractSafari.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractSafari.java index 2bf0351542..429666f8d6 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractSafari.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractSafari.java @@ -647,8 +647,6 @@ final class ExtractSafari extends Extract { Long time = null; Long pathID = null; - FileManager fileManager = getCurrentCase().getServices().getFileManager(); - NSString nsstring = (NSString) entry.get(PLIST_KEY_DOWNLOAD_URL); if (nsstring != null) { url = nsstring.toString(); @@ -669,7 +667,8 @@ final class ExtractSafari extends Extract { bbartifacts.add(webDownloadArtifact); // find the downloaded file and create a TSK_ASSOCIATED_OBJECT for it, associating it with the TSK_WEB_DOWNLOAD artifact. - for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(path), FilenameUtils.getPath(path))) { + for (AbstractFile downloadedFile : currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, + FilenameUtils.getName(path), FilenameUtils.getPath(path))) { bbartifacts.add(createAssociatedArtifact(downloadedFile, webDownloadArtifact)); break; } diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java index 6dd30ed4cc..466dfab42a 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java @@ -592,7 +592,8 @@ class Firefox extends Extract { bbartifacts.add(webDownloadArtifact); // find the downloaded file and create a TSK_ASSOCIATED_OBJECT for it, associating it with the TSK_WEB_DOWNLOAD artifact. - for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(downloadedFilePath), FilenameUtils.getPath(downloadedFilePath))) { + for (AbstractFile downloadedFile : currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, + FilenameUtils.getName(downloadedFilePath), FilenameUtils.getPath(downloadedFilePath))) { bbartifacts.add(createAssociatedArtifact(downloadedFile, webDownloadArtifact)); break; } @@ -727,7 +728,9 @@ class Firefox extends Extract { bbartifacts.add(webDownloadArtifact); // find the downloaded file and create a TSK_ASSOCIATED_OBJECT for it, associating it with the TSK_WEB_DOWNLOAD artifact. - for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(downloadedFilePath), FilenameUtils.getPath(downloadedFilePath))) { + for (AbstractFile downloadedFile : currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, + FilenameUtils.getName(downloadedFilePath), FilenameUtils.getPath(downloadedFilePath))) { + //for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(downloadedFilePath), FilenameUtils.getPath(downloadedFilePath))) { bbartifacts.add(createAssociatedArtifact(downloadedFile, webDownloadArtifact)); break; } diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RecentDocumentsByLnk.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RecentDocumentsByLnk.java index b0c119ae25..d9ad0fbfb8 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RecentDocumentsByLnk.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RecentDocumentsByLnk.java @@ -152,13 +152,12 @@ class RecentDocumentsByLnk extends Extract { * @returnv BlackboardArtifact or a null value */ private BlackboardArtifact createAssociatedArtifact(String filePathName, BlackboardArtifact bba) { - org.sleuthkit.autopsy.casemodule.services.FileManager fileManager = currentCase.getServices().getFileManager(); String normalizePathName = FilenameUtils.normalize(filePathName, true); String fileName = FilenameUtils.getName(normalizePathName); String filePath = FilenameUtils.getPath(normalizePathName); List sourceFiles; try { - sourceFiles = fileManager.findFiles(dataSource, fileName, filePath); //NON-NLS + sourceFiles = currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, fileName, filePath); for (AbstractFile sourceFile : sourceFiles) { if (sourceFile.getParentPath().endsWith(filePath)) { return createAssociatedArtifact(sourceFile, bba); diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Util.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Util.java index ff95c60ca8..766c3c61de 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Util.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Util.java @@ -135,8 +135,7 @@ class Util { parent_path = parent_path.substring(0, index); List files = null; try { - FileManager fileManager = Case.getCurrentCaseThrows().getServices().getFileManager(); - files = fileManager.findFiles(dataSource, name, parent_path); + files = Case.getCurrentCaseThrows().getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, name, parent_path); } catch (TskCoreException | NoCurrentCaseException ex) { logger.log(Level.WARNING, "Error fetching 'index.data' files for Internet Explorer history."); //NON-NLS } From c9337579f6f245ce3487f15fa4b1fe32e3b7e36c Mon Sep 17 00:00:00 2001 From: apriestman Date: Thu, 10 Jun 2021 10:28:35 -0400 Subject: [PATCH 23/33] Change one method back. Cleanup. --- .../autopsy/recentactivity/DataSourceUsageAnalyzer.java | 5 +++-- .../src/org/sleuthkit/autopsy/recentactivity/Firefox.java | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/DataSourceUsageAnalyzer.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/DataSourceUsageAnalyzer.java index 2c05beb967..d633825497 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/DataSourceUsageAnalyzer.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/DataSourceUsageAnalyzer.java @@ -225,9 +225,10 @@ class DataSourceUsageAnalyzer extends Extract { * @throws TskCoreException */ private boolean hasAndroidMediaCardRootNames() throws TskCoreException{ + FileManager fileManager = currentCase.getServices().getFileManager(); for (String fileName : ANDROID_MEDIACARD_ROOT_FILENAMES) { - for (AbstractFile file : currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, fileName, "/")) { // NON-NLS - if (file.getParentPath().equals("/") && file.getName().equalsIgnoreCase(fileName)) { // NON-NLS + for (AbstractFile file : fileManager.findFiles(dataSource, fileName, "/")) { // NON-NLS + if (file.getParentPath().equals("/") && file.getName().equalsIgnoreCase(fileName)) { // NON-NLS createDataSourceUsageArtifact(Bundle.DataSourceUsage_AndroidMedia()); return true; } diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java index 466dfab42a..87bbb0232d 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java @@ -730,7 +730,6 @@ class Firefox extends Extract { // find the downloaded file and create a TSK_ASSOCIATED_OBJECT for it, associating it with the TSK_WEB_DOWNLOAD artifact. for (AbstractFile downloadedFile : currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, FilenameUtils.getName(downloadedFilePath), FilenameUtils.getPath(downloadedFilePath))) { - //for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(downloadedFilePath), FilenameUtils.getPath(downloadedFilePath))) { bbartifacts.add(createAssociatedArtifact(downloadedFile, webDownloadArtifact)); break; } From 227a5a822fe62ac0ab5acd242f36bd64ba6e1283 Mon Sep 17 00:00:00 2001 From: apriestman Date: Thu, 10 Jun 2021 10:30:39 -0400 Subject: [PATCH 24/33] Cleanup --- .../autopsy/recentactivity/DataSourceUsageAnalyzer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/DataSourceUsageAnalyzer.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/DataSourceUsageAnalyzer.java index d633825497..2c4556e6a3 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/DataSourceUsageAnalyzer.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/DataSourceUsageAnalyzer.java @@ -227,7 +227,7 @@ class DataSourceUsageAnalyzer extends Extract { private boolean hasAndroidMediaCardRootNames() throws TskCoreException{ FileManager fileManager = currentCase.getServices().getFileManager(); for (String fileName : ANDROID_MEDIACARD_ROOT_FILENAMES) { - for (AbstractFile file : fileManager.findFiles(dataSource, fileName, "/")) { // NON-NLS + for (AbstractFile file : fileManager.findFiles(dataSource, fileName, "/")) { // NON-NLS if (file.getParentPath().equals("/") && file.getName().equalsIgnoreCase(fileName)) { // NON-NLS createDataSourceUsageArtifact(Bundle.DataSourceUsage_AndroidMedia()); return true; From 8a50a6ac7df963451192b9c63fc9821f381a675a Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 10 Jun 2021 12:35:25 -0400 Subject: [PATCH 25/33] Changed DataSourcenodes to be created asyn --- Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java index c5fae53c03..4546290007 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java @@ -122,7 +122,7 @@ public class DataSourcesNode extends DisplayableItemNode { * Main constructor. */ DataSourcesNode() { - super(Children.create(new DataSourcesByTypeChildren(), false), Lookups.singleton(NAME)); + super(Children.create(new DataSourcesByTypeChildren(), true), Lookups.singleton(NAME)); setName(NAME); setDisplayName(NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/image.png"); From c2eb9a71791ef8418c29f34a949f1b90f5384a45 Mon Sep 17 00:00:00 2001 From: apriestman Date: Thu, 10 Jun 2021 12:48:08 -0400 Subject: [PATCH 26/33] Remove unnecessary path checks --- .../autopsy/recentactivity/DataSourceUsageAnalyzer.java | 9 ++------- .../org/sleuthkit/autopsy/recentactivity/ExtractOs.java | 8 +++----- .../autopsy/recentactivity/ExtractRegistry.java | 6 +----- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/DataSourceUsageAnalyzer.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/DataSourceUsageAnalyzer.java index 2c4556e6a3..0e4fa5ecf1 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/DataSourceUsageAnalyzer.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/DataSourceUsageAnalyzer.java @@ -157,18 +157,13 @@ class DataSourceUsageAnalyzer extends Extract { * does not exist with the given description. * * @param osType - the OS_TYPE to check for - * - * @return true if any specified files exist false if none exist */ private void checkIfOsSpecificVolume(ExtractOs.OS_TYPE osType) throws TskCoreException { - FileManager fileManager = currentCase.getServices().getFileManager(); for (String filePath : osType.getFilePaths()) { for (AbstractFile file : currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, FilenameUtils.getName(filePath), FilenameUtils.getPath(filePath))) { - if ((file.getParentPath() + file.getName()).equals(filePath)) { - createDataSourceUsageArtifact(osType.getDsUsageLabel()); - return; - } + createDataSourceUsageArtifact(osType.getDsUsageLabel()); + return; } } } diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractOs.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractOs.java index b6ea418672..6bc00ada63 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractOs.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractOs.java @@ -118,11 +118,9 @@ class ExtractOs extends Extract { */ private AbstractFile getFirstFileFound(List pathsToSearchFor) throws TskCoreException{ for (String filePath : pathsToSearchFor) { - - for (AbstractFile file : currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, FilenameUtils.getName(filePath), FilenameUtils.getPath(filePath))) { - if ((file.getParentPath() + file.getName()).equals(filePath)) { - return file; - } + List files = currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, FilenameUtils.getName(filePath), FilenameUtils.getPath(filePath)); + if (!files.isEmpty()) { + return files.get(0); } } return null; diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java index 6dcd977f78..8625431a13 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java @@ -1690,11 +1690,7 @@ class ExtractRegistry extends Extract { try { sourceFiles = currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, fileName, filePath); if (!sourceFiles.isEmpty()) { - for (AbstractFile sourceFile : sourceFiles) { - if (sourceFile.getParentPath().endsWith(filePath)) { - return createAssociatedArtifact(sourceFile, bba); - } - } + return createAssociatedArtifact(sourceFiles.get(0), bba); } } catch (TskCoreException ex) { // only catching the error and displaying the message as the file may not exist on the From 21048b038c2aefb902e0284c42448c996be23e5e Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 10 Jun 2021 15:14:51 -0400 Subject: [PATCH 27/33] Modified other locations to make sure nodes are created async --- .../autopsy/corecomponents/DataResultViewerTable.java | 6 ------ .../sleuthkit/autopsy/datamodel/AbstractContentNode.java | 2 +- .../sleuthkit/autopsy/datamodel/DataSourceFilesNode.java | 2 +- Core/src/org/sleuthkit/autopsy/datamodel/HostNode.java | 4 ++-- Core/src/org/sleuthkit/autopsy/datamodel/PersonNode.java | 2 +- 5 files changed, 5 insertions(+), 11 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java index e8c5ae4aea..7d0394d678 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java @@ -361,12 +361,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer { * If the given node is not null and has children, set it as the * root context of the child OutlineView, otherwise make an * "empty"node the root context. - * - * IMPORTANT NOTE: This is the first of many times where a - * getChildren call on the current root node causes all of the - * children of the root node to be created and defeats lazy child - * node creation, if it is enabled. It also likely leads to many - * case database round trips. */ if (rootNode != null && rootNode.getChildren().getNodesCount() > 0) { this.getExplorerManager().setRootContext(this.rootNode); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java index 7e0ee1a883..dfb3a2a75e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java @@ -112,7 +112,7 @@ public abstract class AbstractContentNode extends ContentNode * @param lookup The Lookup object for the node. */ AbstractContentNode(T content, Lookup lookup) { - super(Children.create(new ContentChildren(content), false), lookup); + super(Children.create(new ContentChildren(content), true), lookup); this.content = content; //super.setName(ContentUtils.getSystemName(content)); super.setName("content_" + Long.toString(content.getId())); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceFilesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceFilesNode.java index fd45f69bf0..b7e33860b9 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceFilesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceFilesNode.java @@ -69,7 +69,7 @@ public class DataSourceFilesNode extends DisplayableItemNode { } public DataSourceFilesNode(long dsObjId) { - super(Children.create(new DataSourcesNodeChildren(dsObjId), false), Lookups.singleton(NAME)); + super(Children.create(new DataSourcesNodeChildren(dsObjId), true), Lookups.singleton(NAME)); displayName = (dsObjId > 0) ? NbBundle.getMessage(DataSourceFilesNode.class, "DataSourcesNode.group_by_datasource.name") : NAME; init(); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HostNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/HostNode.java index 08ce15cab6..4b11bf6777 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HostNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HostNode.java @@ -212,7 +212,7 @@ public class HostNode extends DisplayableItemNode { * @param hosts The HostDataSources key. */ HostNode(HostDataSources hosts) { - this(Children.create(new HostGroupingChildren(HOST_DATA_SOURCES, hosts.getHost()), false), hosts.getHost()); + this(Children.create(new HostGroupingChildren(HOST_DATA_SOURCES, hosts.getHost()), true), hosts.getHost()); } /** @@ -222,7 +222,7 @@ public class HostNode extends DisplayableItemNode { * @param hostGrouping The HostGrouping key. */ HostNode(HostGrouping hostGrouping) { - this(Children.create(new HostGroupingChildren(HOST_GROUPING_CONVERTER, hostGrouping.getHost()), false), hostGrouping.getHost()); + this(Children.create(new HostGroupingChildren(HOST_GROUPING_CONVERTER, hostGrouping.getHost()), true), hostGrouping.getHost()); } /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/PersonNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/PersonNode.java index 99db59211b..06d52b8662 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/PersonNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/PersonNode.java @@ -203,7 +203,7 @@ public class PersonNode extends DisplayableItemNode { * @param displayName The display name for the person. */ private PersonNode(Person person, String displayName) { - super(Children.create(new PersonChildren(person), false), + super(Children.create(new PersonChildren(person), true), person == null ? Lookups.fixed(displayName) : Lookups.fixed(person, displayName)); super.setName(displayName); super.setDisplayName(displayName); From 1ab5b74afd1cb9983112dcaf55abf7f0600f1a24 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 11 Jun 2021 11:25:55 -0400 Subject: [PATCH 28/33] new resize approach --- .../corecomponents/DataResultViewerTable.java | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java index e8c5ae4aea..4628d7d8fb 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java @@ -215,6 +215,46 @@ public class DataResultViewerTable extends AbstractDataResultViewer { */ outline.getTableHeader().addMouseListener(outlineViewListener); } + + private static final int MIN_COLUMN_WIDTH = 30; + private static final int MAX_COLUMN_WIDTH = 300; + private static final int SAMPLE_ROW_NUM = 50; + private static final int COLUMN_PADDING = 10; + + // based on https://stackoverflow.com/questions/17627431/auto-resizing-the-jtable-column-widths + private void resizeColumnWidth(JTable table) { + final TableColumnModel columnModel = table.getColumnModel(); + + int availableTableWidth = table.getWidth(); + for (int column = 0; column < table.getColumnCount(); column++) { + int width = MIN_COLUMN_WIDTH; // Min width + + TableColumn tableColumn = columnModel.getColumn(column); + TableCellRenderer headerRenderer = tableColumn.getHeaderRenderer(); + if (headerRenderer == null) { + headerRenderer = table.getTableHeader().getDefaultRenderer(); + } + Object headerValue = tableColumn.getHeaderValue(); + Component headerComp = headerRenderer.getTableCellRendererComponent(table, headerValue, false, false, 0, column); + width = Math.max(headerComp.getPreferredSize().width + COLUMN_PADDING , width); + + for (int row = 0; row < Math.min(table.getRowCount(), SAMPLE_ROW_NUM); row++) { + TableCellRenderer renderer = table.getCellRenderer(row, column); + Component comp = table.prepareRenderer(renderer, row, column); + width = Math.max(comp.getPreferredSize().width + COLUMN_PADDING, width); + } + if(width > MAX_COLUMN_WIDTH) + width=MAX_COLUMN_WIDTH; + + if (column == table.getColumnCount() - 1) { + columnModel.getColumn(column).setMaxWidth(availableTableWidth); + columnModel.getColumn(column).setMinWidth(width); + } else { + columnModel.getColumn(column).setPreferredWidth(width); + availableTableWidth -= width; + } + } + } private void initializePagingSupport() { if (pagingSupport == null) { @@ -434,7 +474,8 @@ public class DataResultViewerTable extends AbstractDataResultViewer { ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(firstProp.getDisplayName()); } - setColumnWidths(); + resizeColumnWidth(outline); + //setColumnWidths(); /* * Load column sorting information from preferences file and apply it to From b374c81f9315ddf19ec77621a12053038d3ce7ea Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 11 Jun 2021 13:48:35 -0400 Subject: [PATCH 29/33] updated setColumnWidths method --- .../corecomponents/DataResultViewerTable.java | 211 +++++++----------- 1 file changed, 79 insertions(+), 132 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java index 4628d7d8fb..cb02899faf 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java @@ -21,8 +21,6 @@ package org.sleuthkit.autopsy.corecomponents; import com.google.common.eventbus.Subscribe; import java.awt.Component; import java.awt.Cursor; -import java.awt.FontMetrics; -import java.awt.Graphics; import java.awt.dnd.DnDConstants; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; @@ -49,6 +47,7 @@ import javax.swing.JTable; import javax.swing.ListSelectionModel; import static javax.swing.SwingConstants.CENTER; import javax.swing.SwingUtilities; +import javax.swing.UIManager; import javax.swing.event.ChangeEvent; import javax.swing.event.ListSelectionEvent; import javax.swing.event.TableColumnModelEvent; @@ -106,6 +105,27 @@ public class DataResultViewerTable extends AbstractDataResultViewer { private static final long serialVersionUID = 1L; private static final Logger LOGGER = Logger.getLogger(DataResultViewerTable.class.getName()); + // How many rows to sample in order to determine column width. + private static final int SAMPLE_ROW_NUM = 100; + + // The padding to be added in addition to content size when considering column width. + private static final int COLUMN_PADDING = 15; + + // The minimum column width. + private static final int MIN_COLUMN_WIDTH = 30; + + // The maximum column width. + private static final int MAX_COLUMN_WIDTH = 300; + + // The minimum row height to use when calculating whether scroll bar will be used. + private static final int MIN_ROW_HEIGHT = 10; + + // The width of the scroll bar. + private static final int SCROLL_BAR_WIDTH = ((Integer) UIManager.get("ScrollBar.width")).intValue(); + + // Any additional padding to be used for the first column. + private static final int FIRST_COL_ADDITIONAL_WIDTH = 0; + private static final String NOTEPAD_ICON_PATH = "org/sleuthkit/autopsy/images/notepad16.png"; private static final String RED_CIRCLE_ICON_PATH = "org/sleuthkit/autopsy/images/red-circle-exclamation.png"; private static final String YELLOW_CIRCLE_ICON_PATH = "org/sleuthkit/autopsy/images/yellow-circle-yield.png"; @@ -152,7 +172,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { * OutlineView to the actions global context. * * @param explorerManager The explorer manager of the ancestor top - * component. + * component. */ public DataResultViewerTable(ExplorerManager explorerManager) { this(explorerManager, Bundle.DataResultViewerTable_title()); @@ -165,8 +185,8 @@ public class DataResultViewerTable extends AbstractDataResultViewer { * in the OutlineView to the actions global context. * * @param explorerManager The explorer manager of the ancestor top - * component. - * @param title The title. + * component. + * @param title The title. */ public DataResultViewerTable(ExplorerManager explorerManager, String title) { super(explorerManager); @@ -215,46 +235,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer { */ outline.getTableHeader().addMouseListener(outlineViewListener); } - - private static final int MIN_COLUMN_WIDTH = 30; - private static final int MAX_COLUMN_WIDTH = 300; - private static final int SAMPLE_ROW_NUM = 50; - private static final int COLUMN_PADDING = 10; - - // based on https://stackoverflow.com/questions/17627431/auto-resizing-the-jtable-column-widths - private void resizeColumnWidth(JTable table) { - final TableColumnModel columnModel = table.getColumnModel(); - - int availableTableWidth = table.getWidth(); - for (int column = 0; column < table.getColumnCount(); column++) { - int width = MIN_COLUMN_WIDTH; // Min width - - TableColumn tableColumn = columnModel.getColumn(column); - TableCellRenderer headerRenderer = tableColumn.getHeaderRenderer(); - if (headerRenderer == null) { - headerRenderer = table.getTableHeader().getDefaultRenderer(); - } - Object headerValue = tableColumn.getHeaderValue(); - Component headerComp = headerRenderer.getTableCellRendererComponent(table, headerValue, false, false, 0, column); - width = Math.max(headerComp.getPreferredSize().width + COLUMN_PADDING , width); - - for (int row = 0; row < Math.min(table.getRowCount(), SAMPLE_ROW_NUM); row++) { - TableCellRenderer renderer = table.getCellRenderer(row, column); - Component comp = table.prepareRenderer(renderer, row, column); - width = Math.max(comp.getPreferredSize().width + COLUMN_PADDING, width); - } - if(width > MAX_COLUMN_WIDTH) - width=MAX_COLUMN_WIDTH; - - if (column == table.getColumnCount() - 1) { - columnModel.getColumn(column).setMaxWidth(availableTableWidth); - columnModel.getColumn(column).setMinWidth(width); - } else { - columnModel.getColumn(column).setPreferredWidth(width); - availableTableWidth -= width; - } - } - } private void initializePagingSupport() { if (pagingSupport == null) { @@ -410,6 +390,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { */ if (rootNode != null && rootNode.getChildren().getNodesCount() > 0) { this.getExplorerManager().setRootContext(this.rootNode); + outline.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); setupTable(); } else { Node emptyNode = new AbstractNode(Children.LEAF); @@ -462,20 +443,12 @@ public class DataResultViewerTable extends AbstractDataResultViewer { firstProp = props.remove(0); } - /* - * show the horizontal scroll panel and show all the content & header If - * there is only one column (which was removed from props above) Just - * let the table resize itself. - */ - outline.setAutoResizeMode((props.isEmpty()) ? JTable.AUTO_RESIZE_ALL_COLUMNS : JTable.AUTO_RESIZE_OFF); - assignColumns(props); // assign columns to match the properties if (firstProp != null) { ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(firstProp.getDisplayName()); } - resizeColumnWidth(outline); - //setColumnWidths(); + setColumnWidths(); /* * Load column sorting information from preferences file and apply it to @@ -554,87 +527,59 @@ public class DataResultViewerTable extends AbstractDataResultViewer { /* * Sets the column widths for the child OutlineView of this tabular results - * viewer. + * viewer providing any additional width to last column. */ protected void setColumnWidths() { - if (rootNode.getChildren().getNodesCount() != 0) { - final Graphics graphics = outlineView.getGraphics(); + // based on https://stackoverflow.com/questions/17627431/auto-resizing-the-jtable-column-widths + final TableColumnModel columnModel = outline.getColumnModel(); - if (graphics != null) { - // Current width of the outlineView - double outlineViewWidth = outlineView.getSize().getWidth(); - // List of the column widths - List columnWidths = new ArrayList<>(); - final FontMetrics metrics = graphics.getFontMetrics(); + // the remaining table width that can be used in last row + double availableTableWidth = outlineView.getSize().getWidth(); - int margin = 4; - int padding = 8; + for (int columnIdx = 0; columnIdx < outline.getColumnCount(); columnIdx++) { + int columnPadding = (columnIdx == 0) ? FIRST_COL_ADDITIONAL_WIDTH + COLUMN_PADDING : COLUMN_PADDING; + TableColumn tableColumn = columnModel.getColumn(columnIdx); - int totalColumnWidth = 0; - int cntMaxSizeColumns = 0; + // The width of this column + int width = MIN_COLUMN_WIDTH; - // Calulate the width for each column keeping track of the number - // of columns that were set to columnwidthLimit. - for (int column = 0; column < outline.getModel().getColumnCount(); column++) { - int firstColumnPadding = (column == 0) ? 32 : 0; - int columnWidthLimit = (column == 0) ? 350 : 300; - int valuesWidth = 0; - - // find the maximum width needed to fit the values for the first 100 rows, at most - for (int row = 0; row < Math.min(100, outline.getRowCount()); row++) { - TableCellRenderer renderer = outline.getCellRenderer(row, column); - Component comp = outline.prepareRenderer(renderer, row, column); - valuesWidth = Math.max(comp.getPreferredSize().width, valuesWidth); - } - - int headerWidth = metrics.stringWidth(outline.getColumnName(column)); - valuesWidth += firstColumnPadding; // add extra padding for first column - - int columnWidth = Math.max(valuesWidth, headerWidth); - columnWidth += 2 * margin + padding; // add margin and regular padding - - columnWidth = Math.min(columnWidth, columnWidthLimit); - columnWidths.add(columnWidth); - - totalColumnWidth += columnWidth; - - if (columnWidth == columnWidthLimit) { - cntMaxSizeColumns++; - } - } - - // Figure out how much extra, if any can be given to the columns - // so that the table is as wide as outlineViewWidth. If cntMaxSizeColumns - // is greater than 0 divide the extra space between the columns - // that could use more space. Otherwise divide evenly amoung - // all columns. - int extraWidth = 0; - - if (totalColumnWidth < outlineViewWidth) { - if (cntMaxSizeColumns > 0) { - extraWidth = (int) ((outlineViewWidth - totalColumnWidth) / cntMaxSizeColumns); - } else { - extraWidth = (int) ((outlineViewWidth - totalColumnWidth) / columnWidths.size()); - } - } - - for (int column = 0; column < columnWidths.size(); column++) { - int columnWidth = columnWidths.get(column); - - if (cntMaxSizeColumns > 0) { - if (columnWidth >= ((column == 0) ? 350 : 300)) { - columnWidth += extraWidth; - } - } else { - columnWidth += extraWidth; - } - - outline.getColumnModel().getColumn(column).setPreferredWidth(columnWidth); - } + // get header cell width + // taken in part from https://stackoverflow.com/a/18381924 + TableCellRenderer headerRenderer = tableColumn.getHeaderRenderer(); + if (headerRenderer == null) { + headerRenderer = outline.getTableHeader().getDefaultRenderer(); + } + Object headerValue = tableColumn.getHeaderValue(); + Component headerComp = headerRenderer.getTableCellRendererComponent(outline, headerValue, false, false, 0, columnIdx); + width = Math.max(headerComp.getPreferredSize().width + columnPadding, width); + + // get the max of row widths from the first SAMPLE_ROW_NUM rows + Component comp = null; + int rowCount = outline.getRowCount(); + for (int row = 0; row < Math.min(rowCount, SAMPLE_ROW_NUM); row++) { + TableCellRenderer renderer = outline.getCellRenderer(row, columnIdx); + comp = outline.prepareRenderer(renderer, row, columnIdx); + width = Math.max(comp.getPreferredSize().width + columnPadding, width); + } + + // no higher than maximum column width + if (width > MAX_COLUMN_WIDTH) { + width = MAX_COLUMN_WIDTH; + } + + // if last column, calculate remaining width factoring in the possibility of a scroll bar. + if (columnIdx == outline.getColumnCount() - 1) { + int rowHeight = comp == null ? MIN_ROW_HEIGHT : comp.getPreferredSize().height; + if (headerComp.getPreferredSize().height + rowCount * rowHeight > outlineView.getSize().getHeight()) { + availableTableWidth -= SCROLL_BAR_WIDTH; + } + + columnModel.getColumn(columnIdx).setPreferredWidth(Math.max(width, (int) availableTableWidth)); + } else { + // otherwise set preferred width to width and decrement availableTableWidth accordingly + columnModel.getColumn(columnIdx).setPreferredWidth(width); + availableTableWidth -= width; } - } else { - // if there's no content just auto resize all columns - outline.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); } } @@ -790,7 +735,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { * order. * * @return a List> of the properties in the persisted - * order. + * order. */ private synchronized List> loadColumnOrder() { @@ -1307,18 +1252,20 @@ public class DataResultViewerTable extends AbstractDataResultViewer { /** * Returns the icon denoted by the Score's Significance. + * * @param significance The Score's Significance. + * * @return The icon (or null) related to that significance. */ private ImageIcon getIcon(Significance significance) { if (significance == null) { return null; } - + switch (significance) { case NOTABLE: return NOTABLE_ICON_SCORE; - case LIKELY_NOTABLE: + case LIKELY_NOTABLE: return INTERESTING_SCORE_ICON; case LIKELY_NONE: case NONE: @@ -1327,7 +1274,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { return null; } } - + @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); From 9609c53e484cb120625d5cda384f27d93d8ac2de Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Mon, 14 Jun 2021 11:14:29 -0400 Subject: [PATCH 30/33] Updated a few more locations that were creating nodes sync --- .../autopsy/commonpropertiessearch/InstanceCountNode.java | 4 ++-- .../autopsy/datasourcesummary/ui/DataSourceSummaryNode.java | 5 ++--- .../autopsy/experimental/autoingest/AinStatusNode.java | 4 ++-- .../autopsy/experimental/autoingest/AutoIngestJobsNode.java | 4 ++-- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InstanceCountNode.java b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InstanceCountNode.java index 5be8f8bae2..628bec9291 100644 --- a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InstanceCountNode.java +++ b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InstanceCountNode.java @@ -2,7 +2,7 @@ * * Autopsy Forensic Browser * - * Copyright 2018-2019 Basis Technology Corp. + * Copyright 2018-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -60,7 +60,7 @@ public final class InstanceCountNode extends DisplayableItemNode { "InstanceCountNode.displayName=Exists in %s data sources (%s)" }) public InstanceCountNode(int instanceCount, CommonAttributeValueList attributeValues, CorrelationAttributeInstance.Type type) { - super(Children.create(new CommonAttributeValueNodeFactory(attributeValues.getMetadataList(), type), false)); + super(Children.create(new CommonAttributeValueNodeFactory(attributeValues.getMetadataList(), type), true)); this.type = type; this.instanceCount = instanceCount; this.attributeValues = attributeValues; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryNode.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryNode.java index a4c48e7adf..4aa3cf1be3 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,7 +30,6 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.datasourcesummary.ui.Bundle; import org.sleuthkit.autopsy.datamodel.NodeProperty; import org.sleuthkit.autopsy.directorytree.ViewContextAction; import org.sleuthkit.datamodel.DataSource; @@ -59,7 +58,7 @@ final class DataSourceSummaryNode extends AbstractNode { * DataSources which are this nodes children */ DataSourceSummaryNode(List dataSourceList) { - super(Children.create(new DataSourceSummaryChildren(dataSourceList), false)); + super(Children.create(new DataSourceSummaryChildren(dataSourceList), true)); } /** diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AinStatusNode.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AinStatusNode.java index 8c7ba7cdd9..9d72539841 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AinStatusNode.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AinStatusNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2018 Basis Technology Corp. + * Copyright 2018-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -40,7 +40,7 @@ final class AinStatusNode extends AbstractNode { * Construct a new AinStatusNode. */ AinStatusNode(AutoIngestMonitor monitor) { - super(Children.create(new AinStatusChildren(monitor), false)); + super(Children.create(new AinStatusChildren(monitor), true)); } /** diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java index ffe8e19f01..3142181117 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2018-2019 Basis Technology Corp. + * Copyright 2018-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -69,7 +69,7 @@ final class AutoIngestJobsNode extends AbstractNode { * refresh events */ AutoIngestJobsNode(AutoIngestMonitor monitor, AutoIngestJobStatus status, EventBus eventBus) { - super(Children.create(new AutoIngestNodeChildren(monitor, status, eventBus), false)); + super(Children.create(new AutoIngestNodeChildren(monitor, status, eventBus), true)); refreshChildrenEventBus = eventBus; } From b437454b34be5653686a4dc83c002eb90c17583f Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Mon, 14 Jun 2021 16:35:34 -0400 Subject: [PATCH 31/33] Removed unused import --- Core/src/org/sleuthkit/autopsy/datamodel/ContentChildren.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentChildren.java index ce8646563c..7b0987f623 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentChildren.java @@ -22,7 +22,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.logging.Level; -import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Directory; From 2a64c3029c291409b717c741ac2de1312055eeed Mon Sep 17 00:00:00 2001 From: apriestman Date: Mon, 14 Jun 2021 18:46:38 -0400 Subject: [PATCH 32/33] Restore line fetching new files --- .../modules/embeddedfileextractor/SevenZipExtractor.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index b7a5f6e545..6fa1e93c5a 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -808,6 +808,9 @@ class SevenZipExtractor { logger.log(Level.SEVERE, "Error populating complete derived file hierarchy from the unpacked dir structure", e); //NON-NLS //TODO decide if anything to cleanup, for now bailing } + + // Get the new files to be added to the case. + unpackedFiles = unpackedTree.getAllFileObjects(); } catch (SevenZipException | IllegalArgumentException ex) { logger.log(Level.WARNING, "Error unpacking file: " + archiveFile, ex); //NON-NLS From 64061c0fe70baa6fbcb5caf137eba59572d53f92 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 15 Jun 2021 12:11:44 -0400 Subject: [PATCH 33/33] Some HostNodes will be created syncronously --- Core/src/org/sleuthkit/autopsy/datamodel/HostNode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HostNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/HostNode.java index 4b11bf6777..1f349fdfc4 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HostNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HostNode.java @@ -222,7 +222,7 @@ public class HostNode extends DisplayableItemNode { * @param hostGrouping The HostGrouping key. */ HostNode(HostGrouping hostGrouping) { - this(Children.create(new HostGroupingChildren(HOST_GROUPING_CONVERTER, hostGrouping.getHost()), true), hostGrouping.getHost()); + this(Children.create(new HostGroupingChildren(HOST_GROUPING_CONVERTER, hostGrouping.getHost()), false), hostGrouping.getHost()); } /**