diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties index 5bac74e842..6e75857c26 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties @@ -981,4 +981,3 @@ CallLogArtifactViewer.localAccountPersonaNameLabel.text=jLabel1 CallLogArtifactViewer.localAccountPersonaButton.text=jButton1 ContactArtifactViewer.personasLabel.text=Personas MessageArtifactViewer.accountsTab.TabConstraints.tabTitle=Accounts -ContactArtifactViewer.contactImage.text= diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java index 2e50bc8d47..8bb83660a1 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java @@ -35,6 +35,7 @@ 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.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -92,6 +93,10 @@ 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); @@ -335,8 +340,15 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac } updateMetadataView(callLogViewData); + + updateOtherAttributesView(callLogViewData); + updateSourceView(callLogViewData); + if (CentralRepository.isEnabled() == false) { + showCRDisabledMessage(); + } + CommunicationArtifactViewerHelper.addPageEndGlue(this, m_gridBagLayout, this.m_constraints); this.setLayout(m_gridBagLayout); @@ -394,6 +406,37 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, callLogViewData.getDataSourceName()); } + /** + * Update the other attributes section. + * + * @param callLogViewData Call log data. + */ + @NbBundle.Messages({ + "CallLogArtifactViewer_heading_others=Other Attributes" + }) + private void updateOtherAttributesView(CallLogViewData callLogViewData) { + + if (callLogViewData.getOtherAttributes().isEmpty()) { + return; + } + CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_heading_others()); + + for (Map.Entry entry : callLogViewData.getOtherAttributes().entrySet()) { + CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, entry.getKey()); + CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, entry.getValue()); + } + } + + @NbBundle.Messages({ + "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()); + m_constraints.gridy++; + } + /** * Returns display string for a account. Checks if the given account is the * local account, if it is known. If it is, it appends a "(Local)" suffix to @@ -421,7 +464,9 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac @Override public boolean isSupported(BlackboardArtifact artifact) { - return artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID(); + + return (artifact != null) + && (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()); } /** @@ -445,9 +490,9 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac m_constraints.anchor = GridBagConstraints.FIRST_LINE_START; m_constraints.gridy = 0; m_constraints.gridx = 0; - m_constraints.weighty = 0.05; - m_constraints.weightx = 0.05; - m_constraints.insets = new java.awt.Insets(0, 0, 0, 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.fill = GridBagConstraints.NONE; } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java b/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java index 9b17fc7262..2c6a013929 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.List; import javax.swing.JLabel; import javax.swing.JMenuItem; +import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; @@ -42,20 +43,20 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; * A class to help display a communication artifact in a panel using a * gridbaglayout. */ -public final class CommunicationArtifactViewerHelper { +final class CommunicationArtifactViewerHelper { // Number of columns in the gridbag layout. private final static int MAX_COLS = 4; - private final static int LEFT_INDENT = 12; - + final static int LEFT_INSET = 12; + /** * Empty private constructor */ private CommunicationArtifactViewerHelper() { } - + /** * Adds a new heading to the panel. * @@ -63,8 +64,15 @@ public final class CommunicationArtifactViewerHelper { * @param gridbagLayout Layout to use. * @param constraints Constrains to use. * @param headerString Heading string to display. + * + * @return JLabel Heading label added. */ - static void addHeader(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String headerString) { + static JLabel addHeader(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, 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 @@ -76,9 +84,9 @@ public final class CommunicationArtifactViewerHelper { // let the header span all of the row constraints.gridwidth = MAX_COLS; + constraints.insets = new Insets(0, 0, 0, 0); // No inset for header - // create label for heading - javax.swing.JLabel headingLabel = new javax.swing.JLabel(); + // set text headingLabel.setText(headerString); // make it large and bold @@ -93,6 +101,28 @@ public final class CommunicationArtifactViewerHelper { // add line end glue addLineEndGlue(panel, gridbagLayout, constraints); + + //restore insets + constraints.insets = savedInsets; + + return headingLabel; + } + + /** + * Adds the given component to the panel. + * + * Caller must know what it's doing and set up all the constraints properly. + * + * @param panel Panel to update. + * @param gridbagLayout Layout to use. + * @param constraints Constrains to use. + * @param component Component to add. + */ + static void addComponent(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, JComponent component) { + + // add to panel + gridbagLayout.setConstraints(component, constraints); + panel.add(component); } /** @@ -103,7 +133,7 @@ public final class CommunicationArtifactViewerHelper { * @param gridbagLayout Layout to use. * @param constraints Constrains to use. */ - private static void addLineEndGlue(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints) { + static void addLineEndGlue(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints) { // Place the filler just past the last column. constraints.gridx = MAX_COLS; @@ -156,7 +186,7 @@ public final class CommunicationArtifactViewerHelper { * @param gridbagLayout Layout to use. * @param constraints Constrains to use. */ - private static void addBlankLine(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints) { + static void addBlankLine(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints) { constraints.gridy++; constraints.gridx = 0; @@ -168,54 +198,85 @@ public final class CommunicationArtifactViewerHelper { } /** - * Adds a label/key to the panel. + * Adds a label/key to the panel at col 0. * * @param panel Panel to update. * @param gridbagLayout Layout to use. * @param constraints Constrains to use. * @param keyString Key name to display. + * + * @return Label added. */ - static void addKey(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String keyString) { + static JLabel addKey(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String keyString) { + return addKeyAtCol(panel, gridbagLayout, constraints, keyString, 0); + } + + /** + * Adds a label/key to the panel at specified column. + * + * @param panel Panel to update. + * @param gridbagLayout Layout to use. + * @param constraints Constrains to use. + * @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) { + + // create label + javax.swing.JLabel keyLabel = new javax.swing.JLabel(); constraints.gridy++; - constraints.gridx = 0; + constraints.gridx = gridx < MAX_COLS - 1 ? gridx : MAX_COLS - 2; - Insets savedInsets = constraints.insets; - - // Set inset to indent in - constraints.insets = new java.awt.Insets(0, LEFT_INDENT, 0, 0); - - // create label, - javax.swing.JLabel keyLabel = new javax.swing.JLabel(); + // set text keyLabel.setText(keyString + ": "); // add to panel gridbagLayout.setConstraints(keyLabel, constraints); panel.add(keyLabel); - // restore inset - constraints.insets = savedInsets; + return keyLabel; } /** - * Adds a value string to the panel. + * Adds a value string to the panel at col 1. * * @param panel Panel to update. * @param gridbagLayout Layout to use. * @param constraints Constrains to use. * @param keyString Value string to display. + * + * @return Label added. */ - static void addValue(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String valueString) { + static JLabel addValue(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String valueString) { + return addValueAtCol(panel, gridbagLayout, constraints, valueString, 1); + } - constraints.gridx = 1; + /** + * Adds a value string to the panel at specified column. + * + * @param panel Panel to update. + * @param gridbagLayout Layout to use. + * @param constraints Constrains to use. + * @param keyString Value string to display. + * @param gridx Column index, must be less than MAX_COLS; + * + * @return Label added. + */ + static JLabel addValueAtCol(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String valueString, int gridx) { + // create label, + javax.swing.JLabel valueField = new javax.swing.JLabel(); + + constraints.gridx = gridx < MAX_COLS ? gridx : MAX_COLS - 1; int savedGridwidth = constraints.gridwidth; // let the value span 2 cols constraints.gridwidth = 2; - // create label, - javax.swing.JLabel valueField = new javax.swing.JLabel(); + // set text valueField.setText(valueString); // attach a right click menu with Copy option @@ -235,6 +296,63 @@ public final class CommunicationArtifactViewerHelper { // end the line addLineEndGlue(panel, gridbagLayout, constraints); + + return valueField; + } + + /** + * Displays a message string, starting at column 0, and spanning the entire + * row. + * + * @param panel Panel to show. + * @param gridbagLayout Layout to use. + * @param constraints Constraints to use. + * + * @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); + } + + /** + * Displays a message string, starting at specified column, and spanning the + * entire row. + * + * @param panel Panel to show. + * @param gridbagLayout Layout to use. + * @param constraints Constraints to use. + * + * @param messageString Message to display. + * + * @return Label for message added. + */ + static JLabel addMessageRow(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, 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; + + int savedGridwidth = constraints.gridwidth; + + constraints.gridwidth = 3; + + // set text + messageLabel.setText(messageString); + + // add to panel + gridbagLayout.setConstraints(messageLabel, constraints); + panel.add(messageLabel); + + addLineEndGlue(panel, gridbagLayout, constraints); + + // restore constraints + constraints.gridwidth = savedGridwidth; + + return messageLabel; } /** @@ -269,8 +387,8 @@ public final class CommunicationArtifactViewerHelper { Insets savedInsets = constraints.insets; - // Indent in - constraints.insets = new java.awt.Insets(0, LEFT_INDENT, 0, 0); + // extra Indent in + constraints.insets = new java.awt.Insets(0, 2 * LEFT_INSET, 0, 0); // create label javax.swing.JLabel personaLabel = new javax.swing.JLabel(); @@ -293,8 +411,8 @@ public final class CommunicationArtifactViewerHelper { // Place a button as place holder. It will be enabled when persona is available. javax.swing.JButton personaButton = new javax.swing.JButton(); personaButton.setText(Bundle.CommunicationArtifactViewerHelper_persona_button_view()); + personaButton.setMargin(new Insets(0, 5, 0, 5)); personaButton.setEnabled(false); - gridbagLayout.setConstraints(personaButton, constraints); panel.add(personaButton); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.form index 467d3ae72d..806a0e3de5 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.form @@ -1,6 +1,9 @@ -
+ + + + @@ -11,217 +14,8 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java index 2d11fcf853..72997e9ede 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java @@ -19,9 +19,9 @@ package org.sleuthkit.autopsy.contentviewers; import java.awt.Component; -import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; +import java.awt.Insets; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.io.File; @@ -40,11 +40,11 @@ import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JLabel; -import javax.swing.JPanel; import javax.swing.JScrollPane; -import org.openide.util.lookup.ServiceProvider; import javax.swing.SwingWorker; +import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle; +import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; @@ -70,11 +70,23 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac private final static Logger logger = Logger.getLogger(ContactArtifactViewer.class.getName()); private static final long serialVersionUID = 1L; - private static final int TOP_INSET = 4; - private static final int LEFT_INSET = 12; + private GridBagLayout m_gridBagLayout = new GridBagLayout(); + private GridBagConstraints m_constraints = new GridBagConstraints(); - // contact name, if available. + private JLabel personaSearchStatusLabel; + + private BlackboardArtifact contactArtifact; private String contactName; + private String datasourceName; + + private List phoneNumList = new ArrayList<>(); + private List emailList = new ArrayList<>(); + private List nameList = new ArrayList<>(); + private List otherList = new ArrayList<>(); + private List accountAttributesList = new ArrayList<>(); + + private final static String DEFAULT_IMAGE_PATH = "/org/sleuthkit/autopsy/images/defaultContact.png"; + private final ImageIcon defaultImage; // A list of unique accounts matching the attributes of the contact artifact. private final List contactUniqueAccountsList = new ArrayList<>(); @@ -83,11 +95,10 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac // account identifier attributes of the Contact artifact. private final Map> contactUniquePersonasMap = new HashMap<>(); - private final static String DEFAULT_IMAGE_PATH = "/org/sleuthkit/autopsy/images/defaultContact.png"; - private final ImageIcon defaultImage; + private ContactPersonaSearcherTask personaSearchTask; /** - * Creates new form for ContactArtifactViewer + * Creates new form ContactArtifactViewer */ public ContactArtifactViewer() { initComponents(); @@ -103,164 +114,13 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { - java.awt.GridBagConstraints gridBagConstraints; - - namePanel = new javax.swing.JPanel(); - contactNameLabel = new javax.swing.JLabel(); - phonesLabel = new javax.swing.JLabel(); - phoneNumbersPanel = new javax.swing.JPanel(); - emailsLabel = new javax.swing.JLabel(); - emailsPanel = new javax.swing.JPanel(); - othersLabel = new javax.swing.JLabel(); - otherAttrsPanel = new javax.swing.JPanel(); - javax.swing.Box.Filler interPanelfiller = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767)); - personasLabel = new javax.swing.JLabel(); - personasPanel = new javax.swing.JPanel(); - javax.swing.Box.Filler bottomFiller = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767)); - javax.swing.Box.Filler rightFiller = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0)); - contactImage = new javax.swing.JLabel(); + setToolTipText(""); // NOI18N setLayout(new java.awt.GridBagLayout()); - - namePanel.setLayout(new java.awt.GridBagLayout()); - - contactNameLabel.setFont(contactNameLabel.getFont().deriveFont((contactNameLabel.getFont().getStyle() | java.awt.Font.ITALIC) | java.awt.Font.BOLD, contactNameLabel.getFont().getSize()+6)); - org.openide.awt.Mnemonics.setLocalizedText(contactNameLabel, org.openide.util.NbBundle.getMessage(ContactArtifactViewer.class, "ContactArtifactViewer.contactNameLabel.text")); // NOI18N - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 0; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.ipadx = 111; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.weightx = 1.0; - namePanel.add(contactNameLabel, gridBagConstraints); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 1; - gridBagConstraints.gridwidth = 5; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.weightx = 1.0; - gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0); - add(namePanel, gridBagConstraints); - - phonesLabel.setFont(phonesLabel.getFont().deriveFont(phonesLabel.getFont().getStyle() | java.awt.Font.BOLD, phonesLabel.getFont().getSize()+2)); - org.openide.awt.Mnemonics.setLocalizedText(phonesLabel, org.openide.util.NbBundle.getMessage(ContactArtifactViewer.class, "ContactArtifactViewer.phonesLabel.text")); // NOI18N - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 2; - gridBagConstraints.gridwidth = 3; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0); - add(phonesLabel, gridBagConstraints); - - phoneNumbersPanel.setLayout(new java.awt.GridBagLayout()); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 3; - gridBagConstraints.gridwidth = 4; - gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0); - add(phoneNumbersPanel, gridBagConstraints); - - emailsLabel.setFont(emailsLabel.getFont().deriveFont(emailsLabel.getFont().getStyle() | java.awt.Font.BOLD, emailsLabel.getFont().getSize()+2)); - org.openide.awt.Mnemonics.setLocalizedText(emailsLabel, org.openide.util.NbBundle.getMessage(ContactArtifactViewer.class, "ContactArtifactViewer.emailsLabel.text")); // NOI18N - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 4; - gridBagConstraints.gridwidth = 2; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0); - add(emailsLabel, gridBagConstraints); - - emailsPanel.setLayout(new java.awt.GridBagLayout()); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 5; - gridBagConstraints.gridwidth = 4; - gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0); - add(emailsPanel, gridBagConstraints); - - othersLabel.setFont(othersLabel.getFont().deriveFont(othersLabel.getFont().getStyle() | java.awt.Font.BOLD, othersLabel.getFont().getSize()+2)); - org.openide.awt.Mnemonics.setLocalizedText(othersLabel, org.openide.util.NbBundle.getMessage(ContactArtifactViewer.class, "ContactArtifactViewer.othersLabel.text")); // NOI18N - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 6; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0); - add(othersLabel, gridBagConstraints); - - otherAttrsPanel.setLayout(new java.awt.GridBagLayout()); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 7; - gridBagConstraints.gridwidth = 4; - gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0); - add(otherAttrsPanel, gridBagConstraints); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 8; - gridBagConstraints.gridheight = 2; - gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL; - gridBagConstraints.weighty = 0.1; - add(interPanelfiller, gridBagConstraints); - - personasLabel.setFont(personasLabel.getFont().deriveFont(personasLabel.getFont().getStyle() | java.awt.Font.BOLD, personasLabel.getFont().getSize()+2)); - org.openide.awt.Mnemonics.setLocalizedText(personasLabel, org.openide.util.NbBundle.getMessage(ContactArtifactViewer.class, "ContactArtifactViewer.personasLabel.text")); // NOI18N - personasLabel.setMaximumSize(new java.awt.Dimension(90, 19)); - personasLabel.setMinimumSize(new java.awt.Dimension(90, 19)); - personasLabel.setPreferredSize(new java.awt.Dimension(90, 19)); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 9; - gridBagConstraints.gridwidth = 3; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0); - add(personasLabel, gridBagConstraints); - - personasPanel.setLayout(new java.awt.GridBagLayout()); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 10; - gridBagConstraints.gridwidth = 4; - gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0); - add(personasPanel, gridBagConstraints); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 11; - gridBagConstraints.gridwidth = 4; - gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; - gridBagConstraints.weighty = 1.0; - add(bottomFiller, gridBagConstraints); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 4; - gridBagConstraints.gridy = 3; - gridBagConstraints.gridheight = 8; - gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; - gridBagConstraints.ipadx = 2; - gridBagConstraints.weightx = 1.0; - add(rightFiller, gridBagConstraints); - - contactImage.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/defaultContact.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(contactImage, org.openide.util.NbBundle.getMessage(ContactArtifactViewer.class, "ContactArtifactViewer.contactImage.text")); // NOI18N - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 0; - gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0); - add(contactImage, gridBagConstraints); }// //GEN-END:initComponents @Override public void setArtifact(BlackboardArtifact artifact) { - // Reset the panel. resetComponent(); @@ -268,50 +128,16 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac return; } - List phoneNumList = new ArrayList<>(); - List emailList = new ArrayList<>(); - List nameList = new ArrayList<>(); - List otherList = new ArrayList<>(); - List accountAttributesList = new ArrayList<>(); - try { - // Get all the attributes and group them by the section panels they go in - for (BlackboardAttribute bba : artifact.getAttributes()) { - if (bba.getAttributeType().getTypeName().startsWith("TSK_PHONE")) { - phoneNumList.add(bba); - accountAttributesList.add(bba); - } else if (bba.getAttributeType().getTypeName().startsWith("TSK_EMAIL")) { - emailList.add(bba); - accountAttributesList.add(bba); - } else if (bba.getAttributeType().getTypeName().startsWith("TSK_NAME")) { - nameList.add(bba); - } else { - otherList.add(bba); - if (bba.getAttributeType().getTypeName().equalsIgnoreCase("TSK_ID")) { - accountAttributesList.add(bba); - } - } - } + 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); - } - // update name section - updateNamePanel(nameList); - - // update contact attributes sections - updateSection(phoneNumList, this.phonesLabel, this.phoneNumbersPanel); - updateSection(emailList, this.emailsLabel, this.emailsPanel); - updateSection(otherList, this.othersLabel, this.otherAttrsPanel); - - try { - initiatePersonasSearch(accountAttributesList); - } catch (CentralRepoException ex) { - logger.log(Level.SEVERE, String.format("Error getting Personas for Contact artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex); + return; } - contactImage.setIcon(getImageFromArtifact(artifact)); + updateView(); - // repaint + this.setLayout(this.m_gridBagLayout); this.revalidate(); this.repaint(); } @@ -322,204 +148,254 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac return new JScrollPane(this, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); } - /** - * Checks if the given artifact is supported by this viewer. This viewer - * supports TSK_CONTACT artifacts. - * - * @param artifact artifact to check. - * - * @return True if the artifact is supported, false otherwise. - */ @Override public boolean isSupported(BlackboardArtifact artifact) { - return artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID(); + return (artifact != null) + && (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID()); } /** - * Clears all artifact specific state. + * Extracts data from the artifact to be displayed in the panel. + * + * @param artifact Artifact to show. + * @throws TskCoreException */ - private void resetComponent() { - contactNameLabel.setVisible(false); - emailsLabel.setVisible(false); - emailsPanel.removeAll(); - //namePanel.removeAll(); // this is not dynamically populated, do not remove. - otherAttrsPanel.removeAll(); - othersLabel.setVisible(false); - personasLabel.setVisible(false); - personasPanel.removeAll(); - phoneNumbersPanel.removeAll(); - phonesLabel.setVisible(false); + private void extractArtifactData(BlackboardArtifact artifact) throws TskCoreException { - contactName = null; - contactUniqueAccountsList.clear(); - contactUniquePersonasMap.clear(); - contactImage.setIcon(defaultImage); + this.contactArtifact = artifact; + + phoneNumList = new ArrayList<>(); + emailList = new ArrayList<>(); + nameList = new ArrayList<>(); + otherList = new ArrayList<>(); + accountAttributesList = new ArrayList<>(); + + // Get all the attributes and group them by the section panels they go in + for (BlackboardAttribute bba : contactArtifact.getAttributes()) { + if (bba.getAttributeType().getTypeName().startsWith("TSK_PHONE")) { + phoneNumList.add(bba); + accountAttributesList.add(bba); + } else if (bba.getAttributeType().getTypeName().startsWith("TSK_EMAIL")) { + emailList.add(bba); + accountAttributesList.add(bba); + } else if (bba.getAttributeType().getTypeName().startsWith("TSK_NAME")) { + nameList.add(bba); + } else { + otherList.add(bba); + if (bba.getAttributeType().getTypeName().equalsIgnoreCase("TSK_ID")) { + accountAttributesList.add(bba); + } + } + } + + datasourceName = contactArtifact.getDataSource().getName(); + } + + /** + * Updates the view with the data extracted from the artifact. + */ + private void updateView() { + + // Update contact name, image, phone numbers + updateContactDetails(); + + // update artifact source panel + updateSource(); + + // show a empty Personas panel and kick off a serch for personas + initiatePersonasSearch(); + + } + + /** + * Updates the view with contact's details. + */ + @NbBundle.Messages({ + "ContactArtifactViewer_phones_header=Phone", + "ContactArtifactViewer_emails_header=Email", + "ContactArtifactViewer_others_header=Other",}) + private void updateContactDetails() { + + // update image and name. + updateContactImage(m_gridBagLayout, m_constraints); + updateContactName(m_gridBagLayout, m_constraints); + + // update contact attributes sections + updateContactMethodSection(phoneNumList, Bundle.ContactArtifactViewer_phones_header(), m_gridBagLayout, m_constraints); + updateContactMethodSection(emailList, Bundle.ContactArtifactViewer_emails_header(), m_gridBagLayout, m_constraints); + updateContactMethodSection(otherList, Bundle.ContactArtifactViewer_others_header(), m_gridBagLayout, m_constraints); + } + + /** + * Updates the contact image in the view. + * + * @param contactPanelLayout Panel layout. + * @param contactPanelConstraints Layout constraints. + * + */ + @NbBundle.Messages({ + "ContactArtifactViewer.contactImage.text=",}) + private void updateContactImage(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) { + // place the image on the top right corner + Insets savedInsets = contactPanelConstraints.insets; + contactPanelConstraints.gridy = 0; + contactPanelConstraints.gridx = 0; + contactPanelConstraints.insets = new Insets(0, 0, 0, 0); + + javax.swing.JLabel contactImage = new javax.swing.JLabel(); + contactImage.setIcon(getImageFromArtifact(contactArtifact)); + contactImage.setText(Bundle.ContactArtifactViewer_contactImage_text()); + + // add image to top left corner of the page. + CommunicationArtifactViewerHelper.addComponent(this, contactPanelLayout, contactPanelConstraints, contactImage); + CommunicationArtifactViewerHelper.addLineEndGlue(this, contactPanelLayout, contactPanelConstraints); + contactPanelConstraints.gridy++; + + contactPanelConstraints.insets = savedInsets; } /** * Updates the contact name in the view. * - * @param attributesList + * @param contactPanelLayout Panel layout. + * @param contactPanelConstraints Layout constraints. + * */ - private void updateNamePanel(List attributesList) { - for (BlackboardAttribute bba : attributesList) { - if (bba.getAttributeType().getTypeName().startsWith("TSK_NAME")) { + @NbBundle.Messages({ + "ContactArtifactViewer_contactname_unknown=Unknown",}) + private void updateContactName(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) { + + boolean foundName = false; + for (BlackboardAttribute bba : this.nameList) { + if (StringUtils.isEmpty(bba.getValueString()) == false) { contactName = bba.getDisplayString(); - contactNameLabel.setText(contactName); - contactNameLabel.setVisible(true); + + CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, contactName); + foundName = true; break; } } - - contactNameLabel.revalidate(); + if (foundName == false) { + CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, Bundle.ContactArtifactViewer_contactname_unknown()); + } } /** * Updates the view by displaying the given list of attributes in the given * section panel. * - * @param sectionAttributesList list of attributes to display. - * @param sectionLabel section name label. - * @param sectionPanel section panel to display the attributes in. + * @param sectionAttributesList List of attributes to display. + * @param sectionLabel Section name label. + * @param contactPanelLayout Panel layout. + * @param contactPanelConstraints Layout constraints. + * */ - private void updateSection(List sectionAttributesList, JLabel sectionLabel, JPanel sectionPanel) { + @NbBundle.Messages({ + "ContactArtifactViewer_plural_suffix=s",}) + private void updateContactMethodSection(List sectionAttributesList, String sectionHeader, GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) { - // If there are no attributes for tis section, hide the section panel and the section label + // If there are no attributes for this section, do nothing if (sectionAttributesList.isEmpty()) { - sectionLabel.setVisible(false); - sectionPanel.setVisible(false); return; } - // create a gridbag layout to show each attribute on one line - GridBagLayout gridBagLayout = new GridBagLayout(); - GridBagConstraints constraints = new GridBagConstraints(); - constraints.anchor = GridBagConstraints.FIRST_LINE_START; - constraints.gridy = 0; - constraints.insets = new java.awt.Insets(TOP_INSET, LEFT_INSET, 0, 0); - for (BlackboardAttribute bba : sectionAttributesList) { - constraints.fill = GridBagConstraints.NONE; - constraints.weightx = 0; - - constraints.gridx = 0; - - // Add a label for attribute type - javax.swing.JLabel attrTypeLabel = new javax.swing.JLabel(); - String attrLabel = bba.getAttributeType().getDisplayName(); - attrTypeLabel.setText(attrLabel); - - // make type label bold - uncomment if needed. - //attrTypeLabel.setFont(attrTypeLabel.getFont().deriveFont(Font.BOLD, attrTypeLabel.getFont().getSize() )); - gridBagLayout.setConstraints(attrTypeLabel, constraints); - sectionPanel.add(attrTypeLabel); - - // Add the attribute value - constraints.gridx++; - javax.swing.JLabel attrValueLabel = new javax.swing.JLabel(); - attrValueLabel.setText(bba.getValueString()); - gridBagLayout.setConstraints(attrValueLabel, constraints); - sectionPanel.add(attrValueLabel); - - // add a filler to take up rest of the space - constraints.gridx++; - constraints.weightx = 1.0; - constraints.fill = GridBagConstraints.HORIZONTAL; - sectionPanel.add(new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0))); - - constraints.gridy++; + String sectionHeaderString = sectionHeader; + if (sectionAttributesList.size() > 1) { + sectionHeaderString = sectionHeaderString.concat(Bundle.ContactArtifactViewer_plural_suffix()); + } + CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, sectionHeaderString); + for (BlackboardAttribute bba : sectionAttributesList) { + CommunicationArtifactViewerHelper.addKey(this, contactPanelLayout, contactPanelConstraints, bba.getAttributeType().getDisplayName()); + CommunicationArtifactViewerHelper.addValue(this, contactPanelLayout, contactPanelConstraints, bba.getDisplayString()); } - - sectionLabel.setVisible(true); - sectionPanel.setVisible(true); - - sectionPanel.setLayout(gridBagLayout); - sectionPanel.revalidate(); - sectionPanel.repaint(); } /** - * Kicks off a search for personas, based in the list of attributes. + * Updates the source section. + */ + @NbBundle.Messages({ + "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.addKey(this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_label_datasource()); + CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, m_constraints, datasourceName); + } + + /** + * Kicks off a search for personas, based in the given list of attributes. * * @param accountAttributesList a list of account identifying attributes. * * @throws CentralRepoException */ @NbBundle.Messages({ - "ContactArtifactViewer_persona_searching= Searching...", + "ContactArtifactViewer_persona_header=Persona", + "ContactArtifactViewer_persona_searching=Searching...", + "ContactArtifactViewer_cr_disabled_message=Enable Central Repository to view, create and edit personas.", "ContactArtifactViewer_persona_unknown=Unknown" }) - private void initiatePersonasSearch(List accountAttributesList) throws CentralRepoException { - personasLabel.setVisible(true); + /** + * Initiates a search for Personas for the accounts associated with the + * Contact. + * + */ + private void initiatePersonasSearch() { - String personaStatusLabelText = CentralRepository.isEnabled() - ? Bundle.ContactArtifactViewer_persona_searching() + // add a section header + JLabel personaHeader = CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_persona_header()); + + m_constraints.gridy++; + + // add a status label + String personaStatusLabelText = CentralRepository.isEnabled() + ? Bundle.ContactArtifactViewer_persona_searching() : Bundle.ContactArtifactViewer_persona_unknown(); - - // create a gridbag layout to show each participant on one line - GridBagLayout gridBagLayout = new GridBagLayout(); - GridBagConstraints constraints = new GridBagConstraints(); - constraints.anchor = GridBagConstraints.FIRST_LINE_START; - constraints.gridx = 0; - constraints.gridy = 0; - constraints.insets = new java.awt.Insets(TOP_INSET, LEFT_INSET, 0, 0); - // Add a Persona Name label - constraints.fill = GridBagConstraints.NONE; - constraints.weightx = 0; + this.personaSearchStatusLabel = new javax.swing.JLabel(); + personaSearchStatusLabel.setText(personaStatusLabelText); - //javax.swing.Box.Filler filler1 = this.createFiller(5, 0); - //personasPanel.add(filler1, constraints); - javax.swing.JLabel personaLabel = new javax.swing.JLabel(); - personaLabel.setText(Bundle.ContactArtifactViewer_persona_label()); - personaLabel.setFont(personaLabel.getFont().deriveFont(Font.BOLD, personaLabel.getFont().getSize())); - gridBagLayout.setConstraints(personaLabel, constraints); - personasPanel.add(personaLabel); + m_constraints.gridx = 0; - constraints.gridy++; - javax.swing.JLabel personaStatusLabel = new javax.swing.JLabel(); - personaStatusLabel.setText(personaStatusLabelText); - gridBagLayout.setConstraints(personaStatusLabel, constraints); - personasPanel.add(personaStatusLabel); + CommunicationArtifactViewerHelper.addComponent(this, m_gridBagLayout, m_constraints, personaSearchStatusLabel); - - if (CentralRepository.isEnabled() ) { - personasLabel.setEnabled(true); - + if (CentralRepository.isEnabled()) { // Kick off a background task to serach for personas for the contact - ContactPersonaSearcherTask personaSearchTask = new ContactPersonaSearcherTask(accountAttributesList); + personaSearchTask = new ContactPersonaSearcherTask(accountAttributesList); personaSearchTask.execute(); } else { - personasLabel.setEnabled(false); - personaLabel.setEnabled(false); - personaStatusLabel.setEnabled(false); + 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()); + m_constraints.gridy++; + + CommunicationArtifactViewerHelper.addPageEndGlue(this, m_gridBagLayout, this.m_constraints); } - personasPanel.setLayout(gridBagLayout); - personasPanel.revalidate(); - personasPanel.repaint(); } /** * Updates the Persona panel with the gathered persona information. */ - private void updatePersonasPanel() { - // Clear out the panel - personasPanel.removeAll(); + private void updatePersonas() { - GridBagLayout gridBagLayout = new GridBagLayout(); - GridBagConstraints constraints = new GridBagConstraints(); - constraints.anchor = GridBagConstraints.FIRST_LINE_START; - constraints.gridx = 0; - constraints.gridy = 0; - constraints.insets = new java.awt.Insets(TOP_INSET, LEFT_INSET, 0, 0); + // Remove the "Searching....." label + this.remove(personaSearchStatusLabel); + m_constraints.gridx = 0; if (contactUniquePersonasMap.isEmpty()) { - showPersona(null, Collections.emptyList(), gridBagLayout, constraints); + // No persona found - show a button to create one. + showPersona(null, 0, Collections.emptyList(), this.m_gridBagLayout, this.m_constraints); } else { + int matchCounter = 0; for (Map.Entry> entry : contactUniquePersonasMap.entrySet()) { List missingAccounts = new ArrayList<>(); ArrayList personaAccounts = entry.getValue(); + matchCounter++; // create a list of accounts missing from this persona for (CentralRepoAccount account : contactUniqueAccountsList) { @@ -528,52 +404,51 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac } } - showPersona(entry.getKey(), missingAccounts, gridBagLayout, constraints); - - constraints.gridy += 2; + showPersona(entry.getKey(), matchCounter, missingAccounts, m_gridBagLayout, m_constraints); + m_constraints.gridy += 2; } } - personasPanel.setLayout(gridBagLayout); - personasPanel.setSize(personasPanel.getPreferredSize()); - personasPanel.revalidate(); - personasPanel.repaint(); - } + // add veritcal glue at the end + CommunicationArtifactViewerHelper.addPageEndGlue(this, m_gridBagLayout, this.m_constraints); - @NbBundle.Messages({ - "ContactArtifactViewer_persona_label=Persona ", - "ContactArtifactViewer_persona_text_none=None found", - "ContactArtifactViewer_persona_button_view=View", - "ContactArtifactViewer_persona_button_new=Create", - "ContactArtifactViewer_missing_account_label=Missing Account: " - }) + // redraw the panel + this.setLayout(this.m_gridBagLayout); + this.revalidate(); + this.repaint(); + } /** * Displays the given persona in the persona panel. * - * @param persona Persona to display. - * @param missingAccountsList List of accounts this persona may be missing. - * @param gridBagLayout Layout to use. - * @param constraints layout constraints. + * @param persona Persona to display. + * @param missingAccountsList List of contact accounts this persona may be + * missing. + * @param gridBagLayout Layout to use. + * @param constraints layout constraints. * * @throws CentralRepoException */ - private void showPersona(Persona persona, List missingAccountsList, GridBagLayout gridBagLayout, GridBagConstraints constraints) { + @NbBundle.Messages({ + "ContactArtifactViewer_persona_label=Persona ", + "ContactArtifactViewer_persona_no_match=No matches found", + "ContactArtifactViewer_persona_button_view=View", + "ContactArtifactViewer_persona_button_new=Create", + "ContactArtifactViewer_persona_match_num=Match ", + "ContactArtifactViewer_missing_account_label=Missing contact account", + "ContactArtifactViewer_found_all_accounts_label=All accounts found." + }) + private void showPersona(Persona persona, int matchNumber, List missingAccountsList, GridBagLayout gridBagLayout, GridBagConstraints constraints) { - constraints.fill = GridBagConstraints.NONE; - constraints.weightx = 0; + // 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.Box.Filler filler1 = createFiller(5, 0); - // gridBagLayout.setConstraints(filler1, constraints); - //personasPanel.add(filler1); - // Add a "Persona" label - //constraints.gridx++; - javax.swing.JLabel personaLabel = new javax.swing.JLabel(); - personaLabel.setText(Bundle.ContactArtifactViewer_persona_label()); - personaLabel.setFont(personaLabel.getFont().deriveFont(Font.BOLD, personaLabel.getFont().getSize())); - gridBagLayout.setConstraints(personaLabel, constraints); - personasPanel.add(personaLabel); + javax.swing.JLabel matchNumberLabel = CommunicationArtifactViewerHelper.addKey(this, gridBagLayout, constraints, String.format("%s %d", Bundle.ContactArtifactViewer_persona_match_num(), matchNumber)); javax.swing.JLabel personaNameLabel = new javax.swing.JLabel(); javax.swing.JButton personaButton = new javax.swing.JButton(); @@ -581,59 +456,110 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac String personaName; String personaButtonText; ActionListener personaButtonListener; - if (persona != null) { personaName = persona.getName(); personaButtonText = Bundle.ContactArtifactViewer_persona_button_view(); - personaButtonListener = new ViewPersonaButtonListener(persona); + personaButtonListener = new ViewPersonaButtonListener(this, persona); } else { - personaName = Bundle.ContactArtifactViewer_persona_text_none(); + matchNumberLabel.setVisible(false); + personaName = Bundle.ContactArtifactViewer_persona_no_match(); personaButtonText = Bundle.ContactArtifactViewer_persona_button_new(); - personaButtonListener = new CreatePersonaButtonListener(new PersonaUIComponents(personaNameLabel, personaButton)); + personaButtonListener = new CreatePersonaButtonListener(this, new PersonaUIComponents(personaNameLabel, personaButton)); } - // Add the label for persona name, - constraints.gridy++; - constraints.gridx = 0; + //constraints.gridwidth = 1; // TBD: this may not be needed if we use single panel + constraints.gridx++; personaNameLabel.setText(personaName); gridBagLayout.setConstraints(personaNameLabel, constraints); - personasPanel.add(personaNameLabel); + CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, personaNameLabel); + //personasPanel.add(personaNameLabel); - //constraints.gridx++; - //personasPanel.add(createFiller(5, 0), constraints); // Add a Persona action button constraints.gridx++; + //constraints.gridwidth = 1; personaButton.setText(personaButtonText); personaButton.addActionListener(personaButtonListener); - // no top inset of the button, in order to center align with the labels. - constraints.insets = new java.awt.Insets(0, LEFT_INSET, 0, 0); + // Shirnk the button height. + personaButton.setMargin(new Insets(0, 5, 0, 5)); gridBagLayout.setConstraints(personaButton, constraints); - personasPanel.add(personaButton); + CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, personaButton); + CommunicationArtifactViewerHelper.addLineEndGlue(this, gridBagLayout, constraints); - // restore normal inset - constraints.insets = new java.awt.Insets(TOP_INSET, LEFT_INSET, 0, 0); + constraints.insets = savedInsets; - // show missing accounts. - for (CentralRepoAccount missingAccount : missingAccountsList) { - constraints.weightx = 0; - constraints.gridx = 0; - constraints.gridy++; + // if we have a persona, indicate if any of the contact's accounts are missing from it. + if (persona != null) { + if (missingAccountsList.isEmpty()) { + constraints.gridy++; + constraints.gridx = 1; + //constraints.insets = labelInsets; - // Add a "Missing Account: " label - constraints.gridx++; // Ident - javax.swing.JLabel missingAccountLabel = new javax.swing.JLabel(); - missingAccountLabel.setText(Bundle.ContactArtifactViewer_missing_account_label()); - gridBagLayout.setConstraints(missingAccountLabel, constraints); - personasPanel.add(missingAccountLabel); + javax.swing.JLabel accountsStatus = new javax.swing.JLabel(Bundle.ContactArtifactViewer_found_all_accounts_label()); + constraints.insets = extraIndentInsets; + CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, accountsStatus); + constraints.insets = savedInsets; - // Add the label for account id, - constraints.gridx++; - javax.swing.JLabel missingAccountIdentifierLabel = new javax.swing.JLabel(); - missingAccountIdentifierLabel.setText(missingAccount.getIdentifier()); - gridBagLayout.setConstraints(missingAccountIdentifierLabel, constraints); - personasPanel.add(missingAccountIdentifierLabel); + CommunicationArtifactViewerHelper.addLineEndGlue(this, gridBagLayout, constraints); + } else { + // show missing accounts. + for (CentralRepoAccount missingAccount : missingAccountsList) { + //constraints.weightx = 0; + constraints.gridx = 0; + constraints.gridy++; + + // this needs an extra indent + constraints.insets = extraIndentInsets; + CommunicationArtifactViewerHelper.addKeyAtCol(this, gridBagLayout, constraints, Bundle.ContactArtifactViewer_missing_account_label(), 1); + constraints.insets = savedInsets; + + CommunicationArtifactViewerHelper.addValueAtCol(this, gridBagLayout, constraints, missingAccount.getIdentifier(), 2); + } + } } + + // restore insets + constraints.insets = savedInsets; + } + + /** + * Resets all artifact specific state. + */ + private void resetComponent() { + + contactArtifact = null; + contactName = null; + datasourceName = null; + + contactUniqueAccountsList.clear(); + contactUniquePersonasMap.clear(); + + phoneNumList.clear(); + emailList.clear(); + nameList.clear(); + otherList.clear(); + accountAttributesList.clear(); + + if (personaSearchTask != null) { + personaSearchTask.cancel(Boolean.TRUE); + personaSearchTask = null; + } + + // clear the panel + this.removeAll(); + this.setLayout(null); + + m_gridBagLayout = new GridBagLayout(); + m_constraints = new GridBagConstraints(); + + m_constraints.anchor = GridBagConstraints.FIRST_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.fill = GridBagConstraints.NONE; + } /** @@ -642,7 +568,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; @@ -666,7 +592,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac imageIcon = new ImageIcon(image); break; } catch (IOException ex) { - // ImageIO.read will through an IOException if file is not an image + // ImageIO.read will throw an IOException if file is not an image // therefore we don't need to report this exception just try // the next file. } @@ -692,7 +618,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(List accountAttributesList) { this.accountAttributesList = accountAttributesList; @@ -703,6 +629,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac Map> uniquePersonas = new HashMap<>(); + // TBD: this search needs to change to use the new method CommunicationsManager.getAccountsRelatedToArtifact for (BlackboardAttribute bba : accountAttributesList) { // Get account, add to accounts list @@ -736,7 +663,6 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac } } } - } return uniquePersonas; @@ -758,7 +684,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac contactUniqueAccountsList.clear(); contactUniqueAccountsList.addAll(uniqueAccountsList); - updatePersonasPanel(); + updatePersonas(); } catch (CancellationException ex) { logger.log(Level.INFO, "Persona searching was canceled."); //NON-NLS @@ -783,7 +709,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) { @@ -815,6 +741,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac */ private class CreatePersonaButtonListener implements ActionListener { + private final Component parentComponent; private final PersonaUIComponents personaUIComponents; /** @@ -822,8 +749,9 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac * * @param personaUIComponents UI components. */ - CreatePersonaButtonListener(PersonaUIComponents personaUIComponents) { + CreatePersonaButtonListener(Component parentComponent, PersonaUIComponents personaUIComponents) { this.personaUIComponents = personaUIComponents; + this.parentComponent = parentComponent; } @NbBundle.Messages({ @@ -833,8 +761,8 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac @Override public void actionPerformed(java.awt.event.ActionEvent evt) { // Launch the Persona Create dialog - do not display immediately - PersonaDetailsDialog createPersonaDialog = new PersonaDetailsDialog(ContactArtifactViewer.this, - PersonaDetailsMode.CREATE, null, new PersonaCreateCallbackImpl(personaUIComponents), false); + PersonaDetailsDialog createPersonaDialog = new PersonaDetailsDialog(parentComponent, + PersonaDetailsMode.CREATE, null, new PersonaCreateCallbackImpl(parentComponent, personaUIComponents), false); // Pre populate the persona name and accounts if we have them. PersonaDetailsPanel personaPanel = createPersonaDialog.getDetailsPanel(); @@ -859,19 +787,21 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac private class ViewPersonaButtonListener implements ActionListener { private final Persona persona; + private final Component parentComponent; /** * Creates listener for View persona button. * * @param persona */ - ViewPersonaButtonListener(Persona persona) { + ViewPersonaButtonListener(Component parentComponent, Persona persona) { this.persona = persona; + this.parentComponent = parentComponent; } @Override public void actionPerformed(java.awt.event.ActionEvent evt) { - new PersonaDetailsDialog(ContactArtifactViewer.this, + new PersonaDetailsDialog(parentComponent, PersonaDetailsMode.VIEW, persona, new PersonaViewCallbackImpl()); } } @@ -881,6 +811,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac */ class PersonaCreateCallbackImpl implements PersonaDetailsDialogCallback { + private final Component parentComponent; private final PersonaUIComponents personaUIComponents; /** @@ -888,7 +819,8 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac * * @param personaUIComponents UI Components. */ - PersonaCreateCallbackImpl(PersonaUIComponents personaUIComponents) { + PersonaCreateCallbackImpl(Component parentComponent, PersonaUIComponents personaUIComponents) { + this.parentComponent = parentComponent; this.personaUIComponents = personaUIComponents; } @@ -905,7 +837,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac for (ActionListener act : personaButton.getActionListeners()) { personaButton.removeActionListener(act); } - personaButton.addActionListener(new ViewPersonaButtonListener(persona)); + personaButton.addActionListener(new ViewPersonaButtonListener(parentComponent, persona)); } @@ -925,18 +857,6 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac } } - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel contactImage; - private javax.swing.JLabel contactNameLabel; - private javax.swing.JLabel emailsLabel; - private javax.swing.JPanel emailsPanel; - private javax.swing.JPanel namePanel; - private javax.swing.JPanel otherAttrsPanel; - private javax.swing.JLabel othersLabel; - private javax.swing.JLabel personasLabel; - private javax.swing.JPanel personasPanel; - private javax.swing.JPanel phoneNumbersPanel; - private javax.swing.JLabel phonesLabel; // End of variables declaration//GEN-END:variables } diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties index 5f60aed634..f4d5248a8b 100644 --- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties +++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Fri, 12 Jun 2020 14:50:38 -0400 +#Fri, 19 Jun 2020 10:14:47 -0400 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=314 SPLASH_WIDTH=538 diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index 6160c1ec95..52d17e0e96 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,4 +1,4 @@ #Updated by build script -#Fri, 12 Jun 2020 14:50:38 -0400 +#Fri, 19 Jun 2020 10:14:47 -0400 CTL_MainWindow_Title=Autopsy 4.15.0 CTL_MainWindow_Title_No_Project=Autopsy 4.15.0