-
-
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java
index f37cccb028..bd3671e44b 100644
--- a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java
+++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java
@@ -20,16 +20,22 @@ 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;
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.EscapeUtil;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.datamodel.AbstractFile;
@@ -63,6 +69,7 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer {
public Metadata() {
initComponents();
customizeComponents();
+ ContentViewerHtmlStyles.setupHtmlJTextPane(jTextPane1);
}
/**
@@ -80,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);
@@ -116,30 +121,59 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer {
* selectAllMenuItem.addActionListener(actList);
*/
- Utilities.configureTextPaneAsHtml(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(""); //NON-NLS
- sb.append(key);
- sb.append(" | "); //NON-NLS
- sb.append(value);
- sb.append(" |
"); //NON-NLS
+ sb.append(MessageFormat.format("{2}: | {4} |
",
+ ContentViewerHtmlStyles.getKeyColumnClassName(),
+ ContentViewerHtmlStyles.getTextClassName(),
+ EscapeUtil.escapeHtml(key),
+ ContentViewerHtmlStyles.getTextClassName(),
+ EscapeUtil.escapeHtml(key)
+ ));
+ }
+
+ private void addMonospacedRow(StringBuilder sb, String key) {
+ sb.append(MessageFormat.format("{2} |
",
+ ContentViewerHtmlStyles.getKeyColumnClassName(),
+ ContentViewerHtmlStyles.getMonospacedClassName(),
+ EscapeUtil.escapeHtml(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, "", EscapeUtil.escapeHtml(line)));
}
@Messages({
+ "Metadata.headerTitle=Metadata",
"Metadata.tableRowTitle.mimeType=MIME Type",
"Metadata.nodeText.truncated=(results truncated)",
"Metadata.tableRowTitle.sha1=SHA1",
@@ -219,8 +253,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
}
@@ -240,11 +277,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() {
@@ -299,6 +334,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) {
@@ -357,30 +393,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) {
+ addMonospacedRow(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) {
+ addMonospacedRow(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());
@@ -419,20 +460,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.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 bf3c45d0f3..f365e8392e 100644
--- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java
@@ -18,20 +18,21 @@
*/
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;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.openide.util.NbBundle;
+import org.openide.util.NbBundle.Messages;
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.Content;
import org.sleuthkit.datamodel.Score;
/**
@@ -40,57 +41,19 @@ import org.sleuthkit.datamodel.Score;
public class AnalysisResultsContentPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
-
+
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);
}
/**
@@ -99,10 +62,11 @@ 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}
",
- MESSAGE_CLASSNAME,
- message == null ? "" : message)
+ + MessageFormat.format("{1}
",
+ ContentViewerHtmlStyles.getMessageClassName(),
+ message == null ? "" : EscapeUtil.escapeHtml(message))
+ "");
}
@@ -118,31 +82,26 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel {
*
* @param nodeResults The analysis results data to display.
*/
- @NbBundle.Messages("AnalysisResultsContentPanel_aggregateScore_displayKey=Aggregate Score")
void displayResults(NodeResults nodeResults) {
Document document = Jsoup.parse(EMPTY_HTML);
Element body = document.getElementsByTag("body").first();
- // if there is an aggregate score, append a section with the value
- Optional aggregateScore = nodeResults.getAggregateScore();
- if (aggregateScore.isPresent()) {
- appendSection(body,
- MessageFormat.format("{0}: {1}",
- Bundle.AnalysisResultsContentPanel_aggregateScore_displayKey(),
- aggregateScore.get().getSignificance().getDisplayName()),
- Optional.empty());
- }
+ Optional panelHeader = appendPanelHeader(body, nodeResults.getContent(), nodeResults.getAggregateScore());
// for each analysis result item, display the data.
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 || panelHeader.isPresent()) {
+ sectionDiv.attr("class", ContentViewerHtmlStyles.getSpacedSectionClassName());
+ }
}
// 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()) {
@@ -153,34 +112,80 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel {
}
}
+ /**
+ * Appends the header to the panel.
+ *
+ * @param parent The parent html element.
+ * @param content The content whose name will be added if present.
+ * @param score The aggregate score whose significance will be added if
+ * present.
+ *
+ * @return The html element.
+ */
+ @Messages({
+ "AnalysisResultsContentPanel_aggregateScore_displayKey=Aggregate Score",
+ "AnalysisResultsContentPanel_content_displayKey=Item"
+ })
+ private Optional appendPanelHeader(Element parent, Optional content, Optional score) {
+ if (!content.isPresent() || !score.isPresent()) {
+ return Optional.empty();
+ }
+
+ Element container = parent.appendElement("div");
+
+ // if there is content append the name
+ content.ifPresent((c) -> {
+ container.appendElement("p")
+ .attr("class", ContentViewerHtmlStyles.getTextClassName())
+ .text(MessageFormat.format("{0}: {1}",
+ Bundle.AnalysisResultsContentPanel_content_displayKey(),
+ c.getName()));
+ });
+
+ // if there is an aggregate score, append the value
+ score.ifPresent((s) -> {
+ container.appendElement("p")
+ .attr("class", ContentViewerHtmlStyles.getTextClassName())
+ .text(MessageFormat.format("{0}: {1}",
+ Bundle.AnalysisResultsContentPanel_aggregateScore_displayKey(),
+ s.getSignificance().getDisplayName()));
+ });
+
+ return Optional.ofNullable(container);
+ }
+
/**
* 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",
"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),
Optional.ofNullable(getAnchor(attrs.getAnalysisResult())));
-
+
// create a table
Element table = sectionDiv.appendElement("table");
- table.attr("class", SUBSECTION_CLASSNAME);
+ table.attr("class", ContentViewerHtmlStyles.getIndentedClassName());
Element tableBody = table.appendElement("tbody");
@@ -188,15 +193,20 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel {
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", TD_CLASSNAME);
+ .attr("class", ContentViewerHtmlStyles.getKeyColumnClassName());
String valueString = keyVal.getValue() == null ? "" : keyVal.getValue();
row.appendElement("td")
.text(valueString)
- .attr("class", TD_CLASSNAME);
+ .attr("class", ContentViewerHtmlStyles.getTextClassName());
}
+
+ return sectionDiv;
}
/**
@@ -210,21 +220,25 @@ 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()) {
- 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;
}
@@ -244,7 +258,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/analysisresults/AnalysisResultsViewModel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java
index 8ba7308eb4..00cc170b14 100644
--- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java
+++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java
@@ -94,6 +94,7 @@ public class AnalysisResultsViewModel {
private final List analysisResults;
private final Optional selectedResult;
private final Optional aggregateScore;
+ private final Optional content;
/**
* Constructor.
@@ -102,11 +103,13 @@ public class AnalysisResultsViewModel {
* @param selectedResult The selected analysis result or empty if none
* selected.
* @param aggregateScore The aggregate score or empty if no score.
+ * @param content The content associated with these results.
*/
- NodeResults(List analysisResults, Optional selectedResult, Optional aggregateScore) {
+ NodeResults(List analysisResults, Optional selectedResult, Optional aggregateScore, Optional content) {
this.analysisResults = analysisResults;
this.selectedResult = selectedResult;
this.aggregateScore = aggregateScore;
+ this.content = content;
}
/**
@@ -135,6 +138,17 @@ public class AnalysisResultsViewModel {
Optional getAggregateScore() {
return aggregateScore;
}
+
+ /**
+ * Returns the content associated with these results or empty if not
+ * present.
+ *
+ * @return The content associated with these results or empty if not
+ * present.
+ */
+ Optional getContent() {
+ return content;
+ }
}
/**
@@ -221,10 +235,11 @@ public class AnalysisResultsViewModel {
*/
NodeResults getAnalysisResults(Node node) {
if (node == null) {
- return new NodeResults(Collections.emptyList(), Optional.empty(), Optional.empty());
+ return new NodeResults(Collections.emptyList(), Optional.empty(), Optional.empty(), Optional.empty());
}
Optional aggregateScore = Optional.empty();
+ Optional nodeContent = Optional.empty();
// maps id of analysis result to analysis result to prevent duplication
Map allAnalysisResults = new HashMap<>();
Optional selectedResult = Optional.empty();
@@ -236,6 +251,8 @@ public class AnalysisResultsViewModel {
}
try {
+ nodeContent = Optional.of(content);
+
// get the aggregate score of that content
aggregateScore = Optional.ofNullable(content.getAggregateScore());
@@ -273,6 +290,6 @@ public class AnalysisResultsViewModel {
// get view model representation
List displayAttributes = getOrderedDisplayAttributes(allAnalysisResults.values());
- return new NodeResults(displayAttributes, selectedResult, aggregateScore);
+ return new NodeResults(displayAttributes, selectedResult, aggregateScore, nodeContent);
}
}
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 extends T> 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/artifactviewers/CallLogArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java
index 8d27c6c5be..0830e8e6ef 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");
@@ -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;
@@ -30,11 +31,13 @@ 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;
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;
@@ -75,6 +78,7 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac
*/
public CallLogArtifactViewer() {
initComponents();
+ this.setBorder(new EmptyBorder(ContentViewerDefaults.getPanelInsets()));
}
/**
@@ -93,29 +97,28 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac
public void setArtifact(BlackboardArtifact artifact) {
resetComponent();
- if (artifact == null) {
- return;
- }
-
CallLogViewData callLogViewData = null;
try {
callLogViewData = getCallLogViewData(artifact);
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, String.format("Error getting attributes for Calllog artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex);
}
-
+ List personaSearchDataList = new ArrayList<>();
// update the view with the call log data
if (callLogViewData != null) {
- List personaSearchDataList = updateView(callLogViewData);
- if (!personaSearchDataList.isEmpty()) {
- currentAccountFetcher = new PersonaAccountFetcher(artifact, personaSearchDataList, this);
- currentAccountFetcher.execute();
- } else {
- currentAccountFetcher = null;
- }
+ personaSearchDataList.addAll(updateView(callLogViewData));
+
}
+ if (!personaSearchDataList.isEmpty()) {
+ currentAccountFetcher = new PersonaAccountFetcher(artifact, personaSearchDataList, this);
+ currentAccountFetcher.execute();
+ } else {
+ currentAccountFetcher = null;
+ }
+
// repaint
this.revalidate();
+ this.repaint();
}
/**
@@ -309,13 +312,13 @@ 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
if (callLogViewData.getFromAccount() != null) {
CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_label_from());
-
+
// check if this is local account
String accountDisplayString = getAccountDisplayString(callLogViewData.getFromAccount(), callLogViewData);
CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, accountDisplayString);
@@ -366,8 +369,6 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac
this.setLayout(m_gridBagLayout);
this.revalidate();
- this.repaint();
-
return dataList;
}
@@ -384,7 +385,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) {
@@ -414,7 +415,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());
}
@@ -432,7 +433,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());
@@ -444,9 +445,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 +505,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..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");
@@ -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
*/
@@ -64,34 +62,34 @@ 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;
// 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.LINE_START;
+ constraints.fill = GridBagConstraints.NONE;
+
+ 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(headingLabel.getFont().deriveFont(Font.BOLD, headingLabel.getFont().getSize() + 2));
+ headingLabel.setFont(ContentViewerDefaults.getHeaderFont());
// add to panel
gridbagLayout.setConstraints(headingLabel, constraints);
@@ -159,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);
@@ -181,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;
@@ -197,24 +196,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.
*
@@ -247,9 +228,12 @@ final class CommunicationArtifactViewerHelper {
constraints.gridy++;
constraints.gridx = gridx < MAX_COLS - 1 ? gridx : MAX_COLS - 2;
+ 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);
@@ -288,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;
@@ -295,7 +280,8 @@ final class CommunicationArtifactViewerHelper {
// let the value span 2 cols
cloneConstraints.gridwidth = 2;
- cloneConstraints.fill = GridBagConstraints.BOTH;
+ constraints.anchor = GridBagConstraints.LINE_START;
+ 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,33 @@ 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;
+ 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
gridbagLayout.setConstraints(messageLabel, constraints);
@@ -406,8 +399,9 @@ 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);
+ constraints.anchor = GridBagConstraints.LINE_START;
+
// create label
javax.swing.JLabel personaLabel = new javax.swing.JLabel();
String personaLabelText = Bundle.CommunicationArtifactViewerHelper_persona_label();
@@ -415,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 = savedInsets;
-
constraints.gridx++;
// Place a button as place holder. It will be enabled when persona is available.
@@ -441,6 +432,9 @@ final class CommunicationArtifactViewerHelper {
} else {
personaLabel.setEnabled(false);
}
+
+ // restore constraint
+ constraints.insets = savedInsets;
addLineEndGlue(panel, gridbagLayout, constraints);
@@ -469,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 * LEFT_INSET, 0, 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 b17263a26d..2b583ff000 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");
@@ -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;
@@ -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;
@@ -107,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));
}
@@ -129,19 +130,15 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
// Reset the panel.
resetComponent();
- if (artifact == null) {
- return;
+ if (artifact != null) {
+ try {
+ extractArtifactData(artifact);
+ } catch (TskCoreException ex) {
+ logger.log(Level.SEVERE, String.format("Error getting attributes for artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex);
+ return;
+ }
+ updateView();
}
-
- try {
- extractArtifactData(artifact);
- } catch (TskCoreException ex) {
- logger.log(Level.SEVERE, String.format("Error getting attributes for artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex);
- return;
- }
-
- updateView();
-
this.setLayout(this.m_gridBagLayout);
this.revalidate();
this.repaint();
@@ -163,6 +160,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
* Extracts data from the artifact to be displayed in the panel.
*
* @param artifact Artifact to show.
+ *
* @throws TskCoreException
*/
private void extractArtifactData(BlackboardArtifact artifact) throws TskCoreException {
@@ -234,7 +232,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
/**
* Updates the contact image in the view.
*
- * @param contactPanelLayout Panel layout.
+ * @param contactPanelLayout Panel layout.
* @param contactPanelConstraints Layout constraints.
*
*/
@@ -245,8 +243,11 @@ 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);
+ 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());
@@ -256,13 +257,14 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
CommunicationArtifactViewerHelper.addLineEndGlue(this, contactPanelLayout, contactPanelConstraints);
contactPanelConstraints.gridy++;
+ contactPanelConstraints.gridwidth = prevGridWidth;
contactPanelConstraints.insets = savedInsets;
}
/**
* Updates the contact name in the view.
*
- * @param contactPanelLayout Panel layout.
+ * @param contactPanelLayout Panel layout.
* @param contactPanelConstraints Layout constraints.
*
*/
@@ -275,13 +277,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());
}
}
@@ -289,9 +291,9 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
* Updates the view by displaying the given list of attributes in the given
* section panel.
*
- * @param sectionAttributesList List of attributes to display.
- * @param sectionHeader Section name label.
- * @param contactPanelLayout Panel layout.
+ * @param sectionAttributesList List of attributes to display.
+ * @param sectionHeader Section name label.
+ * @param contactPanelLayout Panel layout.
* @param contactPanelConstraints Layout constraints.
*
*/
@@ -302,7 +304,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());
@@ -316,7 +318,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);
}
@@ -335,7 +337,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++;
@@ -346,8 +348,10 @@ 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;
+ m_constraints.anchor = GridBagConstraints.LINE_START;
CommunicationArtifactViewerHelper.addComponent(this, m_gridBagLayout, m_constraints, personaSearchStatusLabel);
@@ -359,9 +363,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);
@@ -412,12 +415,12 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
/**
* Displays the given persona in the persona panel.
*
- * @param persona Persona to display.
- * @param matchNumber Number of matches.
+ * @param persona Persona to display.
+ * @param matchNumber Number of matches.
* @param missingAccountsList List of contact accounts this persona may be
- * missing.
- * @param gridBagLayout Layout to use.
- * @param constraints layout constraints.
+ * missing.
+ * @param gridBagLayout Layout to use.
+ * @param constraints layout constraints.
*
* @throws CentralRepoException
*/
@@ -435,12 +438,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 * CommunicationArtifactViewerHelper.LEFT_INSET, 0, 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();
@@ -461,6 +461,8 @@ 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);
@@ -474,6 +476,8 @@ 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);
@@ -488,7 +492,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;
@@ -501,7 +506,6 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
constraints.gridy++;
// this needs an extra indent
- constraints.insets = extraIndentInsets;
CommunicationArtifactViewerHelper.addKeyAtCol(this, gridBagLayout, constraints, Bundle.ContactArtifactViewer_missing_account_label(), 1);
constraints.insets = savedInsets;
@@ -544,12 +548,12 @@ 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;
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;
}
@@ -560,7 +564,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
* @param artifact
*
* @return Image from a TSK_CONTACT artifact or default image if none was
- * found or the artifact is not a TSK_CONTACT
+ * found or the artifact is not a TSK_CONTACT
*/
private ImageIcon getImageFromArtifact(BlackboardArtifact artifact) {
ImageIcon imageIcon = defaultImage;
@@ -610,7 +614,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
* Creates a persona searcher task.
*
* @param accountAttributesList List of attributes that may map to
- * accounts.
+ * accounts.
*/
ContactPersonaSearcherTask(BlackboardArtifact artifact) {
this.artifact = artifact;
@@ -640,7 +644,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
}
}
}
-
+
Collection personaAccounts = PersonaAccount.getPersonaAccountsForAccount(account);
if (personaAccounts != null && !personaAccounts.isEmpty()) {
// get personas for the account
@@ -709,7 +713,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
/**
* Constructor.
*
- * @param personaNameLabel Persona name label.
+ * @param personaNameLabel Persona name label.
* @param personaActionButton Persona action button.
*/
PersonaUIComponents(JLabel personaNameLabel, JButton personaActionButton) {
@@ -777,8 +781,8 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
for (CentralRepoAccount account : contactUniqueAccountsList) {
personaPanel.addAccount(account, Bundle.ContactArtifactViewer_persona_account_justification(), Persona.Confidence.HIGH);
}
-
- if(contactName != null && contactUniqueAccountsList.isEmpty()) {
+
+ if (contactName != null && contactUniqueAccountsList.isEmpty()) {
createPersonaDialog.setStartupPopupMessage(Bundle.ContactArtifactViewer_id_not_found_in_cr(contactName));
}
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/GeneralPurposeArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/GeneralPurposeArtifactViewer.java
index d8150a91a2..e81b6705c6 100644
--- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/GeneralPurposeArtifactViewer.java
+++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/GeneralPurposeArtifactViewer.java
@@ -18,9 +18,9 @@
*/
package org.sleuthkit.autopsy.contentviewers.artifactviewers;
+import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
-import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
@@ -30,18 +30,24 @@ 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;
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 +61,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 ZERO_INSETS = new java.awt.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);
+
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;
@@ -91,6 +102,7 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i
initComponents();
gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START;
detailsPanel.setLayout(gridBagLayout);
+ detailsPanel.setBorder(new EmptyBorder(ContentViewerDefaults.getPanelInsets()));
}
/**
@@ -180,7 +192,7 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i
gridBagConstraints.weighty = 0.0;
gridBagConstraints.weightx = TEXT_WEIGHT_X; // keep components fixed horizontally.
gridBagConstraints.fill = GridBagConstraints.NONE;
- gridBagConstraints.insets = ROW_INSETS;
+ gridBagConstraints.insets = ZERO_INSETS;
}
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
@@ -386,29 +398,26 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i
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.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;
// 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());
+ headingLabel.setMargin(ZERO_INSETS);
// add to panel
addToPanel(headingLabel);
// reset constraints to normal
gridBagConstraints.gridwidth = LABEL_WIDTH;
// add line end glue
addLineEndGlue();
- gridBagConstraints.insets = ROW_INSETS;
+ gridBagConstraints.insets = ZERO_INSETS;
return headingLabel;
}
@@ -465,6 +474,7 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i
javax.swing.JLabel keyLabel = new javax.swing.JLabel();
keyLabel.setFocusable(false);
gridBagConstraints.gridy++;
+ gridBagConstraints.insets = KEY_COLUMN_INSETS;
gridBagConstraints.gridx = LABEL_COLUMN;
gridBagConstraints.gridwidth = LABEL_WIDTH;
// set text
@@ -492,7 +502,9 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i
valueField.setFocusable(false);
valueField.setEditable(false);
valueField.setOpaque(false);
+ 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;
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/MessageAccountPanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/MessageAccountPanel.java
index fbf1ada856..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");
@@ -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());
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 @@
@@ -137,11 +80,8 @@