From 9dcbf35609b4282a78c3bd9cac1b9a97a1c88061 Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Wed, 17 Jun 2020 13:55:29 -0400 Subject: [PATCH 1/9] Interim commit - Panel does not show up. --- .../autopsy/contentviewers/Bundle.properties | 1 - .../CommunicationArtifactViewerHelper.java | 21 ++ .../contentviewers/ContactArtifactViewer.java | 2 +- .../ContactArtifactViewerNew.form | 20 ++ .../ContactArtifactViewerNew.java | 259 ++++++++++++++++++ 5 files changed, 301 insertions(+), 2 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.form create mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties index f932bed9e9..b6e3b0044a 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties @@ -980,4 +980,3 @@ CallLogArtifactViewer.localAccountPersonaLabel.text=Persona CallLogArtifactViewer.localAccountPersonaNameLabel.text=jLabel1 CallLogArtifactViewer.localAccountPersonaButton.text=jButton1 ContactArtifactViewer.personasLabel.text=Personas -ContactArtifactViewer.contactImage.text= diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java b/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java index bb37885786..f3ebd00bb3 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java @@ -29,6 +29,7 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JLabel; import javax.swing.JMenuItem; +import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; @@ -94,6 +95,26 @@ public final class CommunicationArtifactViewerHelper { addLineEndGlue(panel, gridbagLayout, constraints); } + /** + * 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); + + // add line end glue + addLineEndGlue(panel, gridbagLayout, constraints); + } + /** * Adds a filler/glue at the end of the line to keep the other columns * aligned, in case the panel is resized. diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java index 2d11fcf853..0e7f47e7a4 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java @@ -64,7 +64,7 @@ import org.sleuthkit.datamodel.TskCoreException; /** * This class displays the TSK_CONTACT artifact. */ -@ServiceProvider(service = ArtifactContentViewer.class) +//@ServiceProvider(service = ArtifactContentViewer.class) public class ContactArtifactViewer extends javax.swing.JPanel implements ArtifactContentViewer { private final static Logger logger = Logger.getLogger(ContactArtifactViewer.class.getName()); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.form b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.form new file mode 100644 index 0000000000..c0838b761c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.form @@ -0,0 +1,20 @@ + + +
+ + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java new file mode 100644 index 0000000000..06d47f9598 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java @@ -0,0 +1,259 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.contentviewers; + +import java.awt.Component; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import javax.imageio.ImageIO; +import javax.swing.ImageIcon; +import javax.swing.JScrollPane; +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.Persona; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * + * @author raman + */ +@ServiceProvider(service = ArtifactContentViewer.class) +public class ContactArtifactViewerNew extends javax.swing.JPanel implements ArtifactContentViewer { + + private final static Logger logger = Logger.getLogger(ContactArtifactViewer.class.getName()); + private static final long serialVersionUID = 1L; + + private GridBagLayout m_gridBagLayout = new GridBagLayout(); + private GridBagConstraints m_constraints = new GridBagConstraints(); + + // contact name, if available. + private String contactName; // TBD: is this really needed as class member? + + //private javax.swing.JLabel contactImage; // TBD: is this really needed as class member? + + 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<>(); + + // A list of all unique personas and their account, found by searching on the + // account identifier attributes of the Contact artifact. + private final Map> contactUniquePersonasMap = new HashMap<>(); + + + /** + * Creates new form ContactArtifactViewerNew + */ + public ContactArtifactViewerNew() { + initComponents(); + + defaultImage = new ImageIcon(ContactArtifactViewer.class.getResource(DEFAULT_IMAGE_PATH)); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + setToolTipText("RAMAN RAMAN RAMAN RAMAN RAMAN "); // NOI18N + setLayout(new java.awt.GridBagLayout()); + }// //GEN-END:initComponents + + @Override + public void setArtifact(BlackboardArtifact artifact) { + // Reset the panel. + resetComponent(); + + if (artifact == null) { + 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); + } + } + } + } 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); + } + + + updateContactImage(artifact); + + // update name section + updateContactName(nameList); + + + // repaint + this.revalidate(); + this.repaint(); + } + + @Override + public Component getComponent() { + // Slap a vertical scrollbar on the panel. + return this; + //return new JScrollPane(this, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + } + + @Override + public boolean isSupported(BlackboardArtifact artifact) { + return artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID(); + } + + + /** + * Updates the contact name in the view. + * + * @param attributesList + */ + @NbBundle.Messages({ + "ContactArtifactViewer.contactImage.text=RAMAN", + }) + private void updateContactImage(BlackboardArtifact artifact) { + + javax.swing.JLabel contactImage = new javax.swing.JLabel(); + + contactImage.setIcon(getImageFromArtifact(artifact)); + + contactImage.setText(Bundle.ContactArtifactViewer_contactImage_text()); + + CommunicationArtifactViewerHelper.addComponent(this, m_gridBagLayout, this.m_constraints, contactImage); + m_constraints.gridy++; + + } + + /** + * Updates the contact name in the view from the list of attributes. + * + * @param attributesList List of attributes that might have the contact name. + */ + private void updateContactName(List nameAttributesList) { + for (BlackboardAttribute bba : nameAttributesList) { + if (StringUtils.isEmpty(bba.getValueString()) == false) { + contactName = bba.getDisplayString(); + + CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, contactName); + break; + } + } + } + + /** + * Resets all artifact specific state. + */ + private void resetComponent() { + + contactName = null; + contactUniqueAccountsList.clear(); + contactUniquePersonasMap.clear(); + + //contactImage.setIcon(defaultImage); + + + // 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.05; + m_constraints.weightx = 0.05; + m_constraints.insets = new java.awt.Insets(0, 0, 0, 0); + m_constraints.fill = GridBagConstraints.NONE; + + } + + /** + * Gets an image from a TSK_CONTACT artifact. + * + * @param artifact + * + * @return Image from a TSK_CONTACT artifact or default image if none was + * found or the artifact is not a TSK_CONTACT + */ + private ImageIcon getImageFromArtifact(BlackboardArtifact artifact) { + ImageIcon imageIcon = defaultImage; + + if (artifact == null) { + return imageIcon; + } + + BlackboardArtifact.ARTIFACT_TYPE artifactType = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID()); + if (artifactType != BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT) { + return imageIcon; + } + + try { + for (Content content : artifact.getChildren()) { + if (content instanceof AbstractFile) { + AbstractFile file = (AbstractFile) content; + + try { + BufferedImage image = ImageIO.read(new File(file.getLocalAbsPath())); + imageIcon = new ImageIcon(image); + break; + } catch (IOException ex) { + // ImageIO.read will through an IOException if file is not an image + // therefore we don't need to report this exception just try + // the next file. + } + } + } + } catch (TskCoreException ex) { + logger.log(Level.WARNING, String.format("Unable to load image for contact: %d", artifact.getId()), ex); + } + + return imageIcon; + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables +} From 7c4340fd3c7ef68b6b9536b34266d4464b96115b Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Thu, 18 Jun 2020 14:51:41 -0400 Subject: [PATCH 2/9] Interim commit. Single planel cant work with the way personas need to be updated for a contact. Going to try a 3 panel approach. --- .../autopsy/contentviewers/Bundle.properties | 1 - .../CommunicationArtifactViewerHelper.java | 12 +- .../ContactArtifactViewerNew.form | 5 +- .../ContactArtifactViewerNew.java | 266 +++++++++++++++++- 4 files changed, 268 insertions(+), 16 deletions(-) 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/CommunicationArtifactViewerHelper.java b/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java index f3ebd00bb3..e6b59f093d 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java @@ -63,9 +63,14 @@ 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) { + // 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) { @@ -77,8 +82,7 @@ public final class CommunicationArtifactViewerHelper { // let the header span all of the row constraints.gridwidth = MAX_COLS; - // create label for heading - javax.swing.JLabel headingLabel = new javax.swing.JLabel(); + // set text headingLabel.setText(headerString); // make it large and bold @@ -93,6 +97,8 @@ public final class CommunicationArtifactViewerHelper { // add line end glue addLineEndGlue(panel, gridbagLayout, constraints); + + return headingLabel; } /** diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.form b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.form index c0838b761c..806a0e3de5 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.form @@ -1,8 +1,8 @@ -
+ - + @@ -14,6 +14,7 @@ + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java index 06d47f9598..ccf0755f5c 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java @@ -12,19 +12,29 @@ import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; import java.util.logging.Level; +import java.util.stream.Collectors; import javax.imageio.ImageIO; import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.JPanel; import javax.swing.JScrollPane; +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; import org.sleuthkit.autopsy.centralrepository.datamodel.Persona; +import org.sleuthkit.autopsy.centralrepository.datamodel.PersonaAccount; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -60,6 +70,7 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti // account identifier attributes of the Contact artifact. private final Map> contactUniquePersonasMap = new HashMap<>(); + privbate ContactPersonaSearcherTask personaSearchTask; /** * Creates new form ContactArtifactViewerNew @@ -79,7 +90,7 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti // //GEN-BEGIN:initComponents private void initComponents() { - setToolTipText("RAMAN RAMAN RAMAN RAMAN RAMAN "); // NOI18N + setToolTipText(""); // NOI18N setLayout(new java.awt.GridBagLayout()); }// //GEN-END:initComponents @@ -97,6 +108,7 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti List nameList = new ArrayList<>(); List otherList = new ArrayList<>(); List accountAttributesList = new ArrayList<>(); + String datasourceName; try { // Get all the attributes and group them by the section panels they go in @@ -116,8 +128,11 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti } } } + + datasourceName = artifact.getDataSource().getName(); } 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; } @@ -126,8 +141,17 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti // update name section updateContactName(nameList); + // update contact attributes sections + updateSection(phoneNumList, "Phones"); + updateSection(emailList, "Emails"); + updateSection(otherList, "Others"); + updateSource(datasourceName); + + CommunicationArtifactViewerHelper.addPageEndGlue(this, m_gridBagLayout, this.m_constraints); + // repaint + this.setLayout(m_gridBagLayout); this.revalidate(); this.repaint(); } @@ -135,8 +159,7 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti @Override public Component getComponent() { // Slap a vertical scrollbar on the panel. - return this; - //return new JScrollPane(this, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + return new JScrollPane(this, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); } @Override @@ -146,12 +169,12 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti /** - * Updates the contact name in the view. + * Updates the contact image in the view. * - * @param attributesList + * @param artifact */ @NbBundle.Messages({ - "ContactArtifactViewer.contactImage.text=RAMAN", + "ContactArtifactViewer.contactImage.text=", }) private void updateContactImage(BlackboardArtifact artifact) { @@ -161,9 +184,10 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti contactImage.setText(Bundle.ContactArtifactViewer_contactImage_text()); + // add image to top left corner of the page. CommunicationArtifactViewerHelper.addComponent(this, m_gridBagLayout, this.m_constraints, contactImage); m_constraints.gridy++; - + } /** @@ -171,15 +195,139 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti * * @param attributesList List of attributes that might have the contact name. */ + @NbBundle.Messages({ + "ContactArtifactViewer_contactname_unknown=Unknown", + }) private void updateContactName(List nameAttributesList) { + boolean foundName = false; for (BlackboardAttribute bba : nameAttributesList) { if (StringUtils.isEmpty(bba.getValueString()) == false) { contactName = bba.getDisplayString(); + // TBD: need to increase the font size of the page header by 2 CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, contactName); + foundName = true; break; } } + if (foundName== false) { + CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, 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. + */ + private void updateSection(List sectionAttributesList, String sectionHeader) { + + // If there are no attributes for this section, do nothing + if (sectionAttributesList.isEmpty()) { + return; + } + + CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, sectionHeader); + for (BlackboardAttribute bba : sectionAttributesList) { + CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, m_constraints, bba.getAttributeType().getDisplayName()); + CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, m_constraints, bba.getDisplayString()); + } + } + + @NbBundle.Messages({ + "ContactArtifactViewer_heading_Source=Source", + "ContactArtifactViewer_label_datasource=Data Source",}) + private void updateSource(String datasourceName) { + CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, Bundle.ContactArtifactViewer_heading_Source()); + CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, Bundle.ContactArtifactViewer_label_datasource()); + CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.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= Persona", + "ContactArtifactViewer_persona_searching= Searching...", + "ContactArtifactViewer_persona_unknown=Unknown" + }) + private void initiatePersonasSearch(List accountAttributesList) throws CentralRepoException { + + JLabel personaHeader = CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, Bundle.ContactArtifactViewer_persona_searching()); + + //CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, Bundle.ContactArtifactViewer_label_datasource()); + + + personasLabel.setVisible(true); + + String personaStatusLabelText = CentralRepository.isEnabled() + ? Bundle.ContactArtifactViewer_persona_searching() + : Bundle.ContactArtifactViewer_persona_unknown(); + + + + + + + if (CentralRepository.isEnabled() ) { + + + // Kick off a background task to serach for personas for the contact + ContactPersonaSearcherTask personaSearchTask = new ContactPersonaSearcherTask(accountAttributesList); + personaSearchTask.execute(); + } else { + personaHeader.setEnabled(false); + + // RAMAN TBD: add a Unknown diabled label at gridx=1; + } + + + } + + /** + * Updates the Persona panel with the gathered persona information. + */ + private void updatePersonasPanel() { + // Clear out the panel + personasPanel.removeAll(); + + 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); + + if (contactUniquePersonasMap.isEmpty()) { + showPersona(null, Collections.emptyList(), gridBagLayout, constraints); + } else { + for (Map.Entry> entry : contactUniquePersonasMap.entrySet()) { + List missingAccounts = new ArrayList<>(); + ArrayList personaAccounts = entry.getValue(); + + // create a list of accounts missing from this persona + for (CentralRepoAccount account : contactUniqueAccountsList) { + if (personaAccounts.contains(account) == false) { + missingAccounts.add(account); + } + } + + showPersona(entry.getKey(), missingAccounts, gridBagLayout, constraints); + + constraints.gridy += 2; + } + } + + personasPanel.setLayout(gridBagLayout); + personasPanel.setSize(personasPanel.getPreferredSize()); + personasPanel.revalidate(); + personasPanel.repaint(); } /** @@ -191,8 +339,11 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti contactUniqueAccountsList.clear(); contactUniquePersonasMap.clear(); - //contactImage.setIcon(defaultImage); + if (personaSearchTask != null) { + personaSearchTask.cancel(); + } + personaSearchTask - mull; // clear the panel this.removeAll(); @@ -208,7 +359,6 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti m_constraints.weightx = 0.05; m_constraints.insets = new java.awt.Insets(0, 0, 0, 0); m_constraints.fill = GridBagConstraints.NONE; - } /** @@ -241,7 +391,7 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti 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. } @@ -254,6 +404,102 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti return imageIcon; } + + /** + * Thread to search for a personas for all account identifier attributes for + * a contact. + */ + private class ContactPersonaSearcherTask extends SwingWorker>, Void> { + + private final List accountAttributesList; + private final List uniqueAccountsList = new ArrayList<>(); + + /** + * Creates a persona searcher task. + * + * @param accountAttributesList List of attributes that may map to + * accounts. + */ + ContactPersonaSearcherTask(List accountAttributesList) { + this.accountAttributesList = accountAttributesList; + } + + @Override + protected Map> doInBackground() throws Exception { + + Map> uniquePersonas = new HashMap<>(); + + for (BlackboardAttribute bba : accountAttributesList) { + + // Get account, add to accounts list + Collection personas; + + Collection accountCandidates + = CentralRepoAccount.getAccountsWithIdentifier(bba.getValueString()); + + if (accountCandidates.isEmpty() == false) { + CentralRepoAccount account = accountCandidates.iterator().next(); + if (uniqueAccountsList.contains(account) == false) { + uniqueAccountsList.add(account); + } + + // get personas for the account + personas = PersonaAccount.getPersonaAccountsForAccount(account.getId()) + .stream() + .map(PersonaAccount::getPersona) + .collect(Collectors.toList()); + + // make a list of unique personas, along with all their accounts + for (Persona persona : personas) { + if (uniquePersonas.containsKey(persona) == false) { + Collection accounts = persona.getPersonaAccounts() + .stream() + .map(PersonaAccount::getAccount) + .collect(Collectors.toList()); + + ArrayList personaAccountsList = new ArrayList<>(accounts); + uniquePersonas.put(persona, personaAccountsList); + } + } + } + + } + + return uniquePersonas; + } + + @Override + protected void done() { + + Map> personasMap; + try { + personasMap = super.get(); + + if (this.isCancelled()) { + return; + } + + contactUniquePersonasMap.clear(); + contactUniquePersonasMap.putAll(personasMap); + contactUniqueAccountsList.clear(); + contactUniqueAccountsList.addAll(uniqueAccountsList); + + updatePersonasSection(); + + // also update the source section now + + + } catch (CancellationException ex) { + logger.log(Level.INFO, "Persona searching was canceled."); //NON-NLS + } catch (InterruptedException ex) { + logger.log(Level.INFO, "Persona searching was interrupted."); //NON-NLS + } catch (ExecutionException ex) { + logger.log(Level.SEVERE, "Fatal error during Persona search.", ex); //NON-NLS + } + + } + } + // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables } From d460abe1a85d385d13e37b1de0f8eb92bed3d72b Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Fri, 19 Jun 2020 11:07:40 -0400 Subject: [PATCH 3/9] Interim commit - Its working with 3 panels, the alignment isn't great with 3 panels though. --- .../CommunicationArtifactViewerHelper.java | 67 +- .../contentviewers/ContactArtifactViewer.java | 12 +- .../ContactArtifactViewerNew.form | 44 ++ .../ContactArtifactViewerNew.java | 735 ++++++++++++++---- .../netbeans/core/startup/Bundle.properties | 2 +- .../core/windows/view/ui/Bundle.properties | 2 +- 6 files changed, 677 insertions(+), 185 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java b/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java index e6b59f093d..64f9799266 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java @@ -182,7 +182,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; @@ -194,25 +194,44 @@ 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 @@ -221,27 +240,47 @@ public final class CommunicationArtifactViewerHelper { // 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) { - - constraints.gridx = 1; + static JLabel addValue(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String valueString) { + return addValueAtCol(panel, gridbagLayout, constraints, valueString, 1); + } + + /** + * 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. + * @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 @@ -261,6 +300,8 @@ public final class CommunicationArtifactViewerHelper { // end the line addLineEndGlue(panel, gridbagLayout, constraints); + + return valueField; } /** diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java index 0e7f47e7a4..7d67dfc5e0 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java @@ -541,11 +541,11 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac } @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: " + //"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: " }) /** @@ -827,7 +827,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac } @NbBundle.Messages({ - "ContactArtifactViewer_persona_account_justification=Account found in Contact artifact" + // "ContactArtifactViewer_persona_account_justification=Account found in Contact artifact" }) @Override diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.form b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.form index 806a0e3de5..0a86676ba7 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.form @@ -18,4 +18,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java index ccf0755f5c..cedf42544e 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java @@ -1,13 +1,28 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.sleuthkit.autopsy.contentviewers; import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; @@ -23,8 +38,8 @@ import java.util.logging.Level; import java.util.stream.Collectors; 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 javax.swing.SwingWorker; import org.apache.commons.lang.StringUtils; @@ -35,6 +50,10 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.centralrepository.datamodel.Persona; import org.sleuthkit.autopsy.centralrepository.datamodel.PersonaAccount; +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.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -43,23 +62,28 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; /** - * - * @author raman + * This class displays the TSK_CONTACT artifact. */ @ServiceProvider(service = ArtifactContentViewer.class) public class ContactArtifactViewerNew extends javax.swing.JPanel implements ArtifactContentViewer { private final static Logger logger = Logger.getLogger(ContactArtifactViewer.class.getName()); private static final long serialVersionUID = 1L; - - private GridBagLayout m_gridBagLayout = new GridBagLayout(); - private GridBagConstraints m_constraints = new GridBagConstraints(); - - // contact name, if available. - private String contactName; // TBD: is this really needed as class member? - - //private javax.swing.JLabel contactImage; // TBD: is this really needed as class member? - + + private final static int LEFT_INSET = 12; + + //private GridBagLayout m_gridBagLayout = new GridBagLayout(); + //private GridBagConstraints m_constraints = new GridBagConstraints(); + 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; @@ -70,14 +94,14 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti // account identifier attributes of the Contact artifact. private final Map> contactUniquePersonasMap = new HashMap<>(); - privbate ContactPersonaSearcherTask personaSearchTask; - + private ContactPersonaSearcherTask personaSearchTask; + /** - * Creates new form ContactArtifactViewerNew + * Creates new form ContactArtifactViewer */ public ContactArtifactViewerNew() { initComponents(); - + defaultImage = new ImageIcon(ContactArtifactViewer.class.getResource(DEFAULT_IMAGE_PATH)); } @@ -89,9 +113,45 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { + java.awt.GridBagConstraints gridBagConstraints; + + contactDetailsPanel = new javax.swing.JPanel(); + personasPanel = new javax.swing.JPanel(); + sourcePanel = new javax.swing.JPanel(); + filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767)); setToolTipText(""); // NOI18N setLayout(new java.awt.GridBagLayout()); + + contactDetailsPanel.setLayout(new java.awt.GridBagLayout()); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + add(contactDetailsPanel, gridBagConstraints); + + personasPanel.setLayout(new java.awt.GridBagLayout()); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 1; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + add(personasPanel, gridBagConstraints); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 2; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + add(sourcePanel, gridBagConstraints); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 4; + gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.weighty = 1.0; + add(filler1, gridBagConstraints); }// //GEN-END:initComponents @Override @@ -103,55 +163,15 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti return; } - List phoneNumList = new ArrayList<>(); - List emailList = new ArrayList<>(); - List nameList = new ArrayList<>(); - List otherList = new ArrayList<>(); - List accountAttributesList = new ArrayList<>(); - String datasourceName; - 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); - } - } - } - - datasourceName = artifact.getDataSource().getName(); + 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; } - - - updateContactImage(artifact); - - // update name section - updateContactName(nameList); - // update contact attributes sections - updateSection(phoneNumList, "Phones"); - updateSection(emailList, "Emails"); - updateSection(otherList, "Others"); - - updateSource(datasourceName); - - CommunicationArtifactViewerHelper.addPageEndGlue(this, m_gridBagLayout, this.m_constraints); - - // repaint - this.setLayout(m_gridBagLayout); + updateView(); + this.revalidate(); this.repaint(); } @@ -167,85 +187,199 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti return artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID(); } - + /** + * 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 { + + 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(); + + // show a empty Personas panel and kick off a serch for personas + initiatePersonasSearch(); + + // update artifact source panel + updateSource(); + } + + /** + * Updates the view with contact's details. + */ + @NbBundle.Messages({ + "ContactArtifactViewer_phones_header=Phone", + "ContactArtifactViewer_eamils_header=Email", + "ContactArtifactViewer_others_header=Other",}) + private void updateContactDetails() { + GridBagLayout contactPanelLayout = new GridBagLayout(); + GridBagConstraints contactPanelConstraints = new GridBagConstraints(); + + contactPanelConstraints.anchor = GridBagConstraints.FIRST_LINE_START; + contactPanelConstraints.gridy = 0; + contactPanelConstraints.gridx = 0; + contactPanelConstraints.weighty = 0.05; + contactPanelConstraints.weightx = 0.05; + contactPanelConstraints.insets = new java.awt.Insets(0, 0, 0, 0); + contactPanelConstraints.fill = GridBagConstraints.NONE; + + updateContactImage(contactPanelLayout, contactPanelConstraints); + + // update name section + updateContactName(contactPanelLayout, contactPanelConstraints); + + // update contact attributes sections + updateContactMethodSection(phoneNumList, Bundle.ContactArtifactViewer_phones_header(), contactPanelLayout, contactPanelConstraints); + updateContactMethodSection(emailList, Bundle.ContactArtifactViewer_eamils_header(), contactPanelLayout, contactPanelConstraints); + updateContactMethodSection(otherList, Bundle.ContactArtifactViewer_others_header(), contactPanelLayout, contactPanelConstraints); + + CommunicationArtifactViewerHelper.addBlankLine(this.contactDetailsPanel, contactPanelLayout, contactPanelConstraints); + + contactDetailsPanel.setLayout(contactPanelLayout); + contactDetailsPanel.revalidate(); + contactDetailsPanel.repaint(); + } + /** * Updates the contact image in the view. * * @param artifact */ @NbBundle.Messages({ - "ContactArtifactViewer.contactImage.text=", - }) - private void updateContactImage(BlackboardArtifact artifact) { - + "ContactArtifactViewer.contactImage.text=",}) + private void updateContactImage(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) { + + contactPanelConstraints.gridy = 0; + contactPanelConstraints.gridx = 0; + javax.swing.JLabel contactImage = new javax.swing.JLabel(); - - contactImage.setIcon(getImageFromArtifact(artifact)); - + + contactImage.setIcon(getImageFromArtifact(contactArtifact)); + contactImage.setText(Bundle.ContactArtifactViewer_contactImage_text()); - + // add image to top left corner of the page. - CommunicationArtifactViewerHelper.addComponent(this, m_gridBagLayout, this.m_constraints, contactImage); - m_constraints.gridy++; + CommunicationArtifactViewerHelper.addComponent(this.contactDetailsPanel, contactPanelLayout, contactPanelConstraints, contactImage); + contactPanelConstraints.gridy++; } - + /** * Updates the contact name in the view from the list of attributes. * - * @param attributesList List of attributes that might have the contact name. + * @param attributesList List of attributes that might have the contact + * name. */ @NbBundle.Messages({ - "ContactArtifactViewer_contactname_unknown=Unknown", - }) - private void updateContactName(List nameAttributesList) { + "ContactArtifactViewer_contactname_unknown=Unknown",}) + private void updateContactName(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) { + boolean foundName = false; - for (BlackboardAttribute bba : nameAttributesList) { + for (BlackboardAttribute bba : this.nameList) { if (StringUtils.isEmpty(bba.getValueString()) == false) { contactName = bba.getDisplayString(); - - // TBD: need to increase the font size of the page header by 2 - CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, contactName); - foundName = true; + + CommunicationArtifactViewerHelper.addHeader(this.contactDetailsPanel, contactPanelLayout, contactPanelConstraints, contactName); + foundName = true; break; } } - if (foundName== false) { - CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, Bundle.ContactArtifactViewer_contactname_unknown()); + if (foundName == false) { + CommunicationArtifactViewerHelper.addHeader(this.contactDetailsPanel, 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 sectionLabel section name label. */ - private void updateSection(List sectionAttributesList, String sectionHeader) { + @NbBundle.Messages({ + "ContactArtifactViewer_plural_suffix=s",}) + private void updateContactMethodSection(List sectionAttributesList, String sectionHeader, GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) { // If there are no attributes for this section, do nothing if (sectionAttributesList.isEmpty()) { return; } - CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, sectionHeader); + String sectionHeaderString = sectionHeader; + if (sectionAttributesList.size() > 1) { + sectionHeaderString = sectionHeaderString.concat(Bundle.ContactArtifactViewer_plural_suffix()); + } + CommunicationArtifactViewerHelper.addHeader(this.contactDetailsPanel, contactPanelLayout, contactPanelConstraints, sectionHeaderString); for (BlackboardAttribute bba : sectionAttributesList) { - CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, m_constraints, bba.getAttributeType().getDisplayName()); - CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, m_constraints, bba.getDisplayString()); + CommunicationArtifactViewerHelper.addKey(this.contactDetailsPanel, contactPanelLayout, contactPanelConstraints, bba.getAttributeType().getDisplayName()); + CommunicationArtifactViewerHelper.addValue(this.contactDetailsPanel, contactPanelLayout, contactPanelConstraints, bba.getDisplayString()); } } - + + /** + * Updates the source section. + */ @NbBundle.Messages({ "ContactArtifactViewer_heading_Source=Source", "ContactArtifactViewer_label_datasource=Data Source",}) - private void updateSource(String datasourceName) { - CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, Bundle.ContactArtifactViewer_heading_Source()); - CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, Bundle.ContactArtifactViewer_label_datasource()); - CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, datasourceName); + private void updateSource() { + + GridBagLayout sourcePanelLayout = new GridBagLayout(); + GridBagConstraints sourcePanelConstraints = new GridBagConstraints(); + + sourcePanelConstraints.anchor = GridBagConstraints.FIRST_LINE_START; + sourcePanelConstraints.gridy = 0; + sourcePanelConstraints.gridx = 0; + sourcePanelConstraints.weighty = 0.05; + sourcePanelConstraints.weightx = 0.05; + sourcePanelConstraints.insets = new java.awt.Insets(0, 0, 0, 0); + sourcePanelConstraints.fill = GridBagConstraints.NONE; + + CommunicationArtifactViewerHelper.addHeader(this.sourcePanel, sourcePanelLayout, sourcePanelConstraints, Bundle.ContactArtifactViewer_heading_Source()); + CommunicationArtifactViewerHelper.addKey(this.sourcePanel, sourcePanelLayout, sourcePanelConstraints, Bundle.ContactArtifactViewer_label_datasource()); + CommunicationArtifactViewerHelper.addValue(this.sourcePanel, sourcePanelLayout, sourcePanelConstraints, datasourceName); + + sourcePanel.setLayout(sourcePanelLayout); + sourcePanel.revalidate(); + sourcePanel.repaint(); } - - /** + + /** * Kicks off a search for personas, based in the given list of attributes. * * @param accountAttributesList a list of account identifying attributes. @@ -253,59 +387,77 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti * @throws CentralRepoException */ @NbBundle.Messages({ - "ContactArtifactViewer_persona_searching= Persona", - "ContactArtifactViewer_persona_searching= Searching...", - "ContactArtifactViewer_persona_unknown=Unknown" + "ContactArtifactViewer_persona_header=Persona", //"ContactArtifactViewer_persona_searching = Searching...", + //"ContactArtifactViewer_persona_unknown=Unknown" }) - private void initiatePersonasSearch(List accountAttributesList) throws CentralRepoException { - JLabel personaHeader = CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, Bundle.ContactArtifactViewer_persona_searching()); - - //CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, Bundle.ContactArtifactViewer_label_datasource()); - - - personasLabel.setVisible(true); + private void initiatePersonasSearch() { - String personaStatusLabelText = CentralRepository.isEnabled() - ? Bundle.ContactArtifactViewer_persona_searching() + GridBagLayout personasPanelLayout = new GridBagLayout(); + GridBagConstraints personasPanelConstraints = new GridBagConstraints(); + + personasPanelConstraints.anchor = GridBagConstraints.FIRST_LINE_START; + personasPanelConstraints.gridy = 0; + personasPanelConstraints.gridx = 0; + personasPanelConstraints.weighty = 0.05; + personasPanelConstraints.weightx = 0.05; + personasPanelConstraints.insets = new java.awt.Insets(0, 0, 0, 0); + personasPanelConstraints.fill = GridBagConstraints.NONE; + + // add a section header + JLabel personaHeader = CommunicationArtifactViewerHelper.addHeader(this.personasPanel, personasPanelLayout, personasPanelConstraints, Bundle.ContactArtifactViewer_persona_header()); + + personasPanelConstraints.gridy++; + + // add a status label + String personaStatusLabelText = CentralRepository.isEnabled() + ? Bundle.ContactArtifactViewer_persona_searching() : Bundle.ContactArtifactViewer_persona_unknown(); - - - + javax.swing.JLabel statusLabel = new javax.swing.JLabel(); + statusLabel.setText(personaStatusLabelText); - - if (CentralRepository.isEnabled() ) { - - + CommunicationArtifactViewerHelper.addComponent(this.personasPanel, personasPanelLayout, personasPanelConstraints, statusLabel); + + // End of panel, add a blank line + CommunicationArtifactViewerHelper.addBlankLine(this.personasPanel, personasPanelLayout, personasPanelConstraints); + + 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 { personaHeader.setEnabled(false); - - // RAMAN TBD: add a Unknown diabled label at gridx=1; + statusLabel.setEnabled(false); } - + personasPanel.setLayout(personasPanelLayout); + personasPanel.revalidate(); + personasPanel.repaint(); + } - + /** * Updates the Persona panel with the gathered persona information. */ - private void updatePersonasPanel() { + private void updatePersonas() { // Clear out the panel personasPanel.removeAll(); - 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); + GridBagLayout personasPanelLayout = new GridBagLayout(); + GridBagConstraints personasPanelConstraints = new GridBagConstraints(); + personasPanelConstraints.anchor = GridBagConstraints.FIRST_LINE_START; + personasPanelConstraints.gridx = 0; + personasPanelConstraints.gridy = 0; + personasPanelConstraints.insets = new java.awt.Insets(0, 0, 0, 0); + + // add a section header + CommunicationArtifactViewerHelper.addHeader(this.personasPanel, personasPanelLayout, personasPanelConstraints, Bundle.ContactArtifactViewer_persona_header()); + + personasPanelConstraints.gridy++; if (contactUniquePersonasMap.isEmpty()) { - showPersona(null, Collections.emptyList(), gridBagLayout, constraints); + showPersona(null, Collections.emptyList(), personasPanelLayout, personasPanelConstraints); } else { for (Map.Entry> entry : contactUniquePersonasMap.entrySet()) { List missingAccounts = new ArrayList<>(); @@ -318,56 +470,151 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti } } - showPersona(entry.getKey(), missingAccounts, gridBagLayout, constraints); - - constraints.gridy += 2; + showPersona(entry.getKey(), missingAccounts, personasPanelLayout, personasPanelConstraints); + personasPanelConstraints.gridy += 2; } } - personasPanel.setLayout(gridBagLayout); + CommunicationArtifactViewerHelper.addBlankLine(this.personasPanel, personasPanelLayout, personasPanelConstraints); + + personasPanel.setLayout(personasPanelLayout); personasPanel.setSize(personasPanel.getPreferredSize()); personasPanel.revalidate(); personasPanel.repaint(); } - + + /** + * Displays the given persona in the persona panel. + * + * @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 + */ + @NbBundle.Messages({ + "ContactArtifactViewer_persona_label=Persona ", + "ContactArtifactViewer_persona_name_unknown=Unknown", + "ContactArtifactViewer_persona_button_view=View", + "ContactArtifactViewer_persona_button_new=Create", + "ContactArtifactViewer_missing_account_label=Contact account not in persona", + "ContactArtifactViewer_found_all_accounts_label=All contact accounts are in persona" + }) + private void showPersona(Persona persona, List missingAccountsList, GridBagLayout gridBagLayout, GridBagConstraints constraints) { + + Insets savedInsets = constraints.insets; + + Insets labelInsets = new java.awt.Insets(0, LEFT_INSET, 0, 0); + + //constraints.fill = GridBagConstraints.NONE; + //constraints.weightx = 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 personaNameLabel = new javax.swing.JLabel(); + javax.swing.JButton personaButton = new javax.swing.JButton(); + + String personaName; + String personaButtonText; + ActionListener personaButtonListener; + + if (persona != null) { + personaName = persona.getName(); + personaButtonText = Bundle.ContactArtifactViewer_persona_button_view(); + personaButtonListener = new ViewPersonaButtonListener(this, persona); + } else { + personaName = Bundle.ContactArtifactViewer_persona_name_unknown(); + personaButtonText = Bundle.ContactArtifactViewer_persona_button_new(); + personaButtonListener = new CreatePersonaButtonListener(this, new PersonaUIComponents(personaNameLabel, personaButton)); + } + + // Add the label for persona name, + constraints.insets = labelInsets; + constraints.gridx = 0; + constraints.gridwidth = 2; // TBD: this may not be needed if we use single panel + personaNameLabel.setText(personaName); + gridBagLayout.setConstraints(personaNameLabel, constraints); + personasPanel.add(personaNameLabel); + + // Add a Persona action button + constraints.gridx += 2; + constraints.gridwidth = 1; + personaButton.setText(personaButtonText); + personaButton.addActionListener(personaButtonListener); + + constraints.insets = new java.awt.Insets(0, LEFT_INSET, 0, 0); + gridBagLayout.setConstraints(personaButton, constraints); + personasPanel.add(personaButton); + + constraints.insets = labelInsets; + + // 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++; + CommunicationArtifactViewerHelper.addKeyAtCol(personasPanel, gridBagLayout, constraints, Bundle.ContactArtifactViewer_found_all_accounts_label(), 2); + } else { + // show missing accounts. + for (CentralRepoAccount missingAccount : missingAccountsList) { + constraints.weightx = 0; + constraints.gridx = 0; + constraints.gridy++; + + CommunicationArtifactViewerHelper.addKeyAtCol(personasPanel, gridBagLayout, constraints, Bundle.ContactArtifactViewer_missing_account_label(), 2); + CommunicationArtifactViewerHelper.addValueAtCol(personasPanel, gridBagLayout, constraints, missingAccount.getIdentifier(), 3); + } + } + } + + // 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(); + personaSearchTask.cancel(Boolean.TRUE); + personaSearchTask = null; } - - personaSearchTask - mull; - - // 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.05; - m_constraints.weightx = 0.05; - m_constraints.insets = new java.awt.Insets(0, 0, 0, 0); - m_constraints.fill = GridBagConstraints.NONE; + this.contactDetailsPanel.removeAll(); + this.personasPanel.removeAll(); + this.sourcePanel.removeAll(); } - + /** * Gets an image from a TSK_CONTACT artifact. * * @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; @@ -404,7 +651,6 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti return imageIcon; } - /** * Thread to search for a personas for all account identifier attributes for * a contact. @@ -418,7 +664,7 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti * Creates a persona searcher task. * * @param accountAttributesList List of attributes that may map to - * accounts. + * accounts. */ ContactPersonaSearcherTask(List accountAttributesList) { this.accountAttributesList = accountAttributesList; @@ -429,6 +675,7 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti 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 @@ -462,7 +709,6 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti } } } - } return uniquePersonas; @@ -484,10 +730,7 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti contactUniqueAccountsList.clear(); contactUniqueAccountsList.addAll(uniqueAccountsList); - updatePersonasSection(); - - // also update the source section now - + updatePersonas(); } catch (CancellationException ex) { logger.log(Level.INFO, "Persona searching was canceled."); //NON-NLS @@ -499,7 +742,171 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti } } - + + /** + * A wrapper class that bags the UI components that need to be updated when + * a persona search task or a create dialog returns. + */ + private class PersonaUIComponents { + + private final JLabel personaNameLabel; + private final JButton personaActionButton; + + /** + * Constructor. + * + * @param personaNameLabel Persona name label. + * @param personaActionButton Persona action button. + */ + PersonaUIComponents(JLabel personaNameLabel, JButton personaActionButton) { + this.personaNameLabel = personaNameLabel; + this.personaActionButton = personaActionButton; + } + + /** + * Returns persona name label. + * + * @return Persona name label. + */ + public JLabel getPersonaNameLabel() { + return personaNameLabel; + } + + /** + * Returns persona action button. + * + * @return Persona action button. + */ + public JButton getPersonaActionButton() { + return personaActionButton; + } + } + + /** + * Action listener for Create persona button. + */ + private class CreatePersonaButtonListener implements ActionListener { + + private final Component parentComponent; + private final PersonaUIComponents personaUIComponents; + + /** + * Constructs a listener for Create persona button.. + * + * @param personaUIComponents UI components. + */ + CreatePersonaButtonListener(Component parentComponent, PersonaUIComponents personaUIComponents) { + this.personaUIComponents = personaUIComponents; + this.parentComponent = parentComponent; + } + + @NbBundle.Messages({ + "ContactArtifactViewer_persona_account_justification=Account found in Contact artifact" + }) + + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + // Launch the Persona Create dialog - do not display immediately + 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(); + + if (contactName != null) { + personaPanel.setPersonaName(contactName); + } + + // pass the list of accounts to the dialog + for (CentralRepoAccount account : contactUniqueAccountsList) { + personaPanel.addAccount(account, Bundle.ContactArtifactViewer_persona_account_justification(), Persona.Confidence.HIGH); + } + + // display the dialog now + createPersonaDialog.display(); + } + } + + /** + * Action listener for View persona button. + */ + private class ViewPersonaButtonListener implements ActionListener { + + private final Persona persona; + private final Component parentComponent; + + /** + * Creates listener for View persona button. + * + * @param persona + */ + ViewPersonaButtonListener(Component parentComponent, Persona persona) { + this.persona = persona; + this.parentComponent = parentComponent; + } + + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + new PersonaDetailsDialog(parentComponent, + PersonaDetailsMode.VIEW, persona, new PersonaViewCallbackImpl()); + } + } + + /** + * Callback method for the create mode of the PersonaDetailsDialog + */ + class PersonaCreateCallbackImpl implements PersonaDetailsDialogCallback { + + private final Component parentComponent; + private final PersonaUIComponents personaUIComponents; + + /** + * Creates a callback to handle new persona creation. + * + * @param personaUIComponents UI Components. + */ + PersonaCreateCallbackImpl(Component parentComponent, PersonaUIComponents personaUIComponents) { + this.parentComponent = parentComponent; + this.personaUIComponents = personaUIComponents; + } + + @Override + public void callback(Persona persona) { + JButton personaButton = personaUIComponents.getPersonaActionButton(); + if (persona != null) { + // update the persona name label with newly created persona, + // and change the button to a "View" button + personaUIComponents.getPersonaNameLabel().setText(persona.getName()); + personaUIComponents.getPersonaActionButton().setText(Bundle.ContactArtifactViewer_persona_button_view()); + + // replace action listener with a View button listener + for (ActionListener act : personaButton.getActionListeners()) { + personaButton.removeActionListener(act); + } + personaButton.addActionListener(new ViewPersonaButtonListener(parentComponent, persona)); + + } + + personaButton.getParent().revalidate(); + personaButton.getParent().repaint(); + } + } + + /** + * Callback method for the view mode of the PersonaDetailsDialog + */ + class PersonaViewCallbackImpl implements PersonaDetailsDialogCallback { + + @Override + public void callback(Persona persona) { + // nothing to do + } + } + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JPanel contactDetailsPanel; + private javax.swing.Box.Filler filler1; + private javax.swing.JPanel personasPanel; + private javax.swing.JPanel sourcePanel; // 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 From 4eb183575c027414668d6e35ce3c775850ac2d42 Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Mon, 22 Jun 2020 13:52:03 -0400 Subject: [PATCH 4/9] Redid the Contact artifact viewer with a single panel. --- .../AbstractCommunicationArtifactViewer.java | 56 ++++ .../contentviewers/CallLogArtifactViewer.java | 7 +- .../CommunicationArtifactViewerHelper.java | 62 ++-- .../ContactArtifactViewerNew.form | 44 --- .../ContactArtifactViewerNew.java | 307 +++++++----------- 5 files changed, 216 insertions(+), 260 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/AbstractCommunicationArtifactViewer.java diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AbstractCommunicationArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/AbstractCommunicationArtifactViewer.java new file mode 100644 index 0000000000..e682bc22c2 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/AbstractCommunicationArtifactViewer.java @@ -0,0 +1,56 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.contentviewers; + +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; +import org.openide.util.NbBundle; +import org.openide.windows.WindowManager; + +/** + * + * An abstract base class for communication artifact viewers. + */ +@NbBundle.Messages({ + "CommunicationArtifactViewer_cr_disabled_title=Central Repository disabled.", + "CommunicationArtifactViewer_cr_disabled_message=Central Repository is disabled. Persona infomation cannot be displayed.",}) +public abstract class AbstractCommunicationArtifactViewer extends javax.swing.JPanel implements ArtifactContentViewer { + + private static final long serialVersionUID = 1L; + + private boolean centralrepoDisabledDialogShown = false; + + /** + * Displays a dialog to user that Central Repository is disabled. + * + */ + void showCentralRepoDisabledDialog() { + if (centralrepoDisabledDialogShown) { + return; + } + + SwingUtilities.invokeLater(() -> { + JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), + Bundle.CommunicationArtifactViewer_cr_disabled_message(), + Bundle.CommunicationArtifactViewer_cr_disabled_title(), + JOptionPane.INFORMATION_MESSAGE); + }); + centralrepoDisabledDialogShown = true; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java index 99b662f52a..1959591cda 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; @@ -48,7 +49,7 @@ import org.sleuthkit.datamodel.TskCoreException; * Displays the To/From and other parties, and metadata for a call. */ @ServiceProvider(service = ArtifactContentViewer.class) -public class CallLogArtifactViewer extends javax.swing.JPanel implements ArtifactContentViewer { +public class CallLogArtifactViewer extends AbstractCommunicationArtifactViewer { private final static Logger logger = Logger.getLogger(CallLogArtifactViewer.class.getName()); private static final long serialVersionUID = 1L; @@ -92,6 +93,10 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac public void setArtifact(BlackboardArtifact artifact) { resetComponent(); + if (CentralRepository.isEnabled() == false) { + this.showCentralRepoDisabledDialog(); + } + CallLogViewData callLogViewData = null; try { callLogViewData = getCallLogViewData(artifact); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java b/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java index 64f9799266..3527a680af 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java @@ -48,14 +48,14 @@ public final class CommunicationArtifactViewerHelper { private final static int MAX_COLS = 4; private final static int LEFT_INDENT = 12; - + /** * Empty private constructor */ private CommunicationArtifactViewerHelper() { } - + /** * Adds a new heading to the panel. * @@ -63,14 +63,14 @@ 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 JLabel addHeader(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String headerString) { // 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) { @@ -97,13 +97,13 @@ public final class CommunicationArtifactViewerHelper { // add line end glue addLineEndGlue(panel, gridbagLayout, constraints); - + 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. @@ -112,15 +112,15 @@ public final class CommunicationArtifactViewerHelper { * @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); // add line end glue - addLineEndGlue(panel, gridbagLayout, constraints); + //addLineEndGlue(panel, gridbagLayout, constraints); } - + /** * Adds a filler/glue at the end of the line to keep the other columns * aligned, in case the panel is resized. @@ -129,7 +129,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; @@ -200,13 +200,13 @@ public final class CommunicationArtifactViewerHelper { * @param gridbagLayout Layout to use. * @param constraints Constrains to use. * @param keyString Key name to display. - * + * * @return Label added. */ - static JLabel addKey(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String keyString) { - return addKeyAtCol(panel, gridbagLayout, constraints, keyString, 0 ); - } - + 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. * @@ -215,16 +215,16 @@ public final class CommunicationArtifactViewerHelper { * @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 ) { - + static JLabel addKeyAtCol(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String keyString, int gridx) { + // create label javax.swing.JLabel keyLabel = new javax.swing.JLabel(); - + constraints.gridy++; - constraints.gridx = gridx < MAX_COLS - 1? gridx : MAX_COLS - 2; + constraints.gridx = gridx < MAX_COLS - 1 ? gridx : MAX_COLS - 2; Insets savedInsets = constraints.insets; @@ -240,7 +240,7 @@ public final class CommunicationArtifactViewerHelper { // restore inset constraints.insets = savedInsets; - + return keyLabel; } @@ -251,13 +251,13 @@ public final class CommunicationArtifactViewerHelper { * @param gridbagLayout Layout to use. * @param constraints Constrains to use. * @param keyString Value string to display. - * + * * @return Label added. */ static JLabel addValue(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String valueString) { - return addValueAtCol(panel, gridbagLayout, constraints, valueString, 1); + return addValueAtCol(panel, gridbagLayout, constraints, valueString, 1); } - + /** * Adds a value string to the panel at col 1. * @@ -266,21 +266,21 @@ public final class CommunicationArtifactViewerHelper { * @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, + // create label, javax.swing.JLabel valueField = new javax.swing.JLabel(); - - constraints.gridx = gridx < MAX_COLS ? gridx : MAX_COLS - 1 ; + + constraints.gridx = gridx < MAX_COLS ? gridx : MAX_COLS - 1; int savedGridwidth = constraints.gridwidth; // let the value span 2 cols constraints.gridwidth = 2; - // set text + // set text valueField.setText(valueString); // attach a right click menu with Copy option @@ -300,7 +300,7 @@ public final class CommunicationArtifactViewerHelper { // end the line addLineEndGlue(panel, gridbagLayout, constraints); - + return valueField; } @@ -361,8 +361,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/ContactArtifactViewerNew.form b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.form index 0a86676ba7..806a0e3de5 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.form @@ -18,48 +18,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java index cedf42544e..08339b9a53 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java @@ -65,15 +65,18 @@ import org.sleuthkit.datamodel.TskCoreException; * This class displays the TSK_CONTACT artifact. */ @ServiceProvider(service = ArtifactContentViewer.class) -public class ContactArtifactViewerNew extends javax.swing.JPanel implements ArtifactContentViewer { +public class ContactArtifactViewerNew extends AbstractCommunicationArtifactViewer { private final static Logger logger = Logger.getLogger(ContactArtifactViewer.class.getName()); private static final long serialVersionUID = 1L; private final static int LEFT_INSET = 12; - //private GridBagLayout m_gridBagLayout = new GridBagLayout(); - //private GridBagConstraints m_constraints = new GridBagConstraints(); + private GridBagLayout m_gridBagLayout = new GridBagLayout(); + private GridBagConstraints m_constraints = new GridBagConstraints(); + + private JLabel personaSearchStatusLabel; + private BlackboardArtifact contactArtifact; private String contactName; private String datasourceName; @@ -113,45 +116,9 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { - java.awt.GridBagConstraints gridBagConstraints; - - contactDetailsPanel = new javax.swing.JPanel(); - personasPanel = new javax.swing.JPanel(); - sourcePanel = new javax.swing.JPanel(); - filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767)); setToolTipText(""); // NOI18N setLayout(new java.awt.GridBagLayout()); - - contactDetailsPanel.setLayout(new java.awt.GridBagLayout()); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 0; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - add(contactDetailsPanel, gridBagConstraints); - - personasPanel.setLayout(new java.awt.GridBagLayout()); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 1; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - add(personasPanel, gridBagConstraints); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 2; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - add(sourcePanel, gridBagConstraints); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 4; - gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.weightx = 1.0; - gridBagConstraints.weighty = 1.0; - add(filler1, gridBagConstraints); }// //GEN-END:initComponents @Override @@ -170,8 +137,13 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti return; } + if (CentralRepository.isEnabled() == false) { + showCentralRepoDisabledDialog(); + } + updateView(); + this.setLayout(this.m_gridBagLayout); this.revalidate(); this.repaint(); } @@ -232,11 +204,12 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti // 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(); - // update artifact source panel - updateSource(); } /** @@ -244,66 +217,49 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti */ @NbBundle.Messages({ "ContactArtifactViewer_phones_header=Phone", - "ContactArtifactViewer_eamils_header=Email", + "ContactArtifactViewer_emails_header=Email", "ContactArtifactViewer_others_header=Other",}) private void updateContactDetails() { - GridBagLayout contactPanelLayout = new GridBagLayout(); - GridBagConstraints contactPanelConstraints = new GridBagConstraints(); - contactPanelConstraints.anchor = GridBagConstraints.FIRST_LINE_START; - contactPanelConstraints.gridy = 0; - contactPanelConstraints.gridx = 0; - contactPanelConstraints.weighty = 0.05; - contactPanelConstraints.weightx = 0.05; - contactPanelConstraints.insets = new java.awt.Insets(0, 0, 0, 0); - contactPanelConstraints.fill = GridBagConstraints.NONE; - - updateContactImage(contactPanelLayout, contactPanelConstraints); - - // update name section - updateContactName(contactPanelLayout, contactPanelConstraints); + // update image and name. + updateContactImage(m_gridBagLayout, m_constraints); + updateContactName(m_gridBagLayout, m_constraints); // update contact attributes sections - updateContactMethodSection(phoneNumList, Bundle.ContactArtifactViewer_phones_header(), contactPanelLayout, contactPanelConstraints); - updateContactMethodSection(emailList, Bundle.ContactArtifactViewer_eamils_header(), contactPanelLayout, contactPanelConstraints); - updateContactMethodSection(otherList, Bundle.ContactArtifactViewer_others_header(), contactPanelLayout, contactPanelConstraints); - - CommunicationArtifactViewerHelper.addBlankLine(this.contactDetailsPanel, contactPanelLayout, contactPanelConstraints); - - contactDetailsPanel.setLayout(contactPanelLayout); - contactDetailsPanel.revalidate(); - contactDetailsPanel.repaint(); + 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 artifact + * @param contactPanelLayout Panel layout. + * @param contactPanelConstraints Layout constraints. + * */ @NbBundle.Messages({ "ContactArtifactViewer.contactImage.text=",}) private void updateContactImage(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) { - contactPanelConstraints.gridy = 0; contactPanelConstraints.gridx = 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.contactDetailsPanel, contactPanelLayout, contactPanelConstraints, contactImage); + CommunicationArtifactViewerHelper.addComponent(this, contactPanelLayout, contactPanelConstraints, contactImage); + CommunicationArtifactViewerHelper.addLineEndGlue(this, contactPanelLayout, contactPanelConstraints); contactPanelConstraints.gridy++; - } /** - * Updates the contact name in the view from the list of attributes. + * Updates the contact name in the view. + * + * @param contactPanelLayout Panel layout. + * @param contactPanelConstraints Layout constraints. * - * @param attributesList List of attributes that might have the contact - * name. */ @NbBundle.Messages({ "ContactArtifactViewer_contactname_unknown=Unknown",}) @@ -314,13 +270,13 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti if (StringUtils.isEmpty(bba.getValueString()) == false) { contactName = bba.getDisplayString(); - CommunicationArtifactViewerHelper.addHeader(this.contactDetailsPanel, contactPanelLayout, contactPanelConstraints, contactName); + CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, contactName); foundName = true; break; } } if (foundName == false) { - CommunicationArtifactViewerHelper.addHeader(this.contactDetailsPanel, contactPanelLayout, contactPanelConstraints, Bundle.ContactArtifactViewer_contactname_unknown()); + CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, Bundle.ContactArtifactViewer_contactname_unknown()); } } @@ -328,8 +284,11 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti * 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 sectionAttributesList List of attributes to display. + * @param sectionLabel Section name label. + * @param contactPanelLayout Panel layout. + * @param contactPanelConstraints Layout constraints. + * */ @NbBundle.Messages({ "ContactArtifactViewer_plural_suffix=s",}) @@ -344,10 +303,10 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti if (sectionAttributesList.size() > 1) { sectionHeaderString = sectionHeaderString.concat(Bundle.ContactArtifactViewer_plural_suffix()); } - CommunicationArtifactViewerHelper.addHeader(this.contactDetailsPanel, contactPanelLayout, contactPanelConstraints, sectionHeaderString); + CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, sectionHeaderString); for (BlackboardAttribute bba : sectionAttributesList) { - CommunicationArtifactViewerHelper.addKey(this.contactDetailsPanel, contactPanelLayout, contactPanelConstraints, bba.getAttributeType().getDisplayName()); - CommunicationArtifactViewerHelper.addValue(this.contactDetailsPanel, contactPanelLayout, contactPanelConstraints, bba.getDisplayString()); + CommunicationArtifactViewerHelper.addKey(this, contactPanelLayout, contactPanelConstraints, bba.getAttributeType().getDisplayName()); + CommunicationArtifactViewerHelper.addValue(this, contactPanelLayout, contactPanelConstraints, bba.getDisplayString()); } } @@ -358,25 +317,9 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti "ContactArtifactViewer_heading_Source=Source", "ContactArtifactViewer_label_datasource=Data Source",}) private void updateSource() { - - GridBagLayout sourcePanelLayout = new GridBagLayout(); - GridBagConstraints sourcePanelConstraints = new GridBagConstraints(); - - sourcePanelConstraints.anchor = GridBagConstraints.FIRST_LINE_START; - sourcePanelConstraints.gridy = 0; - sourcePanelConstraints.gridx = 0; - sourcePanelConstraints.weighty = 0.05; - sourcePanelConstraints.weightx = 0.05; - sourcePanelConstraints.insets = new java.awt.Insets(0, 0, 0, 0); - sourcePanelConstraints.fill = GridBagConstraints.NONE; - - CommunicationArtifactViewerHelper.addHeader(this.sourcePanel, sourcePanelLayout, sourcePanelConstraints, Bundle.ContactArtifactViewer_heading_Source()); - CommunicationArtifactViewerHelper.addKey(this.sourcePanel, sourcePanelLayout, sourcePanelConstraints, Bundle.ContactArtifactViewer_label_datasource()); - CommunicationArtifactViewerHelper.addValue(this.sourcePanel, sourcePanelLayout, sourcePanelConstraints, datasourceName); - - sourcePanel.setLayout(sourcePanelLayout); - sourcePanel.revalidate(); - sourcePanel.repaint(); + 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); } /** @@ -391,36 +334,33 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti //"ContactArtifactViewer_persona_unknown=Unknown" }) + /** + * Initiates a search for Personas for the accounts associated with the + * Contact. + * + */ private void initiatePersonasSearch() { - GridBagLayout personasPanelLayout = new GridBagLayout(); - GridBagConstraints personasPanelConstraints = new GridBagConstraints(); - - personasPanelConstraints.anchor = GridBagConstraints.FIRST_LINE_START; - personasPanelConstraints.gridy = 0; - personasPanelConstraints.gridx = 0; - personasPanelConstraints.weighty = 0.05; - personasPanelConstraints.weightx = 0.05; - personasPanelConstraints.insets = new java.awt.Insets(0, 0, 0, 0); - personasPanelConstraints.fill = GridBagConstraints.NONE; - // add a section header - JLabel personaHeader = CommunicationArtifactViewerHelper.addHeader(this.personasPanel, personasPanelLayout, personasPanelConstraints, Bundle.ContactArtifactViewer_persona_header()); + JLabel personaHeader = CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_persona_header()); - personasPanelConstraints.gridy++; + m_constraints.gridy++; + + Insets savedInsets = m_constraints.insets; // add a status label String personaStatusLabelText = CentralRepository.isEnabled() ? Bundle.ContactArtifactViewer_persona_searching() : Bundle.ContactArtifactViewer_persona_unknown(); - javax.swing.JLabel statusLabel = new javax.swing.JLabel(); - statusLabel.setText(personaStatusLabelText); + this.personaSearchStatusLabel = new javax.swing.JLabel(); + personaSearchStatusLabel.setText(personaStatusLabelText); - CommunicationArtifactViewerHelper.addComponent(this.personasPanel, personasPanelLayout, personasPanelConstraints, statusLabel); + m_constraints.gridx = 0; + Insets labelInsets = new java.awt.Insets(0, LEFT_INSET, 0, 0); + m_constraints.insets = labelInsets; - // End of panel, add a blank line - CommunicationArtifactViewerHelper.addBlankLine(this.personasPanel, personasPanelLayout, personasPanelConstraints); + CommunicationArtifactViewerHelper.addComponent(this, m_gridBagLayout, m_constraints, personaSearchStatusLabel); if (CentralRepository.isEnabled()) { // Kick off a background task to serach for personas for the contact @@ -428,40 +368,30 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti personaSearchTask.execute(); } else { personaHeader.setEnabled(false); - statusLabel.setEnabled(false); + personaSearchStatusLabel.setEnabled(false); } - personasPanel.setLayout(personasPanelLayout); - personasPanel.revalidate(); - personasPanel.repaint(); - + m_constraints.insets = savedInsets; } /** * Updates the Persona panel with the gathered persona information. */ private void updatePersonas() { - // Clear out the panel - personasPanel.removeAll(); - GridBagLayout personasPanelLayout = new GridBagLayout(); - GridBagConstraints personasPanelConstraints = new GridBagConstraints(); - personasPanelConstraints.anchor = GridBagConstraints.FIRST_LINE_START; - personasPanelConstraints.gridx = 0; - personasPanelConstraints.gridy = 0; - personasPanelConstraints.insets = new java.awt.Insets(0, 0, 0, 0); - - // add a section header - CommunicationArtifactViewerHelper.addHeader(this.personasPanel, personasPanelLayout, personasPanelConstraints, Bundle.ContactArtifactViewer_persona_header()); - - personasPanelConstraints.gridy++; + // Remove the "Searching....." label + this.remove(personaSearchStatusLabel); + m_constraints.gridx = 0; if (contactUniquePersonasMap.isEmpty()) { - showPersona(null, Collections.emptyList(), personasPanelLayout, personasPanelConstraints); + // 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) { @@ -470,17 +400,18 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti } } - showPersona(entry.getKey(), missingAccounts, personasPanelLayout, personasPanelConstraints); - personasPanelConstraints.gridy += 2; + showPersona(entry.getKey(), matchCounter, missingAccounts, m_gridBagLayout, m_constraints); + m_constraints.gridy += 2; } } - CommunicationArtifactViewerHelper.addBlankLine(this.personasPanel, personasPanelLayout, personasPanelConstraints); + // add veritcal glue at the end + CommunicationArtifactViewerHelper.addPageEndGlue(this, m_gridBagLayout, this.m_constraints); - personasPanel.setLayout(personasPanelLayout); - personasPanel.setSize(personasPanel.getPreferredSize()); - personasPanel.revalidate(); - personasPanel.repaint(); + // redraw the panel + this.setLayout(this.m_gridBagLayout); + this.revalidate(); + this.repaint(); } /** @@ -496,82 +427,82 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti */ @NbBundle.Messages({ "ContactArtifactViewer_persona_label=Persona ", - "ContactArtifactViewer_persona_name_unknown=Unknown", + "ContactArtifactViewer_persona_no_match=No matches found", "ContactArtifactViewer_persona_button_view=View", "ContactArtifactViewer_persona_button_new=Create", - "ContactArtifactViewer_missing_account_label=Contact account not in persona", - "ContactArtifactViewer_found_all_accounts_label=All contact accounts are in persona" + "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, List missingAccountsList, GridBagLayout gridBagLayout, GridBagConstraints constraints) { + private void showPersona(Persona persona, int matchNumber, List missingAccountsList, GridBagLayout gridBagLayout, GridBagConstraints constraints) { + // save the original insets Insets savedInsets = constraints.insets; + // keys are inset with an indent. Insets labelInsets = new java.awt.Insets(0, LEFT_INSET, 0, 0); - //constraints.fill = GridBagConstraints.NONE; - //constraints.weightx = 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); + // 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 personaNameLabel = new javax.swing.JLabel(); javax.swing.JButton personaButton = new javax.swing.JButton(); String personaName; String personaButtonText; ActionListener personaButtonListener; - if (persona != null) { personaName = persona.getName(); personaButtonText = Bundle.ContactArtifactViewer_persona_button_view(); personaButtonListener = new ViewPersonaButtonListener(this, persona); } else { - personaName = Bundle.ContactArtifactViewer_persona_name_unknown(); + matchNumberLabel.setVisible(false); + personaName = Bundle.ContactArtifactViewer_persona_no_match(); personaButtonText = Bundle.ContactArtifactViewer_persona_button_new(); personaButtonListener = new CreatePersonaButtonListener(this, new PersonaUIComponents(personaNameLabel, personaButton)); } - // Add the label for persona name, - constraints.insets = labelInsets; - constraints.gridx = 0; - constraints.gridwidth = 2; // TBD: this may not be needed if we use single panel + //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); // Add a Persona action button - constraints.gridx += 2; - constraints.gridwidth = 1; + constraints.gridx++; + //constraints.gridwidth = 1; personaButton.setText(personaButtonText); personaButton.addActionListener(personaButtonListener); - 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); - constraints.insets = labelInsets; + constraints.insets = savedInsets; // 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++; - CommunicationArtifactViewerHelper.addKeyAtCol(personasPanel, gridBagLayout, constraints, Bundle.ContactArtifactViewer_found_all_accounts_label(), 2); + constraints.gridx = 1; + constraints.insets = labelInsets; + + javax.swing.JLabel accountsStatus = new javax.swing.JLabel(Bundle.ContactArtifactViewer_found_all_accounts_label()); + CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, accountsStatus); + CommunicationArtifactViewerHelper.addLineEndGlue(this, gridBagLayout, constraints); } else { // show missing accounts. for (CentralRepoAccount missingAccount : missingAccountsList) { - constraints.weightx = 0; + //constraints.weightx = 0; constraints.gridx = 0; constraints.gridy++; - CommunicationArtifactViewerHelper.addKeyAtCol(personasPanel, gridBagLayout, constraints, Bundle.ContactArtifactViewer_missing_account_label(), 2); - CommunicationArtifactViewerHelper.addValueAtCol(personasPanel, gridBagLayout, constraints, missingAccount.getIdentifier(), 3); + CommunicationArtifactViewerHelper.addKeyAtCol(this, gridBagLayout, constraints, Bundle.ContactArtifactViewer_missing_account_label(), 1); + CommunicationArtifactViewerHelper.addValueAtCol(this, gridBagLayout, constraints, missingAccount.getIdentifier(), 2); } } } @@ -603,9 +534,21 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti personaSearchTask = null; } - this.contactDetailsPanel.removeAll(); - this.personasPanel.removeAll(); - this.sourcePanel.removeAll(); + // 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.05; + m_constraints.weightx = 0.05; + m_constraints.insets = new java.awt.Insets(0, 0, 0, 0); + m_constraints.fill = GridBagConstraints.NONE; + } /** @@ -904,9 +847,5 @@ public class ContactArtifactViewerNew extends javax.swing.JPanel implements Arti } // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JPanel contactDetailsPanel; - private javax.swing.Box.Filler filler1; - private javax.swing.JPanel personasPanel; - private javax.swing.JPanel sourcePanel; // End of variables declaration//GEN-END:variables } From 48f0fbee558a3f36baad3404e4fae9e21c8cbb81 Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Tue, 23 Jun 2020 08:21:34 -0400 Subject: [PATCH 5/9] Interim commit. - Removed the Popup to indicate CR disabled, replaced with a message at the bottom of the artifact viewer. - cleanup and spacing tweaks. --- .../AbstractCommunicationArtifactViewer.java | 56 ----------------- .../contentviewers/CallLogArtifactViewer.java | 50 ++++++++++++--- .../CommunicationArtifactViewerHelper.java | 62 +++++++++++++++---- .../contentviewers/ContactArtifactViewer.java | 4 -- .../ContactArtifactViewerNew.java | 52 ++++++++++------ 5 files changed, 125 insertions(+), 99 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/AbstractCommunicationArtifactViewer.java diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AbstractCommunicationArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/AbstractCommunicationArtifactViewer.java deleted file mode 100644 index e682bc22c2..0000000000 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/AbstractCommunicationArtifactViewer.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2020 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.contentviewers; - -import javax.swing.JOptionPane; -import javax.swing.SwingUtilities; -import org.openide.util.NbBundle; -import org.openide.windows.WindowManager; - -/** - * - * An abstract base class for communication artifact viewers. - */ -@NbBundle.Messages({ - "CommunicationArtifactViewer_cr_disabled_title=Central Repository disabled.", - "CommunicationArtifactViewer_cr_disabled_message=Central Repository is disabled. Persona infomation cannot be displayed.",}) -public abstract class AbstractCommunicationArtifactViewer extends javax.swing.JPanel implements ArtifactContentViewer { - - private static final long serialVersionUID = 1L; - - private boolean centralrepoDisabledDialogShown = false; - - /** - * Displays a dialog to user that Central Repository is disabled. - * - */ - void showCentralRepoDisabledDialog() { - if (centralrepoDisabledDialogShown) { - return; - } - - SwingUtilities.invokeLater(() -> { - JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), - Bundle.CommunicationArtifactViewer_cr_disabled_message(), - Bundle.CommunicationArtifactViewer_cr_disabled_title(), - JOptionPane.INFORMATION_MESSAGE); - }); - centralrepoDisabledDialogShown = true; - } -} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java index 1959591cda..ca701d0086 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java @@ -49,7 +49,7 @@ import org.sleuthkit.datamodel.TskCoreException; * Displays the To/From and other parties, and metadata for a call. */ @ServiceProvider(service = ArtifactContentViewer.class) -public class CallLogArtifactViewer extends AbstractCommunicationArtifactViewer { +public class CallLogArtifactViewer extends javax.swing.JPanel implements ArtifactContentViewer { private final static Logger logger = Logger.getLogger(CallLogArtifactViewer.class.getName()); private static final long serialVersionUID = 1L; @@ -93,10 +93,6 @@ public class CallLogArtifactViewer extends AbstractCommunicationArtifactViewer { public void setArtifact(BlackboardArtifact artifact) { resetComponent(); - if (CentralRepository.isEnabled() == false) { - this.showCentralRepoDisabledDialog(); - } - CallLogViewData callLogViewData = null; try { callLogViewData = getCallLogViewData(artifact); @@ -340,8 +336,15 @@ public class CallLogArtifactViewer extends AbstractCommunicationArtifactViewer { } updateMetadataView(callLogViewData); + + updateOtherAttributesView(callLogViewData); + updateSourceView(callLogViewData); + if (CentralRepository.isEnabled() == false) { + showCRDisabledMessage(); + } + CommunicationArtifactViewerHelper.addPageEndGlue(this, m_gridBagLayout, this.m_constraints); this.setLayout(m_gridBagLayout); @@ -397,6 +400,37 @@ public class CallLogArtifactViewer extends AbstractCommunicationArtifactViewer { CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, callLogViewData.getDataSourceName()); } + /** + * Update the other attributes section. + * + * @param callLogViewData + */ + @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 @@ -446,9 +480,9 @@ public class CallLogArtifactViewer extends AbstractCommunicationArtifactViewer { 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 3527a680af..df88d627ae 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java @@ -47,7 +47,7 @@ public 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 @@ -68,6 +68,8 @@ public final class CommunicationArtifactViewerHelper { */ 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(); @@ -81,6 +83,7 @@ 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 // set text headingLabel.setText(headerString); @@ -98,6 +101,9 @@ public final class CommunicationArtifactViewerHelper { // add line end glue addLineEndGlue(panel, gridbagLayout, constraints); + //restore insets + constraints.insets = savedInsets; + return headingLabel; } @@ -226,11 +232,6 @@ public final class CommunicationArtifactViewerHelper { constraints.gridy++; 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); - // set text keyLabel.setText(keyString + ": "); @@ -238,9 +239,6 @@ public final class CommunicationArtifactViewerHelper { gridbagLayout.setConstraints(keyLabel, constraints); panel.add(keyLabel); - // restore inset - constraints.insets = savedInsets; - return keyLabel; } @@ -304,6 +302,48 @@ public final class CommunicationArtifactViewerHelper { return valueField; } + /** + * Displays a message string 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); + } + + 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; + } + /** * Adds a Persona row to the panel. * @@ -337,8 +377,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(); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java index 7d67dfc5e0..0533c6fae4 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java @@ -444,10 +444,6 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac * * @throws CentralRepoException */ - @NbBundle.Messages({ - "ContactArtifactViewer_persona_searching= Searching...", - "ContactArtifactViewer_persona_unknown=Unknown" - }) private void initiatePersonasSearch(List accountAttributesList) throws CentralRepoException { personasLabel.setVisible(true); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java index 08339b9a53..c6261bf5ff 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java @@ -65,13 +65,12 @@ import org.sleuthkit.datamodel.TskCoreException; * This class displays the TSK_CONTACT artifact. */ @ServiceProvider(service = ArtifactContentViewer.class) -public class ContactArtifactViewerNew extends AbstractCommunicationArtifactViewer { +public class ContactArtifactViewerNew extends javax.swing.JPanel implements ArtifactContentViewer { private final static Logger logger = Logger.getLogger(ContactArtifactViewer.class.getName()); private static final long serialVersionUID = 1L; - private final static int LEFT_INSET = 12; - + //private final static int LEFT_INSET = 12; private GridBagLayout m_gridBagLayout = new GridBagLayout(); private GridBagConstraints m_constraints = new GridBagConstraints(); @@ -137,10 +136,6 @@ public class ContactArtifactViewerNew extends AbstractCommunicationArtifactViewe return; } - if (CentralRepository.isEnabled() == false) { - showCentralRepoDisabledDialog(); - } - updateView(); this.setLayout(this.m_gridBagLayout); @@ -241,8 +236,11 @@ public class ContactArtifactViewerNew extends AbstractCommunicationArtifactViewe @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)); @@ -252,6 +250,8 @@ public class ContactArtifactViewerNew extends AbstractCommunicationArtifactViewe CommunicationArtifactViewerHelper.addComponent(this, contactPanelLayout, contactPanelConstraints, contactImage); CommunicationArtifactViewerHelper.addLineEndGlue(this, contactPanelLayout, contactPanelConstraints); contactPanelConstraints.gridy++; + + contactPanelConstraints.insets = savedInsets; } /** @@ -330,8 +330,10 @@ public class ContactArtifactViewerNew extends AbstractCommunicationArtifactViewe * @throws CentralRepoException */ @NbBundle.Messages({ - "ContactArtifactViewer_persona_header=Persona", //"ContactArtifactViewer_persona_searching = Searching...", - //"ContactArtifactViewer_persona_unknown=Unknown" + "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" }) /** @@ -346,8 +348,6 @@ public class ContactArtifactViewerNew extends AbstractCommunicationArtifactViewe m_constraints.gridy++; - Insets savedInsets = m_constraints.insets; - // add a status label String personaStatusLabelText = CentralRepository.isEnabled() ? Bundle.ContactArtifactViewer_persona_searching() @@ -357,8 +357,6 @@ public class ContactArtifactViewerNew extends AbstractCommunicationArtifactViewe personaSearchStatusLabel.setText(personaStatusLabelText); m_constraints.gridx = 0; - Insets labelInsets = new java.awt.Insets(0, LEFT_INSET, 0, 0); - m_constraints.insets = labelInsets; CommunicationArtifactViewerHelper.addComponent(this, m_gridBagLayout, m_constraints, personaSearchStatusLabel); @@ -369,9 +367,16 @@ public class ContactArtifactViewerNew extends AbstractCommunicationArtifactViewe } else { 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); } - m_constraints.insets = savedInsets; + //m_constraints.insets = savedInsets; } /** @@ -439,8 +444,8 @@ public class ContactArtifactViewerNew extends AbstractCommunicationArtifactViewe // save the original insets Insets savedInsets = constraints.insets; - // keys are inset with an indent. - Insets labelInsets = new java.awt.Insets(0, LEFT_INSET, 0, 0); + // 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; @@ -489,10 +494,13 @@ public class ContactArtifactViewerNew extends AbstractCommunicationArtifactViewe if (missingAccountsList.isEmpty()) { constraints.gridy++; constraints.gridx = 1; - constraints.insets = labelInsets; + //constraints.insets = labelInsets; 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; + CommunicationArtifactViewerHelper.addLineEndGlue(this, gridBagLayout, constraints); } else { // show missing accounts. @@ -501,7 +509,11 @@ public class ContactArtifactViewerNew extends AbstractCommunicationArtifactViewe 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); } } @@ -544,9 +556,9 @@ public class ContactArtifactViewerNew extends AbstractCommunicationArtifactViewe 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; } From d9ff5d9f6809d34b140342fa45049d1fe2ec3cc5 Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Tue, 23 Jun 2020 09:02:44 -0400 Subject: [PATCH 6/9] Deleted old ContactArtifactViewer and renamed ContactArtifactViewerNew to ContactArtifactViewer. --- .../contentviewers/CallLogArtifactViewer.java | 8 +- .../contentviewers/ContactArtifactViewer.form | 216 +---- .../contentviewers/ContactArtifactViewer.java | 771 +++++++--------- .../ContactArtifactViewerNew.form | 21 - .../ContactArtifactViewerNew.java | 863 ------------------ 5 files changed, 360 insertions(+), 1519 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.form delete mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java index ca701d0086..becf098a45 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java @@ -93,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); @@ -458,7 +462,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()); } /** 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 0533c6fae4..7e5f346927 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; @@ -64,17 +64,29 @@ import org.sleuthkit.datamodel.TskCoreException; /** * This class displays the TSK_CONTACT artifact. */ -//@ServiceProvider(service = ArtifactContentViewer.class) +@ServiceProvider(service = ArtifactContentViewer.class) public class ContactArtifactViewer extends javax.swing.JPanel implements ArtifactContentViewer { 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,200 +148,255 @@ 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 */ - private void initiatePersonasSearch(List accountAttributesList) throws CentralRepoException { + @NbBundle.Messages({ + "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" + }) - 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(); + //m_constraints.insets = savedInsets; } /** * 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) { @@ -524,52 +405,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(); @@ -577,59 +457,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; + } /** @@ -638,7 +569,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; @@ -662,7 +593,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. } @@ -688,7 +619,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; @@ -699,6 +630,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 @@ -732,7 +664,6 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac } } } - } return uniquePersonas; @@ -754,7 +685,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 @@ -779,7 +710,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) { @@ -811,6 +742,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac */ private class CreatePersonaButtonListener implements ActionListener { + private final Component parentComponent; private final PersonaUIComponents personaUIComponents; /** @@ -818,19 +750,20 @@ 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({ - // "ContactArtifactViewer_persona_account_justification=Account found in Contact artifact" + "ContactArtifactViewer_persona_account_justification=Account found in Contact artifact" }) @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(); @@ -855,19 +788,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()); } } @@ -877,6 +812,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac */ class PersonaCreateCallbackImpl implements PersonaDetailsDialogCallback { + private final Component parentComponent; private final PersonaUIComponents personaUIComponents; /** @@ -884,7 +820,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; } @@ -901,7 +838,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)); } @@ -921,18 +858,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/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.form b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.form deleted file mode 100644 index 806a0e3de5..0000000000 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.form +++ /dev/null @@ -1,21 +0,0 @@ - - -
- - - - - - - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java deleted file mode 100644 index c6261bf5ff..0000000000 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewerNew.java +++ /dev/null @@ -1,863 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2020 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.contentviewers; - -import java.awt.Component; -import 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; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; -import java.util.logging.Level; -import java.util.stream.Collectors; -import javax.imageio.ImageIO; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JScrollPane; -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; -import org.sleuthkit.autopsy.centralrepository.datamodel.Persona; -import org.sleuthkit.autopsy.centralrepository.datamodel.PersonaAccount; -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.coreutils.Logger; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * This class displays the TSK_CONTACT artifact. - */ -@ServiceProvider(service = ArtifactContentViewer.class) -public class ContactArtifactViewerNew extends javax.swing.JPanel implements ArtifactContentViewer { - - private final static Logger logger = Logger.getLogger(ContactArtifactViewer.class.getName()); - private static final long serialVersionUID = 1L; - - //private final static int LEFT_INSET = 12; - private GridBagLayout m_gridBagLayout = new GridBagLayout(); - private GridBagConstraints m_constraints = new GridBagConstraints(); - - 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<>(); - - // A list of all unique personas and their account, found by searching on the - // account identifier attributes of the Contact artifact. - private final Map> contactUniquePersonasMap = new HashMap<>(); - - private ContactPersonaSearcherTask personaSearchTask; - - /** - * Creates new form ContactArtifactViewer - */ - public ContactArtifactViewerNew() { - initComponents(); - - defaultImage = new ImageIcon(ContactArtifactViewer.class.getResource(DEFAULT_IMAGE_PATH)); - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - - setToolTipText(""); // NOI18N - setLayout(new java.awt.GridBagLayout()); - }// //GEN-END:initComponents - - @Override - public void setArtifact(BlackboardArtifact artifact) { - // Reset the panel. - resetComponent(); - - if (artifact == null) { - return; - } - - 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(); - } - - @Override - public Component getComponent() { - // Slap a vertical scrollbar on the panel. - return new JScrollPane(this, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); - } - - @Override - public boolean isSupported(BlackboardArtifact artifact) { - return artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID(); - } - - /** - * 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 { - - 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 contactPanelLayout Panel layout. - * @param contactPanelConstraints Layout constraints. - * - */ - @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(); - - CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, contactName); - foundName = true; - break; - } - } - 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 contactPanelLayout Panel layout. - * @param contactPanelConstraints Layout constraints. - * - */ - @NbBundle.Messages({ - "ContactArtifactViewer_plural_suffix=s",}) - private void updateContactMethodSection(List sectionAttributesList, String sectionHeader, GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) { - - // If there are no attributes for this section, do nothing - if (sectionAttributesList.isEmpty()) { - return; - } - - 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()); - } - } - - /** - * 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_header=Persona", - "ContactArtifactViewer_persona_searching=Searching...", - "ContactArtifactViewer_cr_disabled_message=Enable Central Repository to view, create and edit personas.", - "ContactArtifactViewer_persona_unknown=Unknown" - }) - - /** - * Initiates a search for Personas for the accounts associated with the - * Contact. - * - */ - private void initiatePersonasSearch() { - - // 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(); - - this.personaSearchStatusLabel = new javax.swing.JLabel(); - personaSearchStatusLabel.setText(personaStatusLabelText); - - m_constraints.gridx = 0; - - CommunicationArtifactViewerHelper.addComponent(this, m_gridBagLayout, m_constraints, personaSearchStatusLabel); - - if (CentralRepository.isEnabled()) { - // Kick off a background task to serach for personas for the contact - personaSearchTask = new ContactPersonaSearcherTask(accountAttributesList); - personaSearchTask.execute(); - } else { - 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); - } - - //m_constraints.insets = savedInsets; - } - - /** - * Updates the Persona panel with the gathered persona information. - */ - private void updatePersonas() { - - // Remove the "Searching....." label - this.remove(personaSearchStatusLabel); - - m_constraints.gridx = 0; - if (contactUniquePersonasMap.isEmpty()) { - // 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) { - if (personaAccounts.contains(account) == false) { - missingAccounts.add(account); - } - } - - showPersona(entry.getKey(), matchCounter, missingAccounts, m_gridBagLayout, m_constraints); - m_constraints.gridy += 2; - } - } - - // add veritcal glue at the end - CommunicationArtifactViewerHelper.addPageEndGlue(this, m_gridBagLayout, this.m_constraints); - - // 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 contact accounts this persona may be - * missing. - * @param gridBagLayout Layout to use. - * @param constraints layout constraints. - * - * @throws CentralRepoException - */ - @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) { - - // 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 personaNameLabel = new javax.swing.JLabel(); - javax.swing.JButton personaButton = new javax.swing.JButton(); - - String personaName; - String personaButtonText; - ActionListener personaButtonListener; - if (persona != null) { - personaName = persona.getName(); - personaButtonText = Bundle.ContactArtifactViewer_persona_button_view(); - personaButtonListener = new ViewPersonaButtonListener(this, persona); - } else { - matchNumberLabel.setVisible(false); - personaName = Bundle.ContactArtifactViewer_persona_no_match(); - personaButtonText = Bundle.ContactArtifactViewer_persona_button_new(); - personaButtonListener = new CreatePersonaButtonListener(this, new PersonaUIComponents(personaNameLabel, personaButton)); - } - - //constraints.gridwidth = 1; // TBD: this may not be needed if we use single panel - constraints.gridx++; - personaNameLabel.setText(personaName); - gridBagLayout.setConstraints(personaNameLabel, constraints); - CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, personaNameLabel); - //personasPanel.add(personaNameLabel); - - // Add a Persona action button - constraints.gridx++; - //constraints.gridwidth = 1; - personaButton.setText(personaButtonText); - personaButton.addActionListener(personaButtonListener); - - // Shirnk the button height. - personaButton.setMargin(new Insets(0, 5, 0, 5)); - gridBagLayout.setConstraints(personaButton, constraints); - CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, personaButton); - CommunicationArtifactViewerHelper.addLineEndGlue(this, gridBagLayout, constraints); - - constraints.insets = savedInsets; - - // 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; - - 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; - - 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; - - } - - /** - * Gets an image from a TSK_CONTACT artifact. - * - * @param artifact - * - * @return Image from a TSK_CONTACT artifact or default image if none was - * found or the artifact is not a TSK_CONTACT - */ - private ImageIcon getImageFromArtifact(BlackboardArtifact artifact) { - ImageIcon imageIcon = defaultImage; - - if (artifact == null) { - return imageIcon; - } - - BlackboardArtifact.ARTIFACT_TYPE artifactType = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID()); - if (artifactType != BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT) { - return imageIcon; - } - - try { - for (Content content : artifact.getChildren()) { - if (content instanceof AbstractFile) { - AbstractFile file = (AbstractFile) content; - - try { - BufferedImage image = ImageIO.read(new File(file.getLocalAbsPath())); - imageIcon = new ImageIcon(image); - break; - } catch (IOException ex) { - // 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. - } - } - } - } catch (TskCoreException ex) { - logger.log(Level.WARNING, String.format("Unable to load image for contact: %d", artifact.getId()), ex); - } - - return imageIcon; - } - - /** - * Thread to search for a personas for all account identifier attributes for - * a contact. - */ - private class ContactPersonaSearcherTask extends SwingWorker>, Void> { - - private final List accountAttributesList; - private final List uniqueAccountsList = new ArrayList<>(); - - /** - * Creates a persona searcher task. - * - * @param accountAttributesList List of attributes that may map to - * accounts. - */ - ContactPersonaSearcherTask(List accountAttributesList) { - this.accountAttributesList = accountAttributesList; - } - - @Override - protected Map> doInBackground() throws Exception { - - 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 - Collection personas; - - Collection accountCandidates - = CentralRepoAccount.getAccountsWithIdentifier(bba.getValueString()); - - if (accountCandidates.isEmpty() == false) { - CentralRepoAccount account = accountCandidates.iterator().next(); - if (uniqueAccountsList.contains(account) == false) { - uniqueAccountsList.add(account); - } - - // get personas for the account - personas = PersonaAccount.getPersonaAccountsForAccount(account.getId()) - .stream() - .map(PersonaAccount::getPersona) - .collect(Collectors.toList()); - - // make a list of unique personas, along with all their accounts - for (Persona persona : personas) { - if (uniquePersonas.containsKey(persona) == false) { - Collection accounts = persona.getPersonaAccounts() - .stream() - .map(PersonaAccount::getAccount) - .collect(Collectors.toList()); - - ArrayList personaAccountsList = new ArrayList<>(accounts); - uniquePersonas.put(persona, personaAccountsList); - } - } - } - } - - return uniquePersonas; - } - - @Override - protected void done() { - - Map> personasMap; - try { - personasMap = super.get(); - - if (this.isCancelled()) { - return; - } - - contactUniquePersonasMap.clear(); - contactUniquePersonasMap.putAll(personasMap); - contactUniqueAccountsList.clear(); - contactUniqueAccountsList.addAll(uniqueAccountsList); - - updatePersonas(); - - } catch (CancellationException ex) { - logger.log(Level.INFO, "Persona searching was canceled."); //NON-NLS - } catch (InterruptedException ex) { - logger.log(Level.INFO, "Persona searching was interrupted."); //NON-NLS - } catch (ExecutionException ex) { - logger.log(Level.SEVERE, "Fatal error during Persona search.", ex); //NON-NLS - } - - } - } - - /** - * A wrapper class that bags the UI components that need to be updated when - * a persona search task or a create dialog returns. - */ - private class PersonaUIComponents { - - private final JLabel personaNameLabel; - private final JButton personaActionButton; - - /** - * Constructor. - * - * @param personaNameLabel Persona name label. - * @param personaActionButton Persona action button. - */ - PersonaUIComponents(JLabel personaNameLabel, JButton personaActionButton) { - this.personaNameLabel = personaNameLabel; - this.personaActionButton = personaActionButton; - } - - /** - * Returns persona name label. - * - * @return Persona name label. - */ - public JLabel getPersonaNameLabel() { - return personaNameLabel; - } - - /** - * Returns persona action button. - * - * @return Persona action button. - */ - public JButton getPersonaActionButton() { - return personaActionButton; - } - } - - /** - * Action listener for Create persona button. - */ - private class CreatePersonaButtonListener implements ActionListener { - - private final Component parentComponent; - private final PersonaUIComponents personaUIComponents; - - /** - * Constructs a listener for Create persona button.. - * - * @param personaUIComponents UI components. - */ - CreatePersonaButtonListener(Component parentComponent, PersonaUIComponents personaUIComponents) { - this.personaUIComponents = personaUIComponents; - this.parentComponent = parentComponent; - } - - @NbBundle.Messages({ - "ContactArtifactViewer_persona_account_justification=Account found in Contact artifact" - }) - - @Override - public void actionPerformed(java.awt.event.ActionEvent evt) { - // Launch the Persona Create dialog - do not display immediately - 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(); - - if (contactName != null) { - personaPanel.setPersonaName(contactName); - } - - // pass the list of accounts to the dialog - for (CentralRepoAccount account : contactUniqueAccountsList) { - personaPanel.addAccount(account, Bundle.ContactArtifactViewer_persona_account_justification(), Persona.Confidence.HIGH); - } - - // display the dialog now - createPersonaDialog.display(); - } - } - - /** - * Action listener for View persona button. - */ - private class ViewPersonaButtonListener implements ActionListener { - - private final Persona persona; - private final Component parentComponent; - - /** - * Creates listener for View persona button. - * - * @param persona - */ - ViewPersonaButtonListener(Component parentComponent, Persona persona) { - this.persona = persona; - this.parentComponent = parentComponent; - } - - @Override - public void actionPerformed(java.awt.event.ActionEvent evt) { - new PersonaDetailsDialog(parentComponent, - PersonaDetailsMode.VIEW, persona, new PersonaViewCallbackImpl()); - } - } - - /** - * Callback method for the create mode of the PersonaDetailsDialog - */ - class PersonaCreateCallbackImpl implements PersonaDetailsDialogCallback { - - private final Component parentComponent; - private final PersonaUIComponents personaUIComponents; - - /** - * Creates a callback to handle new persona creation. - * - * @param personaUIComponents UI Components. - */ - PersonaCreateCallbackImpl(Component parentComponent, PersonaUIComponents personaUIComponents) { - this.parentComponent = parentComponent; - this.personaUIComponents = personaUIComponents; - } - - @Override - public void callback(Persona persona) { - JButton personaButton = personaUIComponents.getPersonaActionButton(); - if (persona != null) { - // update the persona name label with newly created persona, - // and change the button to a "View" button - personaUIComponents.getPersonaNameLabel().setText(persona.getName()); - personaUIComponents.getPersonaActionButton().setText(Bundle.ContactArtifactViewer_persona_button_view()); - - // replace action listener with a View button listener - for (ActionListener act : personaButton.getActionListeners()) { - personaButton.removeActionListener(act); - } - personaButton.addActionListener(new ViewPersonaButtonListener(parentComponent, persona)); - - } - - personaButton.getParent().revalidate(); - personaButton.getParent().repaint(); - } - } - - /** - * Callback method for the view mode of the PersonaDetailsDialog - */ - class PersonaViewCallbackImpl implements PersonaDetailsDialogCallback { - - @Override - public void callback(Persona persona) { - // nothing to do - } - } - - // Variables declaration - do not modify//GEN-BEGIN:variables - // End of variables declaration//GEN-END:variables -} From b9320cf60a9ab9f0ea4f3e8da2215044a7c80dfd Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Tue, 23 Jun 2020 09:05:21 -0400 Subject: [PATCH 7/9] Formatted files. --- .../autopsy/contentviewers/CallLogArtifactViewer.java | 4 ++-- .../autopsy/contentviewers/ContactArtifactViewer.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java index becf098a45..fca201f60e 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java @@ -96,7 +96,7 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac if (artifact == null) { return; } - + CallLogViewData callLogViewData = null; try { callLogViewData = getCallLogViewData(artifact); @@ -462,7 +462,7 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac @Override public boolean isSupported(BlackboardArtifact artifact) { - + return (artifact != null) && (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()); } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java index 7e5f346927..76eac3eb70 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java @@ -150,8 +150,8 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac @Override public boolean isSupported(BlackboardArtifact artifact) { - return (artifact != null) && - (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID()); + return (artifact != null) + && (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID()); } /** From 52450b0b1c364ce5a4b84492ca6a397a948a819a Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Tue, 23 Jun 2020 09:25:59 -0400 Subject: [PATCH 8/9] Fixed some comments and headers --- .../contentviewers/CallLogArtifactViewer.java | 2 +- .../CommunicationArtifactViewerHelper.java | 20 ++++++++++++++----- .../contentviewers/ContactArtifactViewer.java | 1 - 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java index fca201f60e..78f0335504 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java @@ -407,7 +407,7 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac /** * Update the other attributes section. * - * @param callLogViewData + * @param callLogViewData Call log data. */ @NbBundle.Messages({ "CallLogArtifactViewer_heading_others=Other Attributes" diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java b/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java index df88d627ae..32d03afdaa 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java @@ -122,9 +122,6 @@ public final class CommunicationArtifactViewerHelper { // add to panel gridbagLayout.setConstraints(component, constraints); panel.add(component); - - // add line end glue - //addLineEndGlue(panel, gridbagLayout, constraints); } /** @@ -257,7 +254,7 @@ public final class CommunicationArtifactViewerHelper { } /** - * Adds a value string to the panel at col 1. + * Adds a value string to the panel at specified column. * * @param panel Panel to update. * @param gridbagLayout Layout to use. @@ -303,7 +300,8 @@ public final class CommunicationArtifactViewerHelper { } /** - * Displays a message string spanning the entire row. + * Displays a message string, starting at column 0, and spanning the entire + * row. * * @param panel Panel to show. * @param gridbagLayout Layout to use. @@ -317,6 +315,18 @@ public final class CommunicationArtifactViewerHelper { 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 diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java index 76eac3eb70..72997e9ede 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/ContactArtifactViewer.java @@ -376,7 +376,6 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac CommunicationArtifactViewerHelper.addPageEndGlue(this, m_gridBagLayout, this.m_constraints); } - //m_constraints.insets = savedInsets; } /** From 30464eb8f76e0b65dbab5a764ae34ab4456fbcf5 Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Tue, 23 Jun 2020 12:38:42 -0400 Subject: [PATCH 9/9] Changed class access specifier. --- .../contentviewers/CommunicationArtifactViewerHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java b/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java index 32d03afdaa..7b3c7a1f4b 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/CommunicationArtifactViewerHelper.java @@ -42,7 +42,7 @@ 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;