From 3b810693b8d7ab9297a318fba5c3788e8d847c6d Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 10 Apr 2019 11:35:32 -0400 Subject: [PATCH 1/8] Added OutlineView in the messages tab for displaying the messages of the currently selected accounts --- .../communications/AccountsBrowser.java | 26 ++-- .../autopsy/communications/Bundle.properties | 1 - .../communications/Bundle.properties-MERGED | 1 - .../communications/ContactsViewer.java | 2 +- .../autopsy/communications/MessageNode.java | 136 +++++++++++++++++- .../communications/MessageNodeFactory.java | 48 ------- .../MessagesChildNodeFactory.java | 102 +++++++++++++ .../communications/MessagesViewer.form | 18 +-- .../communications/MessagesViewer.java | 72 +++++++--- .../autopsy/communications/SelectionInfo.java | 28 ++-- 10 files changed, 324 insertions(+), 110 deletions(-) delete mode 100755 Core/src/org/sleuthkit/autopsy/communications/MessageNodeFactory.java create mode 100755 Core/src/org/sleuthkit/autopsy/communications/MessagesChildNodeFactory.java diff --git a/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.java b/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.java index d52d2341ab..671f5ed8a2 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.java @@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.communications; import com.google.common.eventbus.Subscribe; import java.awt.Component; -import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.logging.Level; @@ -36,11 +35,11 @@ import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.util.Lookup; -import org.openide.util.lookup.ProxyLookup; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AccountDeviceInstance; +import org.sleuthkit.datamodel.CommunicationsFilter; import org.sleuthkit.datamodel.CommunicationsManager; import org.sleuthkit.datamodel.TskCoreException; @@ -70,7 +69,7 @@ public final class AccountsBrowser extends JPanel implements ExplorerManager.Pro * This lookup proxies the selection lookup of both he accounts table and * the messages table. */ - private final ProxyLookup proxyLookup; + private final Lookup lookup; public AccountsBrowser() { initComponents(); @@ -95,16 +94,19 @@ public final class AccountsBrowser extends JPanel implements ExplorerManager.Pro } else if (ExplorerManager.PROP_EXPLORED_CONTEXT.equals(evt.getPropertyName())) { SwingUtilities.invokeLater(this::setColumnWidths); } else if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) { - relationshipBrowser.setSelectionInfo(new SelectionInfo()); + final Node[] selectedNodes = accountsTableEM.getSelectedNodes(); + final Set accountDeviceInstances = new HashSet<>(); + + CommunicationsFilter filter = null; + for (final Node node : selectedNodes) { + accountDeviceInstances.add(((AccountDeviceInstanceNode) node).getAccountDeviceInstance()); + filter = ((AccountDeviceInstanceNode)node).getFilter(); + } + relationshipBrowser.setSelectionInfo(new SelectionInfo(accountDeviceInstances, filter)); } }); - final MessageBrowser messageBrowser = new MessageBrowser(accountsTableEM, messageBrowserEM); - -// jSplitPane1.setRightComponent(messageBrowser); - - proxyLookup = new ProxyLookup( - messageBrowser.getLookup(), - ExplorerUtils.createLookup(accountsTableEM, getActionMap())); + + lookup = ExplorerUtils.createLookup(accountsTableEM, getActionMap()); } private void setColumnWidths() { @@ -176,6 +178,6 @@ public final class AccountsBrowser extends JPanel implements ExplorerManager.Pro @Override public Lookup getLookup() { - return proxyLookup; + return lookup; } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties index de986e82e2..70fb3bc757 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties @@ -40,4 +40,3 @@ VisualizationPanel.hierarchyLayoutButton.text=Hierarchical VisualizationPanel.clearVizButton.text_1=Clear Viz. VisualizationPanel.snapshotButton.text_1=Snapshot Report ContactsViewer.testLabel.text=No Value Set -MessagesViewer.testLabel.text=No Value Set diff --git a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED index 88ddd57253..c3c4fbc6f1 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED @@ -84,7 +84,6 @@ VisualizationPanel.hierarchyLayoutButton.text=Hierarchical VisualizationPanel.clearVizButton.text_1=Clear Viz. VisualizationPanel.snapshotButton.text_1=Snapshot Report ContactsViewer.testLabel.text=No Value Set -MessagesViewer.testLabel.text=No Value Set VisualizationPanel_action_dialogs_title=Communications VisualizationPanel_action_name_text=Snapshot Report VisualizationPanel_module_name=Communications diff --git a/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.java b/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.java index 66c22fa4d2..1808c8bb62 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.java @@ -47,7 +47,7 @@ public class ContactsViewer extends JPanel implements RelationshipsViewer{ @Override public void setSelectionInfo(SelectionInfo info) { - testLabel.setText(info.getString()); + } /** diff --git a/Core/src/org/sleuthkit/autopsy/communications/MessageNode.java b/Core/src/org/sleuthkit/autopsy/communications/MessageNode.java index 12c1231628..c557809a54 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/MessageNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/MessageNode.java @@ -18,23 +18,147 @@ */ package org.sleuthkit.autopsy.communications; +import java.util.TimeZone; +import java.util.logging.Level; import org.apache.commons.lang3.StringUtils; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.Children; +import org.openide.nodes.Sheet; +import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; +import org.sleuthkit.autopsy.datamodel.ExtractedContent; +import org.sleuthkit.autopsy.datamodel.NodeProperty; import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardAttribute; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_FROM; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_TO; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT; +import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME; +import org.sleuthkit.datamodel.TimeUtilities; +import org.sleuthkit.datamodel.TskCoreException; /** - * - * + * Wraps a BlackboardArtifact as an AbstractNode for use in an OutlookView */ -final class MessageNode extends BlackboardArtifactNode { +final class MessageNode extends AbstractNode { private static final Logger logger = Logger.getLogger(RelationshipNode.class.getName()); + private final BlackboardArtifact artifact; + MessageNode(BlackboardArtifact artifact) { - super(artifact); - // Grabbed this from RelationshipNode, does always work even with internalization? + super(Children.LEAF, Lookups.fixed(artifact)); + this.artifact = artifact; + final String stripEnd = StringUtils.stripEnd(artifact.getDisplayName(), "s"); // NON-NLS String removeEndIgnoreCase = StringUtils.removeEndIgnoreCase(stripEnd, "message"); // NON-NLS setDisplayName(removeEndIgnoreCase.isEmpty() ? stripEnd : removeEndIgnoreCase); + + int typeID = artifact.getArtifactTypeID(); + + String filePath = "org/sleuthkit/autopsy/images/"; //NON-NLS + if( typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) { + filePath = filePath + "mail-icon-16.png"; //NON-NLS + } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) { + filePath = filePath + "message.png"; //NON-NLS + } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()) { + filePath = filePath + "calllog.png"; //NON-NLS + } + + setIconBaseWithExtension(filePath); + } + + @Override + protected Sheet createSheet() { + Sheet sheet = new Sheet(); + Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES); + if (sheetSet == null) { + sheetSet = Sheet.createPropertiesSet(); + sheet.put(sheetSet); + } + + sheetSet.put(new NodeProperty<>("Type", "Type", "Type", getDisplayName())); //NON-NLS + + BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID()); + if (null != fromID) { + //Consider refactoring this to reduce boilerplate + switch (fromID) { + case TSK_EMAIL_MSG: + sheetSet.put(new NodeProperty<>("From", "From", "From", + StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_FROM), " \t\n;"))); //NON-NLS + sheetSet.put(new NodeProperty<>("To", "To", "To", + StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_TO), " \t\n;"))); //NON-NLS + sheetSet.put(new NodeProperty<>("Date", "Date", "Date", + getAttributeDisplayString(artifact, TSK_DATETIME_SENT))); //NON-NLS + sheetSet.put(new NodeProperty<>("Subject", "Subject", "Subject", + getAttributeDisplayString(artifact, TSK_SUBJECT))); //NON-NLS + try { + sheetSet.put(new NodeProperty<>("Attms", "Attms", "Attms", artifact.getChildrenCount())); //NON-NLS + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex); //NON-NLS + } + + break; + case TSK_MESSAGE: + sheetSet.put(new NodeProperty<>("From", "From", "From", + getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM))); //NON-NLS + sheetSet.put(new NodeProperty<>("To", "To", "To", + getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO))); //NON-NLS + sheetSet.put(new NodeProperty<>("Date", "Date", "Date", + getAttributeDisplayString(artifact, TSK_DATETIME))); //NON-NLS + sheetSet.put(new NodeProperty<>("Subject", "Subject", "Subject", + getAttributeDisplayString(artifact, TSK_SUBJECT))); //NON-NLS + try { + sheetSet.put(new NodeProperty<>("Attms", "Attms", "Attms", artifact.getChildrenCount())); //NON-NLS + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex); //NON-NLS + } + break; + case TSK_CALLLOG: + sheetSet.put(new NodeProperty<>("From", "From", "From", + getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM))); //NON-NLS + sheetSet.put(new NodeProperty<>("To", "To", "To", + getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO))); //NON-NLS + sheetSet.put(new NodeProperty<>("Date", "Date", "Date", + getAttributeDisplayString(artifact, TSK_DATETIME_START))); //NON-NLS + break; + default: + break; + } + } + + return sheet; + } + + /** + * + * Get the display string for the attribute of the given type from the given + * artifact. + * + * @param artifact the value of artifact + * @param attributeType the value of TSK_SUBJECT1 + * + * @return The display string, or an empty string if there is no such + * attribute or an an error. + */ + private static String getAttributeDisplayString(final BlackboardArtifact artifact, final BlackboardAttribute.ATTRIBUTE_TYPE attributeType) { + try { + BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(attributeType.getTypeID()))); + if (attribute == null) { + return ""; + } else if (attributeType.getValueType() == DATETIME) { + return TimeUtilities.epochToTime(attribute.getValueLong(), + TimeZone.getTimeZone(Utils.getUserPreferredZoneId())); + } else { + return attribute.getDisplayString(); + } + } catch (TskCoreException tskCoreException) { + logger.log(Level.WARNING, "Error getting attribute value.", tskCoreException); //NON-NLS + return ""; + } } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/MessageNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/MessageNodeFactory.java deleted file mode 100755 index c06bffe692..0000000000 --- a/Core/src/org/sleuthkit/autopsy/communications/MessageNodeFactory.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2019 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; - -import java.util.Collection; -import java.util.List; -import org.openide.nodes.ChildFactory; -import org.openide.nodes.Node; -import org.sleuthkit.datamodel.BlackboardArtifact; - -/** - * - * - */ -public class MessageNodeFactory extends ChildFactory { - private final Collection artifacts; - - MessageNodeFactory(Collection artifacts) { - this.artifacts = artifacts; - } - - @Override - protected boolean createKeys(List list) { - list.addAll(artifacts); - return true; - } - - @Override - protected Node createNodeForKey(BlackboardArtifact key) { - return new MessageNode(key); - } -} diff --git a/Core/src/org/sleuthkit/autopsy/communications/MessagesChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/MessagesChildNodeFactory.java new file mode 100755 index 0000000000..9a1c7d1024 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/MessagesChildNodeFactory.java @@ -0,0 +1,102 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 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; + +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import org.openide.nodes.ChildFactory; +import org.openide.nodes.Node; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.CommunicationsManager; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * ChildFactory that creates createKeys and nodes from a given selectionInfo for + * only emails, call logs and messages. + * + */ +public class MessagesChildNodeFactory extends ChildFactory { + + private static final Logger logger = Logger.getLogger(MessagesChildNodeFactory.class.getName()); + + private CommunicationsManager communicationManager = null; + private final SelectionInfo selectionInfo; + + /** + * Construct a new MessageChildNodeFactory from the currently selectionInfo + * + * @param selectionInfo SelectionInfo object for the currently selected + * accounts + */ + MessagesChildNodeFactory(SelectionInfo selectionInfo) { + this.selectionInfo = selectionInfo; + + try { + communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager(); + } catch (NoCurrentCaseException | TskCoreException ex) { + logger.log(Level.SEVERE, "Failed to get communications manager from case.", ex); //NON-NLS + } + } + + /** + * Creates a list of Keys (BlackboardArtifact) for only messages for the + * currently selected accounts + * @param list List of BlackboardArtifact to populate + * @return True on success + */ + @Override + protected boolean createKeys(List list) { + if (communicationManager == null) { + return false; + } + + final Set relationshipSources; + + try { + relationshipSources = communicationManager.getRelationshipSources(selectionInfo.getAccountDevicesInstances(), selectionInfo.getCommunicationsFilter()); + + relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> { + + BlackboardArtifact bba = (BlackboardArtifact) content; + BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID()); + + if (fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG + || fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG + || fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) { + list.add(bba); + } + }); + + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Failed to get relationship sources.", ex); //NON-NLS + } + + return true; + } + + @Override + protected Node createNodeForKey(BlackboardArtifact key) { + return new MessageNode(key); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.form b/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.form index a80677b2ee..a8a0606f8f 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.form +++ b/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.form @@ -16,30 +16,20 @@ - - - - - + - - - + + - - - - - - + diff --git a/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.java b/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.java index 4624005140..b5b5159aa3 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.java @@ -19,25 +19,61 @@ package org.sleuthkit.autopsy.communications; import javax.swing.JPanel; +import javax.swing.ListSelectionModel; +import org.netbeans.swing.outline.DefaultOutlineModel; +import org.netbeans.swing.outline.Outline; +import org.openide.explorer.ExplorerManager; +import org.openide.explorer.ExplorerUtils; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.Children; +import org.openide.util.Lookup; +import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.ServiceProvider; /** - * Visualation for Contacts - * + * Visualation for the messages of the currently selected accounts. */ @ServiceProvider(service=RelationshipsViewer.class) -public class MessagesViewer extends JPanel implements RelationshipsViewer{ +public class MessagesViewer extends JPanel implements RelationshipsViewer, ExplorerManager.Provider, Lookup.Provider { + private final ExplorerManager tableEM = new ExplorerManager(); + private final Lookup lookup; + private final Outline outline; + + @Messages({ + "MessageViewer_tabTitle=Messages", + "MessageViewer_columnHeader_From=From", + "MessageViewer_columnHeader_To=To", + "MessageViewer_columnHeader_Date=Date", + "MessageViewer_columnHeader_Subject=Subject", + "MessageViewer_columnHeader_Attms=Attachments" + }) + /** * Creates new form MessagesViewer */ public MessagesViewer() { initComponents(); + + outline = outlineView.getOutline(); + outlineView.setPropertyColumns( + "From", Bundle.MessageViewer_columnHeader_From(), + "To", Bundle.MessageViewer_columnHeader_To(), + "Date", Bundle.MessageViewer_columnHeader_Date(), + "Subject", Bundle.MessageViewer_columnHeader_Subject(), + "Attms", Bundle.MessageViewer_columnHeader_Attms() + + ); + outline.setRootVisible(false); + outline.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.AccountNode_accountName()); + + lookup = ExplorerUtils.createLookup(tableEM, getActionMap()); } @Override public String getDisplayName() { - return "Messages"; + return Bundle.MessageViewer_tabTitle(); } @Override @@ -47,7 +83,17 @@ public class MessagesViewer extends JPanel implements RelationshipsViewer{ @Override public void setSelectionInfo(SelectionInfo info) { - testLabel.setText(info.getString()); + tableEM.setRootContext(new AbstractNode(Children.create(new MessagesChildNodeFactory(info), true))); + } + + @Override + public ExplorerManager getExplorerManager() { + return tableEM; + } + + @Override + public Lookup getLookup() { + return lookup; } /** @@ -59,30 +105,24 @@ public class MessagesViewer extends JPanel implements RelationshipsViewer{ // //GEN-BEGIN:initComponents private void initComponents() { - testLabel = new javax.swing.JLabel(); - - org.openide.awt.Mnemonics.setLocalizedText(testLabel, org.openide.util.NbBundle.getMessage(MessagesViewer.class, "MessagesViewer.testLabel.text")); // NOI18N + outlineView = new org.openide.explorer.view.OutlineView(); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(testLabel) - .addContainerGap(294, Short.MAX_VALUE)) + .addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 480, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(testLabel) - .addContainerGap(264, Short.MAX_VALUE)) + .addComponent(outlineView, javax.swing.GroupLayout.PREFERRED_SIZE, 475, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 16, Short.MAX_VALUE)) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel testLabel; + private org.openide.explorer.view.OutlineView outlineView; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/communications/SelectionInfo.java b/Core/src/org/sleuthkit/autopsy/communications/SelectionInfo.java index 0b63e1c129..6dc370841b 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/SelectionInfo.java +++ b/Core/src/org/sleuthkit/autopsy/communications/SelectionInfo.java @@ -18,7 +18,10 @@ */ package org.sleuthkit.autopsy.communications; -import java.util.Date; +import java.util.Set; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.AccountDeviceInstance; +import org.sleuthkit.datamodel.CommunicationsFilter; /** @@ -28,19 +31,22 @@ import java.util.Date; */ public class SelectionInfo { - private final String displayString; + static final private Logger logger = Logger.getLogger(SelectionInfo.class.getName()); + + private final Set accountDeviceInstances; + private final CommunicationsFilter communicationFilter; - SelectionInfo() { - displayString = (new Date()).toString(); + SelectionInfo(Set accountDeviceInstances, CommunicationsFilter communicationFilter) { + this.accountDeviceInstances = accountDeviceInstances; + this.communicationFilter = communicationFilter; } - /** - * Temporary function for testing data flow - * - * @return A String representing the time the object was created - */ - public String getString() { - return displayString; + public Set getAccountDevicesInstances(){ + return accountDeviceInstances; + } + + public CommunicationsFilter getCommunicationsFilter() { + return communicationFilter; } } From 6fcb97429640fcef669ec837db96d7552feab4ba Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 10 Apr 2019 11:40:15 -0400 Subject: [PATCH 2/8] Removed unused import --- .../autopsy/communications/Bundle.properties-MERGED | 6 ++++++ .../org/sleuthkit/autopsy/communications/MessageNode.java | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED index c3c4fbc6f1..e5f00998a6 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED @@ -23,6 +23,12 @@ FiltersPanel.deviceRequiredLabel.text=Select at least one. FiltersPanel.accountTypeRequiredLabel.text=Select at least one. FiltersPanel.needsRefreshLabel.text=Displayed data is out of date. Press Refresh. MessageBrowser.DataResultViewerTable.title=Messages +MessageViewer_columnHeader_Attms=Attachments +MessageViewer_columnHeader_Date=Date +MessageViewer_columnHeader_From=From +MessageViewer_columnHeader_Subject=Subject +MessageViewer_columnHeader_To=To +MessageViewer_tabTitle=Messages OpenCVTAction.displayName=Communications PinAccountsAction.pluralText=Add Selected Accounts to Visualization PinAccountsAction.singularText=Add Selected Account to Visualization diff --git a/Core/src/org/sleuthkit/autopsy/communications/MessageNode.java b/Core/src/org/sleuthkit/autopsy/communications/MessageNode.java index c557809a54..4a02a1d0ce 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/MessageNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/MessageNode.java @@ -26,7 +26,6 @@ import org.openide.nodes.Children; import org.openide.nodes.Sheet; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.ExtractedContent; import org.sleuthkit.autopsy.datamodel.NodeProperty; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; From f4c6d70ff7bfe38419bad411e9713f5735088044 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 11 Apr 2019 11:46:41 -0400 Subject: [PATCH 3/8] Added the message content viewer to the MessageBrowser --- .../autopsy/communications/Bundle.properties | 1 - .../communications/Bundle.properties-MERGED | 1 - .../communications/ContactsViewer.form | 21 +--- .../communications/ContactsViewer.java | 15 +-- .../autopsy/communications/MessageNode.java | 53 +++++---- .../communications/MessagesViewer.form | 13 ++- .../communications/MessagesViewer.java | 101 ++++++++++++++---- .../RelaionshipSetNodeFactory.java | 48 --------- .../communications/RelationshipBrowser.form | 3 + .../communications/RelationshipBrowser.java | 22 +++- 10 files changed, 147 insertions(+), 131 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/communications/RelaionshipSetNodeFactory.java diff --git a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties index 70fb3bc757..6665c2e958 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties @@ -39,4 +39,3 @@ VisualizationPanel.fastOrganicLayoutButton.text=Fast Organic VisualizationPanel.hierarchyLayoutButton.text=Hierarchical VisualizationPanel.clearVizButton.text_1=Clear Viz. VisualizationPanel.snapshotButton.text_1=Snapshot Report -ContactsViewer.testLabel.text=No Value Set diff --git a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED index e5f00998a6..1716b3c7e8 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED @@ -89,7 +89,6 @@ VisualizationPanel.fastOrganicLayoutButton.text=Fast Organic VisualizationPanel.hierarchyLayoutButton.text=Hierarchical VisualizationPanel.clearVizButton.text_1=Clear Viz. VisualizationPanel.snapshotButton.text_1=Snapshot Report -ContactsViewer.testLabel.text=No Value Set VisualizationPanel_action_dialogs_title=Communications VisualizationPanel_action_name_text=Snapshot Report VisualizationPanel_module_name=Communications diff --git a/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.form b/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.form index 81e1e314ef..e7e306cf63 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.form +++ b/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.form @@ -16,30 +16,13 @@ - - - - - + - - - - - + - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.java b/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.java index 1808c8bb62..0473ba0e13 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.java @@ -59,30 +59,19 @@ public class ContactsViewer extends JPanel implements RelationshipsViewer{ // //GEN-BEGIN:initComponents private void initComponents() { - testLabel = new javax.swing.JLabel(); - - org.openide.awt.Mnemonics.setLocalizedText(testLabel, org.openide.util.NbBundle.getMessage(ContactsViewer.class, "ContactsViewer.testLabel.text")); // NOI18N - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(testLabel) - .addContainerGap(294, Short.MAX_VALUE)) + .addGap(0, 692, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(testLabel) - .addContainerGap(264, Short.MAX_VALUE)) + .addGap(0, 573, Short.MAX_VALUE) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel testLabel; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/communications/MessageNode.java b/Core/src/org/sleuthkit/autopsy/communications/MessageNode.java index 4a02a1d0ce..963cd2369e 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/MessageNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/MessageNode.java @@ -18,14 +18,15 @@ */ package org.sleuthkit.autopsy.communications; +import java.util.List; import java.util.TimeZone; import java.util.logging.Level; import org.apache.commons.lang3.StringUtils; -import org.openide.nodes.AbstractNode; -import org.openide.nodes.Children; import org.openide.nodes.Sheet; -import org.openide.util.lookup.Lookups; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; +import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; import org.sleuthkit.autopsy.datamodel.NodeProperty; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -38,42 +39,28 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHO import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT; import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME; +import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.TimeUtilities; import org.sleuthkit.datamodel.TskCoreException; /** * Wraps a BlackboardArtifact as an AbstractNode for use in an OutlookView */ -final class MessageNode extends AbstractNode { +final class MessageNode extends BlackboardArtifactNode { private static final Logger logger = Logger.getLogger(RelationshipNode.class.getName()); - private final BlackboardArtifact artifact; - MessageNode(BlackboardArtifact artifact) { - super(Children.LEAF, Lookups.fixed(artifact)); - this.artifact = artifact; + super(artifact); final String stripEnd = StringUtils.stripEnd(artifact.getDisplayName(), "s"); // NON-NLS String removeEndIgnoreCase = StringUtils.removeEndIgnoreCase(stripEnd, "message"); // NON-NLS setDisplayName(removeEndIgnoreCase.isEmpty() ? stripEnd : removeEndIgnoreCase); - - int typeID = artifact.getArtifactTypeID(); - - String filePath = "org/sleuthkit/autopsy/images/"; //NON-NLS - if( typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) { - filePath = filePath + "mail-icon-16.png"; //NON-NLS - } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) { - filePath = filePath + "message.png"; //NON-NLS - } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()) { - filePath = filePath + "calllog.png"; //NON-NLS - } - - setIconBaseWithExtension(filePath); } @Override protected Sheet createSheet() { Sheet sheet = new Sheet(); + List tags = getAllTagsFromDatabase(); Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES); if (sheetSet == null) { sheetSet = Sheet.createPropertiesSet(); @@ -82,6 +69,19 @@ final class MessageNode extends AbstractNode { sheetSet.put(new NodeProperty<>("Type", "Type", "Type", getDisplayName())); //NON-NLS + addScoreProperty(sheetSet, tags); + + CorrelationAttributeInstance correlationAttribute = null; + if (UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) { + correlationAttribute = getCorrelationAttributeInstance(); + } + addCommentProperty(sheetSet, tags, correlationAttribute); + + if (UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) { + addCountProperty(sheetSet, correlationAttribute); + } + final BlackboardArtifact artifact = getArtifact(); + BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID()); if (null != fromID) { //Consider refactoring this to reduce boilerplate @@ -160,4 +160,15 @@ final class MessageNode extends AbstractNode { return ""; } } + + /** + * Circumvent DataResultFilterNode's slightly odd delegation to + * BlackboardArtifactNode.getSourceName(). + * + * @return the displayName of this Node, which is the type. + */ + @Override + public String getSourceName() { + return getDisplayName(); + } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.form b/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.form index a8a0606f8f..7368b264e5 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.form +++ b/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.form @@ -16,14 +16,16 @@ - + + - - + + + @@ -31,5 +33,10 @@ + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.java b/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.java index b5b5159aa3..e58bf3a39c 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.java @@ -18,28 +18,36 @@ */ package org.sleuthkit.autopsy.communications; +import java.awt.Component; +import java.awt.KeyboardFocusManager; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import javax.swing.JPanel; import javax.swing.ListSelectionModel; +import static javax.swing.SwingUtilities.isDescendingFrom; import org.netbeans.swing.outline.DefaultOutlineModel; import org.netbeans.swing.outline.Outline; import org.openide.explorer.ExplorerManager; -import org.openide.explorer.ExplorerUtils; +import static org.openide.explorer.ExplorerUtils.createLookup; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; +import org.openide.nodes.Node; import org.openide.util.Lookup; import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.directorytree.DataResultFilterNode; /** * Visualation for the messages of the currently selected accounts. */ -@ServiceProvider(service=RelationshipsViewer.class) -public class MessagesViewer extends JPanel implements RelationshipsViewer, ExplorerManager.Provider, Lookup.Provider { +@ServiceProvider(service = RelationshipsViewer.class) +public class MessagesViewer extends JPanel implements RelationshipsViewer, ExplorerManager.Provider, Lookup.Provider{ - private final ExplorerManager tableEM = new ExplorerManager(); - private final Lookup lookup; + private final ExplorerManager tableEM; private final Outline outline; - + private final ModifiableProxyLookup proxyLookup; + private final PropertyChangeListener focusPropertyListener; + @Messages({ "MessageViewer_tabTitle=Messages", "MessageViewer_columnHeader_From=From", @@ -48,13 +56,36 @@ public class MessagesViewer extends JPanel implements RelationshipsViewer, Explo "MessageViewer_columnHeader_Subject=Subject", "MessageViewer_columnHeader_Attms=Attachments" }) - + /** * Creates new form MessagesViewer */ public MessagesViewer() { + tableEM = new ExplorerManager(); + proxyLookup = new ModifiableProxyLookup(createLookup(tableEM, getActionMap())); + + // See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed + // explaination of focusPropertyListener + focusPropertyListener = (final PropertyChangeEvent focusEvent) -> { + if (focusEvent.getPropertyName().equalsIgnoreCase("focusOwner")) { + final Component newFocusOwner = (Component) focusEvent.getNewValue(); + + if (newFocusOwner == null) { + return; + } + if (isDescendingFrom(newFocusOwner, contentViewer)) { + //if the focus owner is within the MessageContentViewer (the attachments table) + proxyLookup.setNewLookups(createLookup(((MessageDataContent) contentViewer).getExplorerManager(), getActionMap())); + } else if (isDescendingFrom(newFocusOwner, MessagesViewer.this)) { + //... or if it is within the Results table. + proxyLookup.setNewLookups(createLookup(tableEM, getActionMap())); + + } + } + } ; + initComponents(); - + outline = outlineView.getOutline(); outlineView.setPropertyColumns( "From", Bundle.MessageViewer_columnHeader_From(), @@ -62,38 +93,60 @@ public class MessagesViewer extends JPanel implements RelationshipsViewer, Explo "Date", Bundle.MessageViewer_columnHeader_Date(), "Subject", Bundle.MessageViewer_columnHeader_Subject(), "Attms", Bundle.MessageViewer_columnHeader_Attms() - ); outline.setRootVisible(false); outline.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.AccountNode_accountName()); - - lookup = ExplorerUtils.createLookup(tableEM, getActionMap()); + + tableEM.addPropertyChangeListener((PropertyChangeEvent evt) -> { + if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) { + final Node[] nodes = tableEM.getSelectedNodes(); + + if (nodes != null && nodes.length > 0) { + contentViewer.setNode(nodes[0]); + } + } + }); } - + @Override public String getDisplayName() { return Bundle.MessageViewer_tabTitle(); } - + @Override public JPanel getPanel() { return this; } - + @Override public void setSelectionInfo(SelectionInfo info) { - tableEM.setRootContext(new AbstractNode(Children.create(new MessagesChildNodeFactory(info), true))); + tableEM.setRootContext(new DataResultFilterNode(new AbstractNode(Children.create(new MessagesChildNodeFactory(info), true)), getExplorerManager())); } - - @Override + + @Override public ExplorerManager getExplorerManager() { return tableEM; } - + @Override public Lookup getLookup() { - return lookup; + return proxyLookup; + } + + @Override + public void addNotify() { + super.addNotify(); + //add listener that maintains correct selection in the Global Actions Context + KeyboardFocusManager.getCurrentKeyboardFocusManager() + .addPropertyChangeListener("focusOwner", focusPropertyListener); + } + + @Override + public void removeNotify() { + super.removeNotify(); + KeyboardFocusManager.getCurrentKeyboardFocusManager() + .removePropertyChangeListener("focusOwner", focusPropertyListener); } /** @@ -106,23 +159,27 @@ public class MessagesViewer extends JPanel implements RelationshipsViewer, Explo private void initComponents() { outlineView = new org.openide.explorer.view.OutlineView(); + contentViewer = new MessageDataContent(); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 480, Short.MAX_VALUE) + .addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(contentViewer, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(outlineView, javax.swing.GroupLayout.PREFERRED_SIZE, 475, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 16, Short.MAX_VALUE)) + .addComponent(outlineView, javax.swing.GroupLayout.PREFERRED_SIZE, 190, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(contentViewer, javax.swing.GroupLayout.DEFAULT_SIZE, 778, Short.MAX_VALUE)) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables + private org.sleuthkit.autopsy.contentviewers.MessageContentViewer contentViewer; private org.openide.explorer.view.OutlineView outlineView; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/communications/RelaionshipSetNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/RelaionshipSetNodeFactory.java deleted file mode 100644 index ac2e5d1c54..0000000000 --- a/Core/src/org/sleuthkit/autopsy/communications/RelaionshipSetNodeFactory.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2017-2019 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; - -import java.util.Collection; -import java.util.List; -import org.openide.nodes.ChildFactory; -import org.openide.nodes.Node; -import org.sleuthkit.datamodel.BlackboardArtifact; - -/** - * - */ -public class RelaionshipSetNodeFactory extends ChildFactory { - - private final Collection artifacts; - - public RelaionshipSetNodeFactory(Collection artifacts) { - this.artifacts = artifacts; - } - - @Override - protected boolean createKeys(List list) { - list.addAll(artifacts); - return true; - } - - @Override - protected Node createNodeForKey(BlackboardArtifact key) { - return new RelationshipNode(key); - } -} diff --git a/Core/src/org/sleuthkit/autopsy/communications/RelationshipBrowser.form b/Core/src/org/sleuthkit/autopsy/communications/RelationshipBrowser.form index 7b6fa1d18f..a664317372 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/RelationshipBrowser.form +++ b/Core/src/org/sleuthkit/autopsy/communications/RelationshipBrowser.form @@ -27,6 +27,9 @@ + + + diff --git a/Core/src/org/sleuthkit/autopsy/communications/RelationshipBrowser.java b/Core/src/org/sleuthkit/autopsy/communications/RelationshipBrowser.java index c934ebade9..6f60981278 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/RelationshipBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/communications/RelationshipBrowser.java @@ -27,6 +27,8 @@ import org.openide.util.Lookup; */ public class RelationshipBrowser extends JPanel { + private SelectionInfo currentSelection; + /** * Creates new form RelationshipBrowser */ @@ -38,11 +40,15 @@ public class RelationshipBrowser extends JPanel { }); } + /** + * Sets the value of currentSelection and passes the SelectionInfo onto + * the currently selected\visible tab. + * + * @param info Currently selected account nodes + */ public void setSelectionInfo(SelectionInfo info) { + currentSelection = info; ((RelationshipsViewer)tabPane.getSelectedComponent()).setSelectionInfo(info); - - // TODO If we only pass the info to the currently selected tab, we - // need to do something when the tab changes } /** @@ -56,6 +62,12 @@ public class RelationshipBrowser extends JPanel { tabPane = new javax.swing.JTabbedPane(); + tabPane.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + tabPaneStateChanged(evt); + } + }); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -68,6 +80,10 @@ public class RelationshipBrowser extends JPanel { ); }// //GEN-END:initComponents + private void tabPaneStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_tabPaneStateChanged + ((RelationshipsViewer)tabPane.getSelectedComponent()).setSelectionInfo(currentSelection); + }//GEN-LAST:event_tabPaneStateChanged + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JTabbedPane tabPane; From 6bf77cc1e0a924e0be1cdaf654b2aa201297bf70 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Fri, 12 Apr 2019 15:44:26 -0400 Subject: [PATCH 4/8] Relationship viewer with contacts tab is completed --- .../autopsy/communications/Bundle.properties | 1 + .../communications/Bundle.properties-MERGED | 12 ++ .../communications/ContactDetailsPane.form | 61 ++++++++ .../communications/ContactDetailsPane.java | 99 +++++++++++++ .../autopsy/communications/ContactNode.java | 126 +++++++++++++++++ .../ContactsChildNodeFactory.java | 98 +++++++++++++ .../communications/ContactsViewer.form | 18 ++- .../communications/ContactsViewer.java | 131 ++++++++++++++++-- .../autopsy/communications/FiltersPanel.java | 3 +- .../autopsy/communications/MessageNode.java | 23 +-- .../MessagesChildNodeFactory.java | 4 +- .../communications/MessagesViewer.java | 18 +-- .../communications/RelationshipBrowser.java | 18 +-- .../communications/RelationshipsViewer.java | 16 +-- .../autopsy/communications/SelectionInfo.java | 55 +++++--- 15 files changed, 609 insertions(+), 74 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/communications/ContactDetailsPane.form create mode 100755 Core/src/org/sleuthkit/autopsy/communications/ContactDetailsPane.java create mode 100755 Core/src/org/sleuthkit/autopsy/communications/ContactNode.java create mode 100755 Core/src/org/sleuthkit/autopsy/communications/ContactsChildNodeFactory.java diff --git a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties index 6665c2e958..5f1dd31ce7 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties @@ -39,3 +39,4 @@ VisualizationPanel.fastOrganicLayoutButton.text=Fast Organic VisualizationPanel.hierarchyLayoutButton.text=Hierarchical VisualizationPanel.clearVizButton.text_1=Clear Viz. VisualizationPanel.snapshotButton.text_1=Snapshot Report +ContactDetailsPane.nameLabel.text=jLabel1 diff --git a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED index 1716b3c7e8..de288e42f3 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED @@ -3,6 +3,17 @@ AccountNode.accountType=Type AccountNode.device=Device AccountNode.messageCount=Msgs applyText=Apply +ContactNode_Email=Email Address +ContactNode_Home_Number=Home Number +ContactNode_Mobile_Number=Mobile Number +ContactNode_Name=Name +ContactNode_Office_Number=Office Number +ContactNode_Phone=Phone Number +ContactNode_URL=URL +ContactsViewer_columnHeader_Email=Email +ContactsViewer_columnHeader_Name=Name +ContactsViewer_columnHeader_Phone=Phone +ContactsViewer_tabTitle=Contacts CTL_OpenCVTAction=Communications CVTTopComponent.name=\ Communications Visualization CVTTopComponent.TabConstraints.tabTitle=Visualize @@ -89,6 +100,7 @@ VisualizationPanel.fastOrganicLayoutButton.text=Fast Organic VisualizationPanel.hierarchyLayoutButton.text=Hierarchical VisualizationPanel.clearVizButton.text_1=Clear Viz. VisualizationPanel.snapshotButton.text_1=Snapshot Report +ContactDetailsPane.nameLabel.text=jLabel1 VisualizationPanel_action_dialogs_title=Communications VisualizationPanel_action_name_text=Snapshot Report VisualizationPanel_module_name=Communications diff --git a/Core/src/org/sleuthkit/autopsy/communications/ContactDetailsPane.form b/Core/src/org/sleuthkit/autopsy/communications/ContactDetailsPane.form new file mode 100755 index 0000000000..2cf54c02ea --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/ContactDetailsPane.form @@ -0,0 +1,61 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/communications/ContactDetailsPane.java b/Core/src/org/sleuthkit/autopsy/communications/ContactDetailsPane.java new file mode 100755 index 0000000000..0d466dac88 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/ContactDetailsPane.java @@ -0,0 +1,99 @@ +/* + * 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.communications; + +import org.openide.explorer.ExplorerManager; +import org.openide.nodes.Node; + +/** + * Displays the propertied of a ContactNode in a PropertySheet. + */ +public final class ContactDetailsPane extends javax.swing.JPanel implements ExplorerManager.Provider { + + final private ExplorerManager explorerManager = new ExplorerManager(); + + /** + * Displays the propertied of a ContactNode in a PropertySheet. + */ + public ContactDetailsPane() { + initComponents(); + this.setEnabled(false); + } + + /** + * Sets the list of nodes for the property sheet. + * + * @param nodes List of nodes to set + */ + public void setNode(Node[] nodes) { + if (nodes != null) { + nameLabel.setText(nodes[0].getDisplayName()); + } else { + nameLabel.setText(""); + } + + propertySheet.setNodes(nodes); + } + + @Override + public ExplorerManager getExplorerManager() { + return explorerManager; + } + + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + nameLabel.setEnabled(enabled); + propertySheet.setEnabled(enabled); + } + + /** + * 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() { + + nameLabel = new javax.swing.JLabel(); + propertySheet = new org.openide.explorer.propertysheet.PropertySheet(); + + nameLabel.setFont(new java.awt.Font("Tahoma", 0, 24)); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(ContactDetailsPane.class, "ContactDetailsPane.nameLabel.text")); // NOI18N + + propertySheet.setDescriptionAreaVisible(false); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(propertySheet, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(nameLabel) + .addGap(0, 0, Short.MAX_VALUE))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(nameLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(propertySheet, javax.swing.GroupLayout.DEFAULT_SIZE, 283, Short.MAX_VALUE) + .addContainerGap()) + ); + }// //GEN-END:initComponents + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel nameLabel; + private org.openide.explorer.propertysheet.PropertySheet propertySheet; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/ContactNode.java b/Core/src/org/sleuthkit/autopsy/communications/ContactNode.java new file mode 100755 index 0000000000..4792e70af8 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/ContactNode.java @@ -0,0 +1,126 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 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; + +import java.util.List; +import java.util.TimeZone; +import java.util.logging.Level; +import org.openide.nodes.Sheet; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; +import org.sleuthkit.autopsy.datamodel.NodeProperty; +import org.sleuthkit.datamodel.BlackboardArtifact; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT; +import org.sleuthkit.datamodel.BlackboardAttribute; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_HOME; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_MOBILE; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_OFFICE; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL; +import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME; +import org.sleuthkit.datamodel.Tag; +import org.sleuthkit.datamodel.TimeUtilities; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Extends BlackboardArtifactNode to override createSheet to create a contact + * artifact specific sheet. + */ +final class ContactNode extends BlackboardArtifactNode { + + private static final Logger logger = Logger.getLogger(RelationshipNode.class.getName()); + + @Messages({ + "ContactNode_Name=Name", + "ContactNode_Phone=Phone Number", + "ContactNode_Email=Email Address", + "ContactNode_Mobile_Number=Mobile Number", + "ContactNode_Office_Number=Office Number", + "ContactNode_URL=URL", + "ContactNode_Home_Number=Home Number",}) + + ContactNode(BlackboardArtifact artifact) { + super(artifact); + + setDisplayName(getAttributeDisplayString(artifact, TSK_NAME)); + } + + @Override + protected Sheet createSheet() { + final BlackboardArtifact artifact = getArtifact(); + BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID()); + if (fromID != TSK_CONTACT) { + return super.createSheet(); + } + + Sheet sheet = new Sheet(); + List tags = getAllTagsFromDatabase(); + Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES); + if (sheetSet == null) { + sheetSet = Sheet.createPropertiesSet(); + sheet.put(sheetSet); + } + + sheetSet.put(new NodeProperty<>("email", Bundle.ContactNode_Email(), "", + getAttributeDisplayString(artifact, TSK_EMAIL))); //NON-NLS + sheetSet.put(new NodeProperty<>("phone", Bundle.ContactNode_Phone(), "", + getAttributeDisplayString(artifact, TSK_PHONE_NUMBER))); //NON-NLS + sheetSet.put(new NodeProperty<>("mobile", Bundle.ContactNode_Mobile_Number(), "", + getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_MOBILE))); //NON-NLS + sheetSet.put(new NodeProperty<>("home", Bundle.ContactNode_Home_Number(), "", + getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_HOME))); //NON-NLS + sheetSet.put(new NodeProperty<>("office", Bundle.ContactNode_Office_Number(), "", + getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_OFFICE))); //NON-NLS + sheetSet.put(new NodeProperty<>("url", Bundle.ContactNode_URL(), "", + getAttributeDisplayString(artifact, TSK_URL))); //NON-NLS + + return sheet; + } + + private static String getAttributeDisplayString(final BlackboardArtifact artifact, final BlackboardAttribute.ATTRIBUTE_TYPE attributeType) { + try { + BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(attributeType.getTypeID()))); + if (attribute == null) { + return ""; + } else if (attributeType.getValueType() == DATETIME) { + return TimeUtilities.epochToTime(attribute.getValueLong(), + TimeZone.getTimeZone(Utils.getUserPreferredZoneId())); + } else { + return attribute.getDisplayString(); + } + } catch (TskCoreException tskCoreException) { + logger.log(Level.WARNING, "Error getting attribute value.", tskCoreException); //NON-NLS + return ""; + } + } + + /** + * Circumvent DataResultFilterNode's slightly odd delegation to + * BlackboardArtifactNode.getSourceName(). + * + * @return the displayName of this Node, which is the type. + */ + @Override + public String getSourceName() { + return getDisplayName(); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/ContactsChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/ContactsChildNodeFactory.java new file mode 100755 index 0000000000..4e5df13589 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/ContactsChildNodeFactory.java @@ -0,0 +1,98 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 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; + +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import org.openide.nodes.ChildFactory; +import org.openide.nodes.Node; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.BlackboardArtifact; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT; +import org.sleuthkit.datamodel.CommunicationsManager; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * ChildFactory for ContactNodes. + */ +final class ContactsChildNodeFactory extends ChildFactory{ + private static final Logger logger = Logger.getLogger(MessagesChildNodeFactory.class.getName()); + + private CommunicationsManager communicationManager = null; + private final SelectionInfo selectionInfo; + + /** + * Construct a new ContactsChildNodeFactory from the currently selectionInfo + * + * @param selectionInfo SelectionInfo object for the currently selected + * accounts + */ + ContactsChildNodeFactory(SelectionInfo selectionInfo) { + this.selectionInfo = selectionInfo; + + try { + communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager(); + } catch (NoCurrentCaseException | TskCoreException ex) { + logger.log(Level.SEVERE, "Failed to get communications manager from case.", ex); //NON-NLS + } + } + + /** + * Creates a list of Keys (BlackboardArtifact) for only contacts of the + * currently selected accounts + * @param list List of BlackboardArtifact to populate + * @return True on success + */ + @Override + protected boolean createKeys(List list) { + if (communicationManager == null) { + return false; + } + + final Set relationshipSources; + + try { + relationshipSources = communicationManager.getRelationshipSources(selectionInfo.getAccountDevicesInstances(), selectionInfo.getCommunicationsFilter()); + + relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> { + + BlackboardArtifact bba = (BlackboardArtifact) content; + BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID()); + + if (fromID == TSK_CONTACT) { + list.add(bba); + } + }); + + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Failed to get relationship sources.", ex); //NON-NLS + } + + return true; + } + + @Override + protected Node createNodeForKey(BlackboardArtifact key) { + return new ContactNode(key); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.form b/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.form index e7e306cf63..166fd065bf 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.form +++ b/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.form @@ -16,13 +16,27 @@ - + + - + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.java b/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.java index 0473ba0e13..3e794f48a8 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.java @@ -18,36 +18,134 @@ */ package org.sleuthkit.autopsy.communications; +import java.awt.Component; +import java.awt.KeyboardFocusManager; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import javax.swing.JPanel; +import javax.swing.ListSelectionModel; +import static javax.swing.SwingUtilities.isDescendingFrom; +import org.netbeans.swing.outline.DefaultOutlineModel; +import org.netbeans.swing.outline.Outline; +import org.openide.explorer.ExplorerManager; +import static org.openide.explorer.ExplorerUtils.createLookup; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.openide.util.Lookup; +import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.corecomponents.TableFilterNode; +import org.sleuthkit.autopsy.directorytree.DataResultFilterNode; /** - * Visualization for contacts - * + * Visualization for contact nodes. + * */ -@ServiceProvider(service=RelationshipsViewer.class) -public class ContactsViewer extends JPanel implements RelationshipsViewer{ +@ServiceProvider(service = RelationshipsViewer.class) +public final class ContactsViewer extends JPanel implements RelationshipsViewer, ExplorerManager.Provider, Lookup.Provider { + + private final ExplorerManager tableEM; + private final Outline outline; + private final ModifiableProxyLookup proxyLookup; + private final PropertyChangeListener focusPropertyListener; + + @NbBundle.Messages({ + "ContactsViewer_tabTitle=Contacts", + "ContactsViewer_columnHeader_Name=Name", + "ContactsViewer_columnHeader_Phone=Phone", + "ContactsViewer_columnHeader_Email=Email",}) /** - * Creates new form ContactsViewer + * Visualization for contact nodes. */ public ContactsViewer() { + tableEM = new ExplorerManager(); + proxyLookup = new ModifiableProxyLookup(createLookup(tableEM, getActionMap())); + + // See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed + // explaination of focusPropertyListener + focusPropertyListener = (final PropertyChangeEvent focusEvent) -> { + if (focusEvent.getPropertyName().equalsIgnoreCase("focusOwner")) { + final Component newFocusOwner = (Component) focusEvent.getNewValue(); + + if (newFocusOwner == null) { + return; + } + if (isDescendingFrom(newFocusOwner, contactPane)) { + //if the focus owner is within the MessageContentViewer (the attachments table) + proxyLookup.setNewLookups(createLookup(contactPane.getExplorerManager(), getActionMap())); + } else if (isDescendingFrom(newFocusOwner, ContactsViewer.this)) { + //... or if it is within the Results table. + proxyLookup.setNewLookups(createLookup(tableEM, getActionMap())); + + } + } + }; + initComponents(); + + outline = outlineView.getOutline(); + outlineView.setPropertyColumns( + "email", Bundle.ContactsViewer_columnHeader_Email(), + "phone", Bundle.ContactsViewer_columnHeader_Phone() + ); + outline.setRootVisible(false); + outline.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.ContactsViewer_columnHeader_Name()); + + tableEM.addPropertyChangeListener((PropertyChangeEvent evt) -> { + if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) { + final Node[] nodes = tableEM.getSelectedNodes(); + + if (nodes != null && nodes.length > 0) { + contactPane.setEnabled(true); + contactPane.setNode(nodes); + } + } + }); } - + @Override public String getDisplayName() { - return "Contacts"; + return Bundle.ContactsViewer_tabTitle(); } - + @Override public JPanel getPanel() { return this; } - + @Override public void setSelectionInfo(SelectionInfo info) { - + contactPane.setNode(new Node[]{new AbstractNode(Children.LEAF)}); + contactPane.setEnabled(false); + tableEM.setRootContext(new TableFilterNode(new DataResultFilterNode(new AbstractNode(Children.create(new ContactsChildNodeFactory(info), true)), getExplorerManager()), true)); + } + + @Override + public ExplorerManager getExplorerManager() { + return tableEM; + } + + @Override + public Lookup getLookup() { + return proxyLookup; + } + + @Override + public void addNotify() { + super.addNotify(); + //add listener that maintains correct selection in the Global Actions Context + KeyboardFocusManager.getCurrentKeyboardFocusManager() + .addPropertyChangeListener("focusOwner", focusPropertyListener); + } + + @Override + public void removeNotify() { + super.removeNotify(); + KeyboardFocusManager.getCurrentKeyboardFocusManager() + .removePropertyChangeListener("focusOwner", focusPropertyListener); } /** @@ -59,19 +157,28 @@ public class ContactsViewer extends JPanel implements RelationshipsViewer{ // //GEN-BEGIN:initComponents private void initComponents() { + outlineView = new org.openide.explorer.view.OutlineView(); + contactPane = new org.sleuthkit.autopsy.communications.ContactDetailsPane(); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 692, Short.MAX_VALUE) + .addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(contactPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 573, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(contactPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables + private org.sleuthkit.autopsy.communications.ContactDetailsPane contactPane; + private org.openide.explorer.view.OutlineView outlineView; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java index 587bf47260..287b6f9ae9 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java @@ -49,6 +49,7 @@ import org.sleuthkit.datamodel.CommunicationsFilter.DateRangeFilter; import org.sleuthkit.datamodel.CommunicationsFilter.DeviceFilter; import org.sleuthkit.datamodel.DataSource; import static org.sleuthkit.datamodel.Relationship.Type.CALL_LOG; +import static org.sleuthkit.datamodel.Relationship.Type.CONTACT; import static org.sleuthkit.datamodel.Relationship.Type.MESSAGE; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; @@ -514,7 +515,7 @@ final public class FiltersPanel extends JPanel { commsFilter.addAndFilter(getAccountTypeFilter()); commsFilter.addAndFilter(getDateRangeFilter()); commsFilter.addAndFilter(new CommunicationsFilter.RelationshipTypeFilter( - ImmutableSet.of(CALL_LOG, MESSAGE))); + ImmutableSet.of(CALL_LOG, MESSAGE, CONTACT))); return commsFilter; } diff --git a/Core/src/org/sleuthkit/autopsy/communications/MessageNode.java b/Core/src/org/sleuthkit/autopsy/communications/MessageNode.java index 963cd2369e..8fd5e44d96 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/MessageNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/MessageNode.java @@ -47,16 +47,17 @@ import org.sleuthkit.datamodel.TskCoreException; * Wraps a BlackboardArtifact as an AbstractNode for use in an OutlookView */ final class MessageNode extends BlackboardArtifactNode { + private static final Logger logger = Logger.getLogger(RelationshipNode.class.getName()); - + MessageNode(BlackboardArtifact artifact) { super(artifact); - + final String stripEnd = StringUtils.stripEnd(artifact.getDisplayName(), "s"); // NON-NLS String removeEndIgnoreCase = StringUtils.removeEndIgnoreCase(stripEnd, "message"); // NON-NLS setDisplayName(removeEndIgnoreCase.isEmpty() ? stripEnd : removeEndIgnoreCase); } - + @Override protected Sheet createSheet() { Sheet sheet = new Sheet(); @@ -68,20 +69,20 @@ final class MessageNode extends BlackboardArtifactNode { } sheetSet.put(new NodeProperty<>("Type", "Type", "Type", getDisplayName())); //NON-NLS - + addScoreProperty(sheetSet, tags); - + CorrelationAttributeInstance correlationAttribute = null; - if (UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) { + if (UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) { correlationAttribute = getCorrelationAttributeInstance(); } addCommentProperty(sheetSet, tags, correlationAttribute); - - if (UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) { + + if (UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) { addCountProperty(sheetSet, correlationAttribute); } final BlackboardArtifact artifact = getArtifact(); - + BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID()); if (null != fromID) { //Consider refactoring this to reduce boilerplate @@ -160,8 +161,8 @@ final class MessageNode extends BlackboardArtifactNode { return ""; } } - - /** + + /** * Circumvent DataResultFilterNode's slightly odd delegation to * BlackboardArtifactNode.getSourceName(). * diff --git a/Core/src/org/sleuthkit/autopsy/communications/MessagesChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/MessagesChildNodeFactory.java index 9a1c7d1024..220e3f718f 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/MessagesChildNodeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/communications/MessagesChildNodeFactory.java @@ -36,7 +36,7 @@ import org.sleuthkit.datamodel.TskCoreException; * only emails, call logs and messages. * */ -public class MessagesChildNodeFactory extends ChildFactory { +final class MessagesChildNodeFactory extends ChildFactory { private static final Logger logger = Logger.getLogger(MessagesChildNodeFactory.class.getName()); @@ -62,7 +62,9 @@ public class MessagesChildNodeFactory extends ChildFactory { /** * Creates a list of Keys (BlackboardArtifact) for only messages for the * currently selected accounts + * * @param list List of BlackboardArtifact to populate + * * @return True on success */ @Override diff --git a/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.java b/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.java index e58bf3a39c..ca185eee90 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.java @@ -35,13 +35,14 @@ import org.openide.nodes.Node; import org.openide.util.Lookup; import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.corecomponents.TableFilterNode; import org.sleuthkit.autopsy.directorytree.DataResultFilterNode; /** * Visualation for the messages of the currently selected accounts. */ @ServiceProvider(service = RelationshipsViewer.class) -public class MessagesViewer extends JPanel implements RelationshipsViewer, ExplorerManager.Provider, Lookup.Provider{ +public final class MessagesViewer extends JPanel implements RelationshipsViewer, ExplorerManager.Provider, Lookup.Provider { private final ExplorerManager tableEM; private final Outline outline; @@ -58,7 +59,7 @@ public class MessagesViewer extends JPanel implements RelationshipsViewer, Explo }) /** - * Creates new form MessagesViewer + * Visualation for the messages of the currently selected accounts. */ public MessagesViewer() { tableEM = new ExplorerManager(); @@ -69,7 +70,7 @@ public class MessagesViewer extends JPanel implements RelationshipsViewer, Explo focusPropertyListener = (final PropertyChangeEvent focusEvent) -> { if (focusEvent.getPropertyName().equalsIgnoreCase("focusOwner")) { final Component newFocusOwner = (Component) focusEvent.getNewValue(); - + if (newFocusOwner == null) { return; } @@ -79,10 +80,10 @@ public class MessagesViewer extends JPanel implements RelationshipsViewer, Explo } else if (isDescendingFrom(newFocusOwner, MessagesViewer.this)) { //... or if it is within the Results table. proxyLookup.setNewLookups(createLookup(tableEM, getActionMap())); - + } } - } ; + }; initComponents(); @@ -92,11 +93,12 @@ public class MessagesViewer extends JPanel implements RelationshipsViewer, Explo "To", Bundle.MessageViewer_columnHeader_To(), "Date", Bundle.MessageViewer_columnHeader_Date(), "Subject", Bundle.MessageViewer_columnHeader_Subject(), - "Attms", Bundle.MessageViewer_columnHeader_Attms() + "Attms", Bundle.MessageViewer_columnHeader_Attms(), + "Type", "Type" ); outline.setRootVisible(false); outline.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.AccountNode_accountName()); + ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel("Type"); tableEM.addPropertyChangeListener((PropertyChangeEvent evt) -> { if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) { @@ -121,7 +123,7 @@ public class MessagesViewer extends JPanel implements RelationshipsViewer, Explo @Override public void setSelectionInfo(SelectionInfo info) { - tableEM.setRootContext(new DataResultFilterNode(new AbstractNode(Children.create(new MessagesChildNodeFactory(info), true)), getExplorerManager())); + tableEM.setRootContext(new TableFilterNode(new DataResultFilterNode(new AbstractNode(Children.create(new MessagesChildNodeFactory(info), true)), getExplorerManager()), true)); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/communications/RelationshipBrowser.java b/Core/src/org/sleuthkit/autopsy/communications/RelationshipBrowser.java index 6f60981278..8fa082fc2c 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/RelationshipBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/communications/RelationshipBrowser.java @@ -23,12 +23,12 @@ import org.openide.util.Lookup; /** * Displays the Relationship information for the currently selected accounts. - * + * */ -public class RelationshipBrowser extends JPanel { +final class RelationshipBrowser extends JPanel { private SelectionInfo currentSelection; - + /** * Creates new form RelationshipBrowser */ @@ -39,16 +39,16 @@ public class RelationshipBrowser extends JPanel { tabPane.add(viewer.getDisplayName(), viewer.getPanel()); }); } - + /** - * Sets the value of currentSelection and passes the SelectionInfo onto - * the currently selected\visible tab. - * + * Sets the value of currentSelection and passes the SelectionInfo onto the + * currently selected\visible tab. + * * @param info Currently selected account nodes */ public void setSelectionInfo(SelectionInfo info) { currentSelection = info; - ((RelationshipsViewer)tabPane.getSelectedComponent()).setSelectionInfo(info); + ((RelationshipsViewer) tabPane.getSelectedComponent()).setSelectionInfo(info); } /** @@ -81,7 +81,7 @@ public class RelationshipBrowser extends JPanel { }// //GEN-END:initComponents private void tabPaneStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_tabPaneStateChanged - ((RelationshipsViewer)tabPane.getSelectedComponent()).setSelectionInfo(currentSelection); + ((RelationshipsViewer) tabPane.getSelectedComponent()).setSelectionInfo(currentSelection); }//GEN-LAST:event_tabPaneStateChanged diff --git a/Core/src/org/sleuthkit/autopsy/communications/RelationshipsViewer.java b/Core/src/org/sleuthkit/autopsy/communications/RelationshipsViewer.java index 82464de4ba..395182f5d6 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/RelationshipsViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/RelationshipsViewer.java @@ -24,26 +24,26 @@ import javax.swing.JPanel; * Interface for Controls wishing to appear in the RelationshipBrowser tabPane. */ public interface RelationshipsViewer { - + /** * Returns the value to be displayed on the "tab" - * + * * @return String display name */ public String getDisplayName(); - + /** * Returns the JPanel to be displayed in the RelationshipBrowser. - * + * * @return JPanel to be displayed */ public JPanel getPanel(); - + /** * Sets current SelectionInfo allowing the panel to update accordingly. - * + * * @param info SelectionInfo instance representing the currently selected - * accounts + * accounts */ - public void setSelectionInfo(SelectionInfo info); + public void setSelectionInfo(SelectionInfo info); } diff --git a/Core/src/org/sleuthkit/autopsy/communications/SelectionInfo.java b/Core/src/org/sleuthkit/autopsy/communications/SelectionInfo.java index 6dc370841b..d4131b2024 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/SelectionInfo.java +++ b/Core/src/org/sleuthkit/autopsy/communications/SelectionInfo.java @@ -19,34 +19,45 @@ package org.sleuthkit.autopsy.communications; import java.util.Set; -import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AccountDeviceInstance; import org.sleuthkit.datamodel.CommunicationsFilter; - /** * Class to wrap the details of the current selection from the AccountBrowser or * VisualizationPane - * */ -public class SelectionInfo { - - static final private Logger logger = Logger.getLogger(SelectionInfo.class.getName()); +final class SelectionInfo { + + private final Set accountDeviceInstances; + private final CommunicationsFilter communicationFilter; + + /** + * Wraps the details of the currently selected accounts. + * + * @param accountDeviceInstances Selected accountDecivedInstances + * @param communicationFilter Currently selected communications filters + */ + SelectionInfo(Set accountDeviceInstances, CommunicationsFilter communicationFilter) { + this.accountDeviceInstances = accountDeviceInstances; + this.communicationFilter = communicationFilter; + } + + /** + * Returns the currently selected accountDeviceInstances + * + * @return Set of AccountDeviceInstance + */ + public Set getAccountDevicesInstances() { + return accountDeviceInstances; + } + + /** + * Returns the currently selected communications filters. + * + * @return Instance of CommunicationsFilter + */ + public CommunicationsFilter getCommunicationsFilter() { + return communicationFilter; + } - private final Set accountDeviceInstances; - private final CommunicationsFilter communicationFilter; - - SelectionInfo(Set accountDeviceInstances, CommunicationsFilter communicationFilter) { - this.accountDeviceInstances = accountDeviceInstances; - this.communicationFilter = communicationFilter; - } - - public Set getAccountDevicesInstances(){ - return accountDeviceInstances; - } - - public CommunicationsFilter getCommunicationsFilter() { - return communicationFilter; - } - } From febbb1212338aff2b45dbb8f0c274ae40b53c234 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Fri, 12 Apr 2019 16:35:17 -0400 Subject: [PATCH 5/8] Added the refresh node functionality to the node factories. --- .../ContactsChildNodeFactory.java | 29 +++++++++++++------ .../communications/ContactsViewer.java | 7 ++++- .../MessagesChildNodeFactory.java | 29 +++++++++++++------ .../communications/MessagesViewer.java | 7 ++++- .../autopsy/communications/SelectionInfo.java | 2 +- 5 files changed, 53 insertions(+), 21 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/ContactsChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/ContactsChildNodeFactory.java index 4e5df13589..08471c5324 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/ContactsChildNodeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/communications/ContactsChildNodeFactory.java @@ -38,8 +38,7 @@ import org.sleuthkit.datamodel.TskCoreException; final class ContactsChildNodeFactory extends ChildFactory{ private static final Logger logger = Logger.getLogger(MessagesChildNodeFactory.class.getName()); - private CommunicationsManager communicationManager = null; - private final SelectionInfo selectionInfo; + private SelectionInfo selectionInfo; /** * Construct a new ContactsChildNodeFactory from the currently selectionInfo @@ -48,13 +47,17 @@ final class ContactsChildNodeFactory extends ChildFactory{ * accounts */ ContactsChildNodeFactory(SelectionInfo selectionInfo) { + this.selectionInfo = selectionInfo; + } + + /** + * Updates the current instance of selectionInfo and calls the refresh method. + * + * @param selectionInfo New instance of the currently selected accounts + */ + public void refresh(SelectionInfo selectionInfo) { this.selectionInfo = selectionInfo; - - try { - communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager(); - } catch (NoCurrentCaseException | TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to get communications manager from case.", ex); //NON-NLS - } + refresh(true); } /** @@ -65,9 +68,17 @@ final class ContactsChildNodeFactory extends ChildFactory{ */ @Override protected boolean createKeys(List list) { - if (communicationManager == null) { + CommunicationsManager communicationManager; + try { + communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager(); + } catch (NoCurrentCaseException | TskCoreException ex) { + logger.log(Level.SEVERE, "Failed to get communications manager from case.", ex); //NON-NLS return false; } + + if(selectionInfo == null) { + return true; + } final Set relationshipSources; diff --git a/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.java b/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.java index 3e794f48a8..3c8cebedd5 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/ContactsViewer.java @@ -49,6 +49,7 @@ public final class ContactsViewer extends JPanel implements RelationshipsViewer, private final Outline outline; private final ModifiableProxyLookup proxyLookup; private final PropertyChangeListener focusPropertyListener; + private final ContactsChildNodeFactory nodeFactory; @NbBundle.Messages({ "ContactsViewer_tabTitle=Contacts", @@ -62,6 +63,7 @@ public final class ContactsViewer extends JPanel implements RelationshipsViewer, public ContactsViewer() { tableEM = new ExplorerManager(); proxyLookup = new ModifiableProxyLookup(createLookup(tableEM, getActionMap())); + nodeFactory = new ContactsChildNodeFactory(null); // See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed // explaination of focusPropertyListener @@ -104,6 +106,8 @@ public final class ContactsViewer extends JPanel implements RelationshipsViewer, } } }); + + tableEM.setRootContext(new TableFilterNode(new DataResultFilterNode(new AbstractNode(Children.create(nodeFactory, true)), getExplorerManager()), true)); } @Override @@ -120,7 +124,8 @@ public final class ContactsViewer extends JPanel implements RelationshipsViewer, public void setSelectionInfo(SelectionInfo info) { contactPane.setNode(new Node[]{new AbstractNode(Children.LEAF)}); contactPane.setEnabled(false); - tableEM.setRootContext(new TableFilterNode(new DataResultFilterNode(new AbstractNode(Children.create(new ContactsChildNodeFactory(info), true)), getExplorerManager()), true)); + + nodeFactory.refresh(info); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/communications/MessagesChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/MessagesChildNodeFactory.java index 220e3f718f..38d5cfa8f0 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/MessagesChildNodeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/communications/MessagesChildNodeFactory.java @@ -40,8 +40,7 @@ final class MessagesChildNodeFactory extends ChildFactory { private static final Logger logger = Logger.getLogger(MessagesChildNodeFactory.class.getName()); - private CommunicationsManager communicationManager = null; - private final SelectionInfo selectionInfo; + private SelectionInfo selectionInfo; /** * Construct a new MessageChildNodeFactory from the currently selectionInfo @@ -51,12 +50,16 @@ final class MessagesChildNodeFactory extends ChildFactory { */ MessagesChildNodeFactory(SelectionInfo selectionInfo) { this.selectionInfo = selectionInfo; - - try { - communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager(); - } catch (NoCurrentCaseException | TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to get communications manager from case.", ex); //NON-NLS - } + } + + /** + * Updates the current instance of selectionInfo and calls the refresh method. + * + * @param selectionInfo New instance of the currently selected accounts + */ + public void refresh(SelectionInfo selectionInfo) { + this.selectionInfo = selectionInfo; + refresh(true); } /** @@ -69,9 +72,17 @@ final class MessagesChildNodeFactory extends ChildFactory { */ @Override protected boolean createKeys(List list) { - if (communicationManager == null) { + CommunicationsManager communicationManager; + try { + communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager(); + } catch (NoCurrentCaseException | TskCoreException ex) { + logger.log(Level.SEVERE, "Failed to get communications manager from case.", ex); //NON-NLS return false; } + + if(selectionInfo == null) { + return true; + } final Set relationshipSources; diff --git a/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.java b/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.java index ca185eee90..45b121e243 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/MessagesViewer.java @@ -48,6 +48,7 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer, private final Outline outline; private final ModifiableProxyLookup proxyLookup; private final PropertyChangeListener focusPropertyListener; + private final MessagesChildNodeFactory nodeFactory; @Messages({ "MessageViewer_tabTitle=Messages", @@ -64,6 +65,7 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer, public MessagesViewer() { tableEM = new ExplorerManager(); proxyLookup = new ModifiableProxyLookup(createLookup(tableEM, getActionMap())); + nodeFactory = new MessagesChildNodeFactory(null); // See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed // explaination of focusPropertyListener @@ -109,6 +111,8 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer, } } }); + + tableEM.setRootContext(new TableFilterNode(new DataResultFilterNode(new AbstractNode(Children.create(nodeFactory, true)), getExplorerManager()), true)); } @Override @@ -123,7 +127,8 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer, @Override public void setSelectionInfo(SelectionInfo info) { - tableEM.setRootContext(new TableFilterNode(new DataResultFilterNode(new AbstractNode(Children.create(new MessagesChildNodeFactory(info), true)), getExplorerManager()), true)); +// tableEM.setRootContext(new TableFilterNode(new DataResultFilterNode(new AbstractNode(Children.create(new MessagesChildNodeFactory(info), true)), getExplorerManager()), true)); + nodeFactory.refresh(info); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/communications/SelectionInfo.java b/Core/src/org/sleuthkit/autopsy/communications/SelectionInfo.java index d4131b2024..d1a28eb2d6 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/SelectionInfo.java +++ b/Core/src/org/sleuthkit/autopsy/communications/SelectionInfo.java @@ -26,7 +26,7 @@ import org.sleuthkit.datamodel.CommunicationsFilter; * Class to wrap the details of the current selection from the AccountBrowser or * VisualizationPane */ -final class SelectionInfo { +public final class SelectionInfo { private final Set accountDeviceInstances; private final CommunicationsFilter communicationFilter; From d60e12e9083d6502dd43cc5a79230a550ce82f7f Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 16 Apr 2019 11:35:34 -0400 Subject: [PATCH 6/8] Put user visible strings into Messages --- .../autopsy/communications/MessageNode.java | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/MessageNode.java b/Core/src/org/sleuthkit/autopsy/communications/MessageNode.java index 4a02a1d0ce..ff64185d25 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/MessageNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/MessageNode.java @@ -24,6 +24,7 @@ import org.apache.commons.lang3.StringUtils; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; import org.openide.nodes.Sheet; +import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.NodeProperty; @@ -71,6 +72,15 @@ final class MessageNode extends AbstractNode { setIconBaseWithExtension(filePath); } + @Messages({ + "MessageNode_Node_Property_Type=Type", + "MessageNode_Node_Property_From=From", + "MessageNode_Node_Property_To=To", + "MessageNode_Node_Property_Date=Date", + "MessageNode_Node_Property_Subject=Subject", + "MessageNode_Node_Property_Attms=Attachments" + }) + @Override protected Sheet createSheet() { Sheet sheet = new Sheet(); @@ -80,49 +90,49 @@ final class MessageNode extends AbstractNode { sheet.put(sheetSet); } - sheetSet.put(new NodeProperty<>("Type", "Type", "Type", getDisplayName())); //NON-NLS + sheetSet.put(new NodeProperty<>("Type", Bundle.MessageNode_Node_Property_Type(), "", getDisplayName())); //NON-NLS BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID()); if (null != fromID) { //Consider refactoring this to reduce boilerplate switch (fromID) { case TSK_EMAIL_MSG: - sheetSet.put(new NodeProperty<>("From", "From", "From", + sheetSet.put(new NodeProperty<>("From", Bundle.MessageNode_Node_Property_From(), "", StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_FROM), " \t\n;"))); //NON-NLS - sheetSet.put(new NodeProperty<>("To", "To", "To", + sheetSet.put(new NodeProperty<>("To", Bundle.MessageNode_Node_Property_To(), "", StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_TO), " \t\n;"))); //NON-NLS - sheetSet.put(new NodeProperty<>("Date", "Date", "Date", + sheetSet.put(new NodeProperty<>("Date", Bundle.MessageNode_Node_Property_Date(), "", getAttributeDisplayString(artifact, TSK_DATETIME_SENT))); //NON-NLS - sheetSet.put(new NodeProperty<>("Subject", "Subject", "Subject", + sheetSet.put(new NodeProperty<>("Subject", Bundle.MessageNode_Node_Property_Subject(), "", getAttributeDisplayString(artifact, TSK_SUBJECT))); //NON-NLS try { - sheetSet.put(new NodeProperty<>("Attms", "Attms", "Attms", artifact.getChildrenCount())); //NON-NLS + sheetSet.put(new NodeProperty<>("Attms", Bundle.MessageNode_Node_Property_Attms(), "", artifact.getChildrenCount())); //NON-NLS } catch (TskCoreException ex) { logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex); //NON-NLS } break; case TSK_MESSAGE: - sheetSet.put(new NodeProperty<>("From", "From", "From", + sheetSet.put(new NodeProperty<>("From", Bundle.MessageNode_Node_Property_From(), "", getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM))); //NON-NLS - sheetSet.put(new NodeProperty<>("To", "To", "To", + sheetSet.put(new NodeProperty<>("To", Bundle.MessageNode_Node_Property_To(), "", getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO))); //NON-NLS - sheetSet.put(new NodeProperty<>("Date", "Date", "Date", + sheetSet.put(new NodeProperty<>("Date", Bundle.MessageNode_Node_Property_Date(), "", getAttributeDisplayString(artifact, TSK_DATETIME))); //NON-NLS - sheetSet.put(new NodeProperty<>("Subject", "Subject", "Subject", + sheetSet.put(new NodeProperty<>("Subject", Bundle.MessageNode_Node_Property_Subject(), "", getAttributeDisplayString(artifact, TSK_SUBJECT))); //NON-NLS try { - sheetSet.put(new NodeProperty<>("Attms", "Attms", "Attms", artifact.getChildrenCount())); //NON-NLS + sheetSet.put(new NodeProperty<>("Attms", Bundle.MessageNode_Node_Property_Attms(), "", artifact.getChildrenCount())); //NON-NLS } catch (TskCoreException ex) { logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex); //NON-NLS } break; case TSK_CALLLOG: - sheetSet.put(new NodeProperty<>("From", "From", "From", + sheetSet.put(new NodeProperty<>("From", Bundle.MessageNode_Node_Property_From(), "", getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM))); //NON-NLS - sheetSet.put(new NodeProperty<>("To", "To", "To", + sheetSet.put(new NodeProperty<>("To", Bundle.MessageNode_Node_Property_To(), "", getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO))); //NON-NLS - sheetSet.put(new NodeProperty<>("Date", "Date", "Date", + sheetSet.put(new NodeProperty<>("Date", Bundle.MessageNode_Node_Property_Date(), "", getAttributeDisplayString(artifact, TSK_DATETIME_START))); //NON-NLS break; default: From a8a6735ecff28af2374b6ced4b010cca04804ec6 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 16 Apr 2019 12:59:01 -0400 Subject: [PATCH 7/8] updated based on review comments --- .../communications/Bundle.properties-MERGED | 7 ++++++- .../communications/ContactDetailsPane.java | 19 ++++++++++++++++--- .../autopsy/communications/ContactNode.java | 1 - 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED index de288e42f3..0a92efdbf8 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED @@ -33,7 +33,12 @@ FiltersPanel.refreshButton.text=Refresh FiltersPanel.deviceRequiredLabel.text=Select at least one. FiltersPanel.accountTypeRequiredLabel.text=Select at least one. FiltersPanel.needsRefreshLabel.text=Displayed data is out of date. Press Refresh. -MessageBrowser.DataResultViewerTable.title=Messages +MessageNode_Node_Property_Attms=Attachments +MessageNode_Node_Property_Date=Date +MessageNode_Node_Property_From=From +MessageNode_Node_Property_Subject=Subject +MessageNode_Node_Property_To=To +MessageNode_Node_Property_Type=Type MessageViewer_columnHeader_Attms=Attachments MessageViewer_columnHeader_Date=Date MessageViewer_columnHeader_From=From diff --git a/Core/src/org/sleuthkit/autopsy/communications/ContactDetailsPane.java b/Core/src/org/sleuthkit/autopsy/communications/ContactDetailsPane.java index 0d466dac88..c22f60fb7e 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/ContactDetailsPane.java +++ b/Core/src/org/sleuthkit/autopsy/communications/ContactDetailsPane.java @@ -1,7 +1,20 @@ /* - * 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 2019 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; diff --git a/Core/src/org/sleuthkit/autopsy/communications/ContactNode.java b/Core/src/org/sleuthkit/autopsy/communications/ContactNode.java index 4792e70af8..f70cbcf682 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/ContactNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/ContactNode.java @@ -73,7 +73,6 @@ final class ContactNode extends BlackboardArtifactNode { } Sheet sheet = new Sheet(); - List tags = getAllTagsFromDatabase(); Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES); if (sheetSet == null) { sheetSet = Sheet.createPropertiesSet(); From 8a0a84a6f8f80874c068d721bcefb816b4162808 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 16 Apr 2019 13:00:32 -0400 Subject: [PATCH 8/8] update based on review comments --- Core/src/org/sleuthkit/autopsy/communications/ContactNode.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/ContactNode.java b/Core/src/org/sleuthkit/autopsy/communications/ContactNode.java index f70cbcf682..c73cfff430 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/ContactNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/ContactNode.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.communications; -import java.util.List; import java.util.TimeZone; import java.util.logging.Level; import org.openide.nodes.Sheet; @@ -37,7 +36,6 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHO import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_OFFICE; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL; import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME; -import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.TimeUtilities; import org.sleuthkit.datamodel.TskCoreException;