diff --git a/Core/src/org/sleuthkit/autopsy/communications/AccountDetailsNode.java b/Core/src/org/sleuthkit/autopsy/communications/AccountDetailsNode.java index ac93209b8b..5136ed2843 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/AccountDetailsNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/AccountDetailsNode.java @@ -18,17 +18,16 @@ */ package org.sleuthkit.autopsy.communications; +import java.util.List; import java.util.Set; -import java.util.logging.Level; import org.openide.nodes.AbstractNode; +import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.datamodel.AccountDeviceInstance; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.CommunicationsFilter; import org.sleuthkit.datamodel.CommunicationsManager; -import org.sleuthkit.datamodel.TskCoreException; /** * 'Root' Node for the Account/Messages area. Has children which are all the @@ -39,37 +38,43 @@ class AccountDetailsNode extends AbstractNode { private final static Logger logger = Logger.getLogger(AccountDetailsNode.class.getName()); - AccountDetailsNode(Set accountDeviceInstances, CommunicationsFilter filter, CommunicationsManager commsManager) { - super(new AccountRelationshipChildren(accountDeviceInstances, commsManager, filter)); + AccountDetailsNode(Set accountDeviceInstances, CommunicationsFilter filter, CommunicationsManager commsManager) { + super(Children.create(new AccountRelationshipChildren(accountDeviceInstances, commsManager, filter), true)); } /** * Children object for the relationships that the accounts are part of. */ - private static class AccountRelationshipChildren extends Children.Keys { + private static class AccountRelationshipChildren extends ChildFactory { - private final Set accountDeviceInstances; + private final Set accountDeviceInstances; private final CommunicationsManager commsManager; private final CommunicationsFilter filter; - private AccountRelationshipChildren(Set accountDeviceInstances, CommunicationsManager commsManager, CommunicationsFilter filter) { + private AccountRelationshipChildren(Set accountDeviceInstances, CommunicationsManager commsManager, CommunicationsFilter filter) { this.accountDeviceInstances = accountDeviceInstances; this.commsManager = commsManager; this.filter = filter; } @Override - protected Node[] createNodes(BlackboardArtifact key) { - return new Node[]{new RelationShipNode(key)}; + protected boolean createKeys(List list) { + list.addAll(accountDeviceInstances); + return true; } @Override - protected void addNotify() { - try { - setKeys(commsManager.getCommunications(accountDeviceInstances, filter)); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error loading communications for accounts. ", ex); - } + protected Node createNodeForKey(BlackboardArtifact t) { + return new RelationShipNode(t); //To change body of generated methods, choose Tools | Templates. } + +// @Override +// protected Node[] createNodes(BlackboardArtifact key) { +// return new Node[]{new RelationShipNode(key)}; +// } +// @Override +// protected void addNotify() { +// setKeys(accountDeviceInstances); +// } } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceKey.java b/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceKey.java index b2df68c542..9078d7c0b6 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceKey.java +++ b/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceKey.java @@ -23,17 +23,21 @@ import org.sleuthkit.datamodel.CommunicationsFilter; /** * Key for AccountDeviceInstance node. - * + * * Encapsulates a AccountDeviceInstance, and CommunicationsFilter. */ -public class AccountDeviceInstanceKey { +class AccountDeviceInstanceKey { private final AccountDeviceInstance accountDeviceInstance; private final CommunicationsFilter filter; + private final long messageCount; - AccountDeviceInstanceKey(AccountDeviceInstance accountDeviceInstance, CommunicationsFilter filter) { + + + AccountDeviceInstanceKey(AccountDeviceInstance accountDeviceInstance, CommunicationsFilter filter, long msgCount) { this.accountDeviceInstance = accountDeviceInstance; this.filter = filter; + this.messageCount = msgCount; } AccountDeviceInstance getAccountDeviceInstance() { @@ -43,4 +47,8 @@ public class AccountDeviceInstanceKey { CommunicationsFilter getCommunicationsFilter() { return filter; } + + long getMessageCount() { + return messageCount; + } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/AccountsRootChildren.java b/Core/src/org/sleuthkit/autopsy/communications/AccountsRootChildren.java index d0a43b3c84..a6938008d6 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/AccountsRootChildren.java +++ b/Core/src/org/sleuthkit/autopsy/communications/AccountsRootChildren.java @@ -18,59 +18,59 @@ */ package org.sleuthkit.autopsy.communications; -import java.util.Collections; import java.util.List; -import java.util.logging.Level; import java.util.logging.Logger; import org.openide.nodes.AbstractNode; +import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.datamodel.NodeProperty; +import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.AccountDeviceInstance; import org.sleuthkit.datamodel.CommunicationsFilter; import org.sleuthkit.datamodel.CommunicationsManager; -import org.sleuthkit.datamodel.TskCoreException; -class AccountsRootChildren extends Children.Keys { +class AccountsRootChildren extends ChildFactory { private final List accountDeviceInstanceKeys; private final CommunicationsManager commsManager; AccountsRootChildren(List accountDeviceInstanceKeys, CommunicationsManager commsManager) { - super(true); + super(); this.accountDeviceInstanceKeys = accountDeviceInstanceKeys; this.commsManager = commsManager; } - - @Override - protected void removeNotify() { - super.removeNotify(); - setKeys(Collections.emptySet()); - } - - @Override - protected void addNotify() { - super.addNotify(); - setKeys(accountDeviceInstanceKeys); - } - +//these are the methods for Children.Keys +// @Override +// protected void removeNotify() { +// super.removeNotify(); +// setKeys(Collections.emptySet()); +// } +// +// @Override +// protected void addNotify() { +// super.addNotify(); +// setKeys(accountDeviceInstanceKeys); +// } + // @Override +// protected Node[] createNodes(AccountDeviceInstanceKey key) { +// return new Node[]{new AccountDeviceInstanceNode(key, commsManager)}; +// } + + //These are the methods for ChildFactory. I am going to keep them around but commented until we make a final descision. - // @Override - // protected boolean createKeys(List list) { - // list.addAll(accounts); - // return true; - // } - // - // @Override - // protected Node createNodeForKey(Account key) { - // return new AccountDeviceInstanceNode(key); - // } @Override - protected Node[] createNodes(AccountDeviceInstanceKey key) { - return new Node[]{new AccountDeviceInstanceNode(key, commsManager)}; + protected boolean createKeys(List list) { + list.addAll(accountDeviceInstanceKeys); + return true; + } + + @Override + protected Node createNodeForKey(AccountDeviceInstanceKey key) { + return new AccountDeviceInstanceNode(key, commsManager); } /** @@ -79,21 +79,21 @@ class AccountsRootChildren extends Children.Keys { static class AccountDeviceInstanceNode extends AbstractNode { private static final Logger LOGGER = Logger.getLogger(AccountDeviceInstanceNode.class.getName()); - private final AccountDeviceInstance accountDeviceInstance; + private final AccountDeviceInstanceKey accountDeviceInstanceKey; private final CommunicationsManager commsManager; - private final CommunicationsFilter filter; + private final Account account; private AccountDeviceInstanceNode(AccountDeviceInstanceKey accountDeviceInstanceKey, CommunicationsManager commsManager) { super(Children.LEAF, Lookups.fixed(accountDeviceInstanceKey, commsManager)); - this.accountDeviceInstance = accountDeviceInstanceKey.getAccountDeviceInstance(); + this.accountDeviceInstanceKey = accountDeviceInstanceKey; this.commsManager = commsManager; - this.filter = accountDeviceInstanceKey.getCommunicationsFilter(); - setName(accountDeviceInstance.getAccount().getAccountUniqueID()); - setIconBaseWithExtension("org/sleuthkit/autopsy/communications/images/" + Utils.getIconFileName(accountDeviceInstance.getAccount().getAccountType())); + this.account = accountDeviceInstanceKey.getAccountDeviceInstance().getAccount(); + setName(account.getAccountUniqueID()); + setIconBaseWithExtension("org/sleuthkit/autopsy/communications/images/" + Utils.getIconFileName(account.getAccountType())); } public AccountDeviceInstance getAccountDeviceInstance() { - return accountDeviceInstance; + return accountDeviceInstanceKey.getAccountDeviceInstance(); } public CommunicationsManager getCommsManager() { @@ -101,7 +101,7 @@ class AccountsRootChildren extends Children.Keys { } public CommunicationsFilter getFilter() { - return filter; + return accountDeviceInstanceKey.getCommunicationsFilter(); } @Override @@ -116,15 +116,13 @@ class AccountsRootChildren extends Children.Keys { properties = Sheet.createPropertiesSet(); s.put(properties); } - long msgCount = 0; - try { - msgCount = commsManager.getCommunicationsCount(accountDeviceInstance, filter ); - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "Failed to get message count for account", ex); //NON-NLS - } - properties.put(new NodeProperty<>("type", Bundle.AccountNode_accountType(), "type", accountDeviceInstance.getAccount().getAccountType().getDisplayName())); // NON-NLS - properties.put(new NodeProperty<>("count", Bundle.AccountNode_messageCount(), "count", msgCount)); // NON-NLS - properties.put(new NodeProperty<>("device", Bundle.AccountNode_device(), "device", accountDeviceInstance.getDeviceId())); // NON-NLS + + properties.put(new NodeProperty<>("type", Bundle.AccountNode_accountType(), "type", + account.getAccountType().getDisplayName())); // NON-NLS + properties.put(new NodeProperty<>("count", Bundle.AccountNode_messageCount(), "count", + accountDeviceInstanceKey.getMessageCount())); // NON-NLS + properties.put(new NodeProperty<>("device", Bundle.AccountNode_device(), "device", + accountDeviceInstanceKey.getAccountDeviceInstance().getDeviceId())); // NON-NLS return s; } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form index 023193d488..911ca2eca4 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form +++ b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form @@ -68,15 +68,15 @@ - - - + + + @@ -271,13 +271,13 @@ - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java index e7d17ecf71..93dc713468 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.communications; import java.awt.Cursor; import java.time.LocalDate; import java.time.ZoneId; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -32,10 +33,12 @@ import javax.swing.JCheckBox; import javax.swing.SwingWorker; import org.openide.explorer.ExplorerManager; import org.openide.nodes.AbstractNode; +import org.openide.nodes.Children; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.datamodel.Account; +import org.sleuthkit.datamodel.AccountDeviceInstance; import org.sleuthkit.datamodel.AccountTypeFilter; import org.sleuthkit.datamodel.CommunicationsFilter; import org.sleuthkit.datamodel.CommunicationsManager; @@ -53,7 +56,6 @@ final public class FiltersPanel extends javax.swing.JPanel { private static final Logger logger = Logger.getLogger(FiltersPanel.class.getName()); private static final long serialVersionUID = 1L; -// private static final DateFormat DATE_FORMAT = new SimpleDateFormat("MM/dd/yyyy"); private ExplorerManager em; @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @@ -67,8 +69,6 @@ final public class FiltersPanel extends javax.swing.JPanel { endDatePicker.setDateToToday(); startDatePicker.getSettings().setVetoPolicy( //no end date, or start is before end - - startDate -> endCheckBox.isSelected() == false || startDate.compareTo(endDatePicker.getDate()) <= 0 ); @@ -77,16 +77,15 @@ final public class FiltersPanel extends javax.swing.JPanel { endDate -> startCheckBox.isSelected() == false || endDate.compareTo(startDatePicker.getDate()) >= 0 ); - applyFiltersButton.addActionListener(actionEvent -> applyFilters()); + applyFiltersButton.addActionListener(actionEvent -> applyFilters()); } /** * Update the filter widgets, and apply them. */ void updateAndApplyFilters() { - updateAccountTypeFilter(); - updateDeviceFilter(); + updateFilters(); if (em != null) { applyFilters(); } @@ -94,6 +93,11 @@ final public class FiltersPanel extends javax.swing.JPanel { dateRangeLabel.setText("Date Range ( " + Utils.getUserPreferredZoneId().getId() + "):"); } + private void updateFilters() { + updateAccountTypeFilter(); + updateDeviceFilter(); + } + @Override public void addNotify() { super.addNotify(); @@ -312,10 +316,10 @@ final public class FiltersPanel extends javax.swing.JPanel { .addComponent(startCheckBox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(startDatePicker, javax.swing.GroupLayout.PREFERRED_SIZE, 162, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(jPanel4Layout.createSequentialGroup() + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel4Layout.createSequentialGroup() .addComponent(endCheckBox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(endDatePicker, javax.swing.GroupLayout.PREFERRED_SIZE, 161, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(endDatePicker, javax.swing.GroupLayout.PREFERRED_SIZE, 163, javax.swing.GroupLayout.PREFERRED_SIZE))) .addGap(0, 0, 0)) ); jPanel4Layout.setVerticalGroup( @@ -377,16 +381,18 @@ final public class FiltersPanel extends javax.swing.JPanel { try { final CommunicationsManager commsManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager(); + + getRootPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); new SwingWorker() { @Override protected AbstractNode doInBackground() throws Exception { - List accountDeviceInstanceKeys = - commsManager.getAccountDeviceInstancesWithCommunications(commsFilter) - .stream() - .map(adi -> new AccountDeviceInstanceKey(adi, commsFilter)) - .collect(Collectors.toList()); - return new AbstractNode(new AccountsRootChildren(accountDeviceInstanceKeys, commsManager)); + List accountDeviceInstanceKeys = new ArrayList<>(); + for (AccountDeviceInstance adi : commsManager.getAccountDeviceInstancesWithCommunications(commsFilter)) { + long communicationsCount = commsManager.getCommunicationsCount(adi, commsFilter); + accountDeviceInstanceKeys.add(new AccountDeviceInstanceKey(adi, commsFilter, communicationsCount)); + }; + return new AbstractNode(Children.create(new AccountsRootChildren(accountDeviceInstanceKeys, commsManager), true)); } @Override @@ -394,6 +400,7 @@ final public class FiltersPanel extends javax.swing.JPanel { super.done(); //To change body of generated methods, choose Tools | Templates. setCursor(Cursor.getDefaultCursor()); + getRootPane().setCursor(Cursor.getDefaultCursor()); try { em.setRootContext(get()); } catch (InterruptedException | ExecutionException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/communications/MessageBrowser.java b/Core/src/org/sleuthkit/autopsy/communications/MessageBrowser.java index c4c6e91fe8..73962e9214 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/MessageBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/communications/MessageBrowser.java @@ -18,17 +18,23 @@ */ package org.sleuthkit.autopsy.communications; +import java.awt.Cursor; import java.util.Collections; import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; +import javax.swing.SwingWorker; import org.openide.explorer.ExplorerManager; import org.openide.nodes.Node; import org.sleuthkit.autopsy.communications.AccountsRootChildren.AccountDeviceInstanceNode; import org.sleuthkit.autopsy.corecomponents.DataResultPanel; import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; import org.sleuthkit.autopsy.corecomponents.TableFilterNode; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AccountDeviceInstance; +import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.CommunicationsFilter; import org.sleuthkit.datamodel.CommunicationsManager; @@ -40,6 +46,8 @@ final class MessageBrowser extends javax.swing.JPanel implements ExplorerManager private static final long serialVersionUID = 1L; + private static final Logger logger = Logger.getLogger(MessageBrowser.class.getName()); + private final DataResultPanel messagesResultPanel; private final ExplorerManager explorerManager = new ExplorerManager(); private final DataResultViewerTable dataResultViewerTable = new DataResultViewerTable(explorerManager, "Messages"); @@ -84,8 +92,29 @@ final class MessageBrowser extends javax.swing.JPanel implements ExplorerManager .collect(Collectors.toSet()); messagesResultPanel.setPath(selectedNodes.length + " accounts"); } - messagesResultPanel.setNode(new TableFilterNode( - new AccountDetailsNode(collect, filter, commsManager), true)); + messagesResultPanel.setNumMatches(0); + messagesResultPanel.setNode(null); + getRootPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + new SwingWorker, Void>() { + @Override + protected Set doInBackground() throws Exception { + return commsManager.getCommunications(collect, filter); + } + + @Override + protected void done() { + super.done(); //To change body of generated methods, choose Tools | Templates. + try { + messagesResultPanel.setNode(new TableFilterNode( + new AccountDetailsNode(get(), filter, commsManager), true)); + } catch (InterruptedException | ExecutionException ex) { + logger.log(Level.SEVERE, "Error getting relationships", ex); + } + getRootPane().setCursor(Cursor.getDefaultCursor()); + + } + }.execute(); + } } });