diff --git a/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceNode.java b/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceNode.java index 24d190bf2d..06af861154 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceNode.java @@ -20,27 +20,21 @@ package org.sleuthkit.autopsy.communications; import java.util.ArrayList; import java.util.Arrays; -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.logging.Level; import javax.swing.Action; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; -import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.Lookups; -import org.sleuthkit.autopsy.centralrepository.datamodel.PersonaAccount; +import org.sleuthkit.autopsy.communications.relationships.RelationshipsNodeUtilities; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.NodeProperty; import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.AccountDeviceInstance; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME; import org.sleuthkit.datamodel.CommunicationsFilter; import org.sleuthkit.datamodel.CommunicationsManager; -import org.sleuthkit.datamodel.TskCoreException; /** * Node to represent an Account Device Instance in the CVT @@ -118,48 +112,8 @@ final class AccountDeviceInstanceNode extends AbstractNode { return actions.toArray(new Action[actions.size()]); } - @Messages({ - "# {0} - Contact Name", - "# {1} - Persona Name", - "AccountInstanceNode_Tooltip_Template=Contact: {0} - Persona: {1}", - "# {0} - PersonaAccount count", - "AccountInstanceNode_Tooltip_suffix=(1 of {0})" - }) @Override public String getShortDescription() { - List personaList; - List contactArtifactList; - try { - personaList = CVTPersonaCache.getPersonaAccounts(account); - contactArtifactList = ContactCache.getContacts(account); - } catch (ExecutionException ex) { - logger.log(Level.WARNING, "Failed to retrieve Persona details for node.", ex); - return getDisplayName(); - } - - String personaName; - if (personaList != null && !personaList.isEmpty()) { - personaName = personaList.get(0).getPersona().getName(); - if (personaList.size() > 1) { - personaName += Bundle.AccountInstanceNode_Tooltip_suffix(Integer.toString(personaList.size())); - } - } else { - personaName = "None"; - } - - String contactName = getDisplayName(); - if (contactArtifactList != null && !contactArtifactList.isEmpty()) { - try { - BlackboardArtifact contactArtifact = contactArtifactList.get(0); - BlackboardAttribute attribute = contactArtifact.getAttribute(NAME_ATTRIBUTE); - if (attribute != null) { - contactName = attribute.getValueString(); - } - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Failed to retrive name attribute from contact artifact.", ex); - } - } - - return Bundle.AccountInstanceNode_Tooltip_Template(contactName, personaName); + return RelationshipsNodeUtilities.getAccoutToolTipText(getDisplayName(), account); } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED index 2d83902cb7..2938a7d0c1 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED @@ -1,8 +1,3 @@ -# {0} - PersonaAccount count -AccountInstanceNode_Tooltip_suffix=(1 of {0}) -# {0} - Contact Name -# {1} - Persona Name -AccountInstanceNode_Tooltip_Template=Contact: {0} - Persona: {1} AccountNode.accountName=Account AccountNode.accountType=Type AccountNode.device=Device diff --git a/Core/src/org/sleuthkit/autopsy/communications/CVTPersonaCache.java b/Core/src/org/sleuthkit/autopsy/communications/CVTPersonaCache.java index 92cebad8a3..974d7ca299 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/CVTPersonaCache.java +++ b/Core/src/org/sleuthkit/autopsy/communications/CVTPersonaCache.java @@ -38,7 +38,7 @@ import org.sleuthkit.datamodel.Account; * PersonaAccounts for a given Account typeSpecificID retrieved on first access * and evicted from the cache after 5 minutes. */ -final class CVTPersonaCache { +final public class CVTPersonaCache { private static final Logger logger = Logger.getLogger(CVTPersonaCache.class.getName()); private final LoadingCache> accountMap; @@ -90,7 +90,7 @@ final class CVTPersonaCache { * * @throws ExecutionException */ - static synchronized List getPersonaAccounts(Account account) throws ExecutionException { + static public synchronized List getPersonaAccounts(Account account) throws ExecutionException { return getInstance().accountMap.get(account); } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/ContactCache.java b/Core/src/org/sleuthkit/autopsy/communications/ContactCache.java index 2b0cc8f678..d4544edf59 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/ContactCache.java +++ b/Core/src/org/sleuthkit/autopsy/communications/ContactCache.java @@ -48,7 +48,7 @@ import org.sleuthkit.datamodel.TskCoreException; * expires after 10 of non-use. * */ -final class ContactCache { +final public class ContactCache { private static final Logger logger = Logger.getLogger(ContactCache.class.getName()); @@ -66,7 +66,7 @@ final class ContactCache { * * @throws ExecutionException */ - static synchronized List getContacts(Account account) throws ExecutionException { + static public synchronized List getContacts(Account account) throws ExecutionException { return getInstance().accountMap.get("realMap").get(account.getTypeSpecificID()); } diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/AccountNodeProperty.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/AccountNodeProperty.java new file mode 100755 index 0000000000..626f3c82de --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/AccountNodeProperty.java @@ -0,0 +1,52 @@ +/* + * 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.communications.relationships; + +import java.lang.reflect.InvocationTargetException; +import org.openide.util.Exceptions; +import org.sleuthkit.autopsy.datamodel.NodeProperty; +import org.sleuthkit.datamodel.Account; + +/** + * A subclass of NodeProperty that stores an account object for use with looking + * up personas. + */ +class AccountNodeProperty extends NodeProperty { + + private final Account account; + + AccountNodeProperty(String name, String displayName, T value, Account account) { + super(name, displayName, "", value); + this.account = account; + } + + @Override + public String getShortDescription() { + try { + if (account != null) { + return RelationshipsNodeUtilities.getAccoutToolTipText(getValue().toString(), account); + } + return getValue().toString(); + } catch (IllegalAccessException | InvocationTargetException ex) { + Exceptions.printStackTrace(ex); + } + + return ""; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties-MERGED index c0801a1e4e..b70541a494 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties-MERGED @@ -35,6 +35,11 @@ MessageViewer_viewMessage_all=All MessageViewer_viewMessage_calllogs=Call Logs MessageViewer_viewMessage_selected=Selected MessageViewer_viewMessage_unthreaded=Unthreaded +# {0} - PersonaAccount count +RelationshipsNodeUtilities_Tooltip_suffix=(1 of {0}) +# {0} - Contact Name +# {1} - Persona Name +RelationshipsNodeUtilities_Tooltip_Template=Contact: {0} - Persona: {1} # {0} - accountIdentifer SummaryPersonaPane_not_account_in_cr=Unable to find an account with identifier {0} in the Central Repository. SummaryViewer.countsPanel.border.title=Communications diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogNode.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogNode.java index 3151d75780..d0985c046b 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogNode.java @@ -77,7 +77,16 @@ final class CallLogNode extends BlackboardArtifactNode { sheetSet.put(createNode(TSK_DATETIME_START, artifact)); sheetSet.put(createNode(TSK_DIRECTION, artifact)); - sheetSet.put(new NodeProperty<>(TSK_PHONE_NUMBER.getLabel(), TSK_PHONE_NUMBER.getDisplayName(), "", getPhoneNumber(artifact))); + + String phoneNumber = getPhoneNumber(artifact); + Account account = null; + try { + account = artifact.getSleuthkitCase().getCommunicationsManager().getAccount(Account.Type.PHONE, phoneNumber); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Failed to get instance of communications manager", ex); + } + + sheetSet.put(new AccountNodeProperty<>(TSK_PHONE_NUMBER.getLabel(), TSK_PHONE_NUMBER.getDisplayName(), phoneNumber, account)); if(duration != -1) { sheetSet.put(new NodeProperty<>("duration", "Duration", "", Long.toString(duration))); } diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogViewer.java index dd60003833..21d7deb8bd 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogViewer.java @@ -24,6 +24,7 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.JPanel; import static javax.swing.SwingUtilities.isDescendingFrom; +import javax.swing.table.TableColumn; import org.netbeans.swing.outline.DefaultOutlineModel; import org.netbeans.swing.outline.Outline; import org.openide.explorer.ExplorerManager; @@ -82,6 +83,8 @@ final class CallLogViewer extends javax.swing.JPanel implements RelationshipsVie outlineViewPanel.hideOutlineView(Bundle.CallLogViewer_noCallLogs()); + // If changing the order of these columns effects the location of the + // phone number column be sure to adjust the renderer code below. outlineViewPanel.getOutlineView().setPropertyColumns( TSK_DIRECTION.getLabel(), TSK_DIRECTION.getDisplayName(), TSK_PHONE_NUMBER.getLabel(), Bundle.CallLogViewer_recipient_label(), @@ -116,6 +119,9 @@ final class CallLogViewer extends javax.swing.JPanel implements RelationshipsVie updateOutlineViewPanel(); } }); + + TableColumn column = outline.getColumnModel().getColumn(2); + column.setCellRenderer(new NodeTableCellRenderer() ); } @@ -223,7 +229,7 @@ final class CallLogViewer extends javax.swing.JPanel implements RelationshipsVie } } - + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JScrollPane bottomScrollPane; private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel outlineViewPanel; diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java index 744408b30d..c4e341b60d 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java @@ -24,7 +24,9 @@ import javax.swing.AbstractAction; import javax.swing.Action; import org.apache.commons.lang3.StringUtils; import org.openide.nodes.Sheet; +import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.NodeProperty; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -38,9 +40,11 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUB import org.sleuthkit.datamodel.TskCoreException; import static org.sleuthkit.autopsy.communications.relationships.RelationshipsNodeUtilities.getAttributeDisplayString; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; +import org.sleuthkit.datamodel.Account; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE; import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.CommunicationsManager; import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil; import org.sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments; @@ -113,22 +117,48 @@ class MessageNode extends BlackboardArtifactNode { String msg_from = getAttributeDisplayString(artifact, TSK_EMAIL_FROM); String msg_to = getAttributeDisplayString(artifact, TSK_EMAIL_TO); String date = getAttributeDisplayString(artifact, TSK_DATETIME_SENT); - - if (msg_from.isEmpty()) { - msg_from = getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM); - - } - if (msg_to.isEmpty()) { - msg_to = getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO); - } - if (date.isEmpty()) { - date = getAttributeDisplayString(artifact, TSK_DATETIME); + + Account account_from = null; + Account account_to = null; + + try { + CommunicationsManager manager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager(); + + if (msg_from.isEmpty()) { + msg_from = getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM); + if(manager != null && !msg_from.isEmpty()) { + account_from = manager.getAccount(Account.Type.PHONE, msg_from); + } + } else if(manager != null) { + // To email address sometime is in the format : + String toStr = msg_to; + String[] strSplit = msg_to.split(":"); + if(strSplit.length > 0) { + toStr = strSplit[strSplit.length-1].trim(); + } + account_from = manager.getAccount(Account.Type.EMAIL, toStr); + } + + if (msg_to.isEmpty()) { + msg_to = getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO); + if(manager != null && !msg_to.isEmpty()) { + account_to = manager.getAccount(Account.Type.PHONE, msg_to); + } + } else if(manager != null) { + account_to = manager.getAccount(Account.Type.EMAIL, msg_to); + } + + if (date.isEmpty()) { + date = getAttributeDisplayString(artifact, TSK_DATETIME); + } + } catch (TskCoreException ex) { + } - sheetSet.put(new NodeProperty<>("From", Bundle.MessageNode_Node_Property_From(), "", - msg_from)); //NON-NLS - sheetSet.put(new NodeProperty<>("To", Bundle.MessageNode_Node_Property_To(), "", - msg_to)); //NON-NLS + sheetSet.put(new AccountNodeProperty<>("From", Bundle.MessageNode_Node_Property_From(), + msg_from, account_from)); //NON-NLS + sheetSet.put(new AccountNodeProperty<>("To", Bundle.MessageNode_Node_Property_To(), + msg_to, account_to)); //NON-NLS sheetSet.put(new NodeProperty<>("Date", Bundle.MessageNode_Node_Property_Date(), "", date)); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.java index 633c40ac4f..f409c288f7 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,6 +25,7 @@ import java.beans.PropertyChangeListener; import static javax.swing.SwingUtilities.isDescendingFrom; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; +import javax.swing.table.TableColumn; import org.netbeans.swing.outline.DefaultOutlineModel; import org.netbeans.swing.outline.Outline; import org.openide.explorer.ExplorerManager; @@ -65,6 +66,8 @@ class MessagesPanel extends javax.swing.JPanel implements Lookup.Provider { proxyLookup = new ModifiableProxyLookup(createLookup(outlineViewPanel.getExplorerManager(), getActionMap())); outline = outlineViewPanel.getOutlineView().getOutline(); + // When changing this column this, if the from and to columns pos is + // effected make sure to modify the renderer code below. outlineViewPanel.getOutlineView().setPropertyColumns( "From", Bundle.MessageViewer_columnHeader_From(), "To", Bundle.MessageViewer_columnHeader_To(), @@ -98,7 +101,13 @@ class MessagesPanel extends javax.swing.JPanel implements Lookup.Provider { } } }); - + + TableColumn column = outline.getColumnModel().getColumn(1); + column.setCellRenderer(new NodeTableCellRenderer()); + + column = outline.getColumnModel().getColumn(2); + column.setCellRenderer(new NodeTableCellRenderer()); + splitPane.setResizeWeight(0.5); splitPane.setDividerLocation(0.5); outlineViewPanel.setTableColumnsWidth(5, 10, 10, 15, 50, 10); @@ -164,7 +173,7 @@ class MessagesPanel extends javax.swing.JPanel implements Lookup.Provider { Children.create(nodeFactory, true)), outlineViewPanel.getExplorerManager()), true)); } - + /** * 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 diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/NodeTableCellRenderer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/NodeTableCellRenderer.java new file mode 100755 index 0000000000..e368c64bf2 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/NodeTableCellRenderer.java @@ -0,0 +1,66 @@ +/* + * 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.communications.relationships; + +import java.awt.Component; +import java.beans.FeatureDescriptor; +import java.lang.reflect.InvocationTargetException; +import java.util.logging.Level; +import javax.swing.JTable; +import javax.swing.table.DefaultTableCellRenderer; +import org.openide.nodes.Node; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.NodeProperty; + +/** + * TableCellRenderer for NodeProperty with custom tooltip data. + */ +final class NodeTableCellRenderer extends DefaultTableCellRenderer { + + private static final long serialVersionUID = 1L; + + private static final Logger logger = Logger.getLogger(NodeTableCellRenderer.class.getName()); + + @Override + public Component getTableCellRendererComponent(JTable table, + Object value, + boolean isSelected, + boolean hasFocus, + int row, + int column) { + + String descr = ""; + Object theRealValue = value; + if (value instanceof NodeProperty) { + descr = ((FeatureDescriptor) value).getShortDescription(); + try { + theRealValue = ((Node.Property) value).getValue(); + } catch (IllegalAccessException | InvocationTargetException ex) { + logger.log(Level.WARNING, "Unable to get NodeProperty cell value."); + } + } + + super.getTableCellRendererComponent(table, theRealValue, isSelected, hasFocus, row, column); + + setToolTipText(descr); + + return this; + + } +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/RelationshipsNodeUtilities.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/RelationshipsNodeUtilities.java index be150dd590..5c72488968 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/RelationshipsNodeUtilities.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/RelationshipsNodeUtilities.java @@ -19,12 +19,21 @@ package org.sleuthkit.autopsy.communications.relationships; +import java.util.List; import java.util.TimeZone; +import java.util.concurrent.ExecutionException; import java.util.logging.Level; +import org.openide.nodes.Node; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.centralrepository.datamodel.PersonaAccount; +import org.sleuthkit.autopsy.communications.CVTPersonaCache; +import org.sleuthkit.autopsy.communications.ContactCache; import org.sleuthkit.autopsy.communications.Utils; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME; import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME; import org.sleuthkit.datamodel.TimeUtilities; import org.sleuthkit.datamodel.TskCoreException; @@ -33,9 +42,11 @@ import org.sleuthkit.datamodel.TskCoreException; * A set of reusable utility functions for the Relationships package. * */ -final class RelationshipsNodeUtilities { +final public class RelationshipsNodeUtilities { private static final Logger logger = Logger.getLogger(RelationshipsNodeUtilities.class.getName()); + private static final BlackboardAttribute.Type NAME_ATTRIBUTE = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(TSK_NAME.getTypeID())); + // Here to make codacy happy private RelationshipsNodeUtilities(){ @@ -69,4 +80,52 @@ final class RelationshipsNodeUtilities { } } + @NbBundle.Messages({ + "# {0} - Contact Name", + "# {1} - Persona Name", + "RelationshipsNodeUtilities_Tooltip_Template=Contact: {0} - Persona: {1}", + "# {0} - PersonaAccount count", + "RelationshipsNodeUtilities_Tooltip_suffix=(1 of {0})" + }) + static public String getAccoutToolTipText(String displayName, Account account) { + if(account == null) { + return displayName; + } + + List personaList; + List contactArtifactList; + try { + personaList = CVTPersonaCache.getPersonaAccounts(account); + contactArtifactList = ContactCache.getContacts(account); + } catch (ExecutionException ex) { + logger.log(Level.WARNING, "Failed to retrieve Persona details for node.", ex); + return displayName; + } + + String personaName; + if (personaList != null && !personaList.isEmpty()) { + personaName = personaList.get(0).getPersona().getName(); + if (personaList.size() > 1) { + personaName += Bundle.RelationshipsNodeUtilities_Tooltip_suffix(Integer.toString(personaList.size())); + } + } else { + personaName = "None"; + } + + String contactName = displayName; + if (contactArtifactList != null && !contactArtifactList.isEmpty()) { + try { + BlackboardArtifact contactArtifact = contactArtifactList.get(0); + BlackboardAttribute attribute = contactArtifact.getAttribute(NAME_ATTRIBUTE); + if (attribute != null) { + contactName = attribute.getValueString(); + } + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Failed to retrive name attribute from contact artifact.", ex); + } + } + + return Bundle.RelationshipsNodeUtilities_Tooltip_Template(contactName, personaName); + } + }