From 71f1c2654b7c00eb0d1f5e25a1e16748bd2eb470 Mon Sep 17 00:00:00 2001 From: apriestman Date: Tue, 30 Nov 2021 13:59:58 -0500 Subject: [PATCH 01/20] testing --- .../directorytree/DataResultFilterNode.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index d8b2436179..955881230b 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -33,6 +33,7 @@ import org.openide.nodes.FilterNode; import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.corecomponents.SelectionResponder; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; @@ -128,6 +129,13 @@ public class DataResultFilterNode extends FilterNode { @Override public Action getPreferredAction() { final Node original = this.getOriginal(); + + if (original instanceof SelectionResponder + && original instanceof AbstractNode) { + AbstractNode abstractNode = (AbstractNode)original; + return openChild(abstractNode); + } + // Once had a org.openide.nodes.ChildFactory$WaitFilterNode passed in if ((original instanceof DisplayableItemNode) == false) { return null; @@ -136,6 +144,56 @@ public class DataResultFilterNode extends FilterNode { final DisplayableItemNode originalNode = (DisplayableItemNode) this.getOriginal(); return originalNode.accept(getPreferredActionsDIV); } + + /** + * Tell the originating ExplorerManager to display the given + * dataModelNode. + * + * @param dataModelNode Original (non-filtered) dataModelNode to open + * + * @return + */ + private AbstractAction openChild(final AbstractNode dataModelNode) { + // get the current selection from the directory tree explorer manager, + // which is a DirectoryTreeFilterNode. One of that node's children + // is a DirectoryTreeFilterNode that wraps the dataModelNode. We need + // to set that wrapped node as the selection and root context of the + // directory tree explorer manager (sourceEm) + if (sourceEm == null || sourceEm.getSelectedNodes().length == 0) { + return null; + } + final Node currentSelectionInDirectoryTree = sourceEm.getSelectedNodes()[0]; + + return new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (currentSelectionInDirectoryTree != null) { + // Find the filter version of the passed in dataModelNode. + final org.openide.nodes.Children children = currentSelectionInDirectoryTree.getChildren(); + // This call could break if the DirectoryTree is re-implemented with lazy ChildFactory objects. + Node newSelection = children.findChild(dataModelNode.getName()); + + /* + * We got null here when we were viewing a ZIP file in + * the Views -> Archives area and double clicking on it + * got to this code. It tried to find the child in the + * tree and didn't find it. An exception was then thrown + * from setting the selected node to be null. + */ + if (newSelection != null) { + try { + sourceEm.setExploredContextAndSelection(newSelection, new Node[]{newSelection}); + } catch (PropertyVetoException ex) { + Logger logger = Logger.getLogger(DataResultFilterNode.class.getName()); + logger.log(Level.WARNING, "Error: can't open the selected directory.", ex); //NON-NLS + } + } + } + } + }; + } + + @Override public Node.PropertySet[] getPropertySets() { From 9d031937d1ca9e14acd9748ad170438dff6eb8e6 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 30 Nov 2021 14:59:47 -0500 Subject: [PATCH 02/20] Fixed label --- .../sleuthkit/autopsy/corecomponents/DataResultPanel.form | 8 ++++---- .../sleuthkit/autopsy/corecomponents/DataResultPanel.java | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.form index 450b21181b..c468a485b6 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.form @@ -41,7 +41,7 @@ - + @@ -53,7 +53,7 @@ - + @@ -69,7 +69,7 @@ - + @@ -252,7 +252,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java index 649f304356..c6a1971db5 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java @@ -874,7 +874,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; - gridBagConstraints.gridwidth = 7; + gridBagConstraints.gridwidth = 8; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5); @@ -882,7 +882,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C org.openide.awt.Mnemonics.setLocalizedText(numberOfChildNodesLabel, org.openide.util.NbBundle.getMessage(DataResultPanel.class, "DataResultPanel.numberOfChildNodesLabel.text")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 8; + gridBagConstraints.gridx = 9; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5); @@ -890,7 +890,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C org.openide.awt.Mnemonics.setLocalizedText(matchLabel, org.openide.util.NbBundle.getMessage(DataResultPanel.class, "DataResultPanel.matchLabel.text")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 9; + gridBagConstraints.gridx = 10; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 0); @@ -1003,7 +1003,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; - gridBagConstraints.gridwidth = 10; + gridBagConstraints.gridwidth = 11; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; From 15fd8a1e337bca33744379d786ebee81cda7345e Mon Sep 17 00:00:00 2001 From: apriestman Date: Thu, 2 Dec 2021 09:57:53 -0500 Subject: [PATCH 03/20] Basic test working --- .../autopsy/mainui/nodes/BaseNode.java | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/BaseNode.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/BaseNode.java index bb737e19ea..7666e3aae0 100755 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/BaseNode.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/BaseNode.java @@ -18,15 +18,24 @@ */ package org.sleuthkit.autopsy.mainui.nodes; +import java.awt.event.ActionEvent; +import java.beans.PropertyVetoException; +import java.util.logging.Level; +import javax.swing.AbstractAction; import javax.swing.Action; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; import org.openide.nodes.Sheet; import org.openide.util.Lookup; +import org.openide.explorer.ExplorerManager; +import org.openide.nodes.Node; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.directorytree.DataResultFilterNode; import org.sleuthkit.autopsy.mainui.datamodel.BaseRowDTO; import org.sleuthkit.autopsy.mainui.datamodel.SearchResultsDTO; import org.sleuthkit.autopsy.mainui.nodes.actions.ActionContext; import org.sleuthkit.autopsy.mainui.nodes.actions.ActionsFactory; +import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; /** * A a simple starting point for nodes. @@ -69,4 +78,52 @@ abstract class BaseNode extend public Action[] getActions(boolean context) { return ActionsFactory.getActions(this); } + + @Override + public Action getPreferredAction() { + System.out.println("### getPreferredAction for node of type: " + this.getClass().getSimpleName()); + DirectoryTreeTopComponent treeViewTopComponent = DirectoryTreeTopComponent.findInstance(); + ExplorerManager treeViewExplorerMgr = treeViewTopComponent.getExplorerManager(); + + // For now, skip .. case + if (treeViewExplorerMgr == null || treeViewExplorerMgr.getSelectedNodes().length == 0) { + return null; + } + final Node currentSelectionInDirectoryTree = treeViewExplorerMgr.getSelectedNodes()[0]; + final String currentNodeName = this.getDisplayName(); + + return new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (currentSelectionInDirectoryTree != null) { + // Find the filter version of the passed in dataModelNode. + final org.openide.nodes.Children children = currentSelectionInDirectoryTree.getChildren(); + // This call could break if the DirectoryTree is re-implemented with lazy ChildFactory objects. + System.out.println("### Looking for child with name " + currentNodeName); + Node newSelection = children.findChild(currentNodeName); + if (newSelection == null) { + System.out.println(" Did not find it"); + } else { + System.out.println(" Found it!"); + } + + /* + * We got null here when we were viewing a ZIP file in + * the Views -> Archives area and double clicking on it + * got to this code. It tried to find the child in the + * tree and didn't find it. An exception was then thrown + * from setting the selected node to be null. + */ + if (newSelection != null) { + try { + treeViewExplorerMgr.setExploredContextAndSelection(newSelection, new Node[]{newSelection}); + } catch (PropertyVetoException ex) { + Logger logger = Logger.getLogger(DataResultFilterNode.class.getName()); + logger.log(Level.WARNING, "Error: can't open the selected directory.", ex); //NON-NLS + } + } + } + } + }; + } } From 956534391162d472813d1accb0914fe6b67ea1ce Mon Sep 17 00:00:00 2001 From: apriestman Date: Fri, 3 Dec 2021 09:51:24 -0500 Subject: [PATCH 04/20] Refactor double-click handling. Add it to the Views nodes. --- .../directorytree/DataResultFilterNode.java | 98 +++---------------- .../DirectoryTreeTopComponent.java | 57 +++++++++++ .../autopsy/mainui/nodes/BaseNode.java | 53 +--------- .../mainui/nodes/ViewsTypeFactory.java | 23 +++++ 4 files changed, 94 insertions(+), 137 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index 955881230b..2a6ef46699 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -145,55 +145,17 @@ public class DataResultFilterNode extends FilterNode { return originalNode.accept(getPreferredActionsDIV); } - /** - * Tell the originating ExplorerManager to display the given - * dataModelNode. - * - * @param dataModelNode Original (non-filtered) dataModelNode to open - * - * @return - */ - private AbstractAction openChild(final AbstractNode dataModelNode) { - // get the current selection from the directory tree explorer manager, - // which is a DirectoryTreeFilterNode. One of that node's children - // is a DirectoryTreeFilterNode that wraps the dataModelNode. We need - // to set that wrapped node as the selection and root context of the - // directory tree explorer manager (sourceEm) - if (sourceEm == null || sourceEm.getSelectedNodes().length == 0) { - return null; - } - final Node currentSelectionInDirectoryTree = sourceEm.getSelectedNodes()[0]; - - return new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - if (currentSelectionInDirectoryTree != null) { - // Find the filter version of the passed in dataModelNode. - final org.openide.nodes.Children children = currentSelectionInDirectoryTree.getChildren(); - // This call could break if the DirectoryTree is re-implemented with lazy ChildFactory objects. - Node newSelection = children.findChild(dataModelNode.getName()); - - /* - * We got null here when we were viewing a ZIP file in - * the Views -> Archives area and double clicking on it - * got to this code. It tried to find the child in the - * tree and didn't find it. An exception was then thrown - * from setting the selected node to be null. - */ - if (newSelection != null) { - try { - sourceEm.setExploredContextAndSelection(newSelection, new Node[]{newSelection}); - } catch (PropertyVetoException ex) { - Logger logger = Logger.getLogger(DataResultFilterNode.class.getName()); - logger.log(Level.WARNING, "Error: can't open the selected directory.", ex); //NON-NLS - } - } - } - } - }; - } - - + /** + * Tell the originating ExplorerManager to display the given + * dataModelNode. + * + * @param dataModelNode Original (non-filtered) dataModelNode to open + * + * @return + */ + private AbstractAction openChild(final AbstractNode dataModelNode) { + return DirectoryTreeTopComponent.getOpenChildAction(dataModelNode.getName(), sourceEm); + } @Override public Node.PropertySet[] getPropertySets() { @@ -425,43 +387,7 @@ public class DataResultFilterNode extends FilterNode { * @return */ private AbstractAction openChild(final AbstractNode dataModelNode) { - // get the current selection from the directory tree explorer manager, - // which is a DirectoryTreeFilterNode. One of that node's children - // is a DirectoryTreeFilterNode that wraps the dataModelNode. We need - // to set that wrapped node as the selection and root context of the - // directory tree explorer manager (sourceEm) - if (sourceEm == null || sourceEm.getSelectedNodes().length == 0) { - return null; - } - final Node currentSelectionInDirectoryTree = sourceEm.getSelectedNodes()[0]; - - return new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - if (currentSelectionInDirectoryTree != null) { - // Find the filter version of the passed in dataModelNode. - final org.openide.nodes.Children children = currentSelectionInDirectoryTree.getChildren(); - // This call could break if the DirectoryTree is re-implemented with lazy ChildFactory objects. - Node newSelection = children.findChild(dataModelNode.getName()); - - /* - * We got null here when we were viewing a ZIP file in - * the Views -> Archives area and double clicking on it - * got to this code. It tried to find the child in the - * tree and didn't find it. An exception was then thrown - * from setting the selected node to be null. - */ - if (newSelection != null) { - try { - sourceEm.setExploredContextAndSelection(newSelection, new Node[]{newSelection}); - } catch (PropertyVetoException ex) { - Logger logger = Logger.getLogger(DataResultFilterNode.class.getName()); - logger.log(Level.WARNING, "Error: can't open the selected directory.", ex); //NON-NLS - } - } - } - } - }; + return DirectoryTreeTopComponent.getOpenChildAction(dataModelNode.getName(), sourceEm); } /** diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index bec78407d8..8f6c9c6bea 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.directorytree; import java.awt.Cursor; import java.awt.EventQueue; +import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyVetoException; @@ -41,6 +42,7 @@ import java.util.prefs.PreferenceChangeEvent; import java.util.prefs.PreferenceChangeListener; import java.util.stream.Collectors; import java.util.stream.Stream; +import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; @@ -1677,5 +1679,60 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat public void addOnFinishedListener(PropertyChangeListener l) { DirectoryTreeTopComponent.this.addPropertyChangeListener(l); } + + public static AbstractAction getOpenChildAction(String nodeName) { + DirectoryTreeTopComponent treeViewTopComponent = DirectoryTreeTopComponent.findInstance(); + ExplorerManager treeViewExplorerMgr = treeViewTopComponent.getExplorerManager(); + return getOpenChildAction(nodeName, treeViewExplorerMgr); + } + + public static AbstractAction getOpenChildAction(String nodeName, ExplorerManager explorerManager) { + // get the current selection from the directory tree explorer manager, + // which is a DirectoryTreeFilterNode. One of that node's children + // is a DirectoryTreeFilterNode that wraps the dataModelNode. We need + // to set that wrapped node as the selection and root context of the + // directory tree explorer manager (sourceEm) + if (explorerManager != null) { + System.out.println("### Selected node count: " + explorerManager.getSelectedNodes().length); + } + if (explorerManager == null || explorerManager.getSelectedNodes().length == 0) { + System.out.println("### Returning early..."); + return null; + } + final Node currentSelectionInDirectoryTree = explorerManager.getSelectedNodes()[0]; + System.out.println("### Current selection name: " + currentSelectionInDirectoryTree.getName()); + + return new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (currentSelectionInDirectoryTree != null) { + // Find the filter version of the passed in dataModelNode. + final org.openide.nodes.Children children = currentSelectionInDirectoryTree.getChildren(); + // This call could break if the DirectoryTree is re-implemented with lazy ChildFactory objects. + System.out.println("### Looking for child with name: " + nodeName); + Node newSelection = children.findChild(nodeName); + + /* + * We got null here when we were viewing a ZIP file in + * the Views -> Archives area and double clicking on it + * got to this code. It tried to find the child in the + * tree and didn't find it. An exception was then thrown + * from setting the selected node to be null. + */ + if (newSelection != null) { + System.out.println("### Found it!"); + try { + explorerManager.setExploredContextAndSelection(newSelection, new Node[]{newSelection}); + } catch (PropertyVetoException ex) { + Logger logger = Logger.getLogger(DataResultFilterNode.class.getName()); + logger.log(Level.WARNING, "Error: can't open the selected directory.", ex); //NON-NLS + } + } else { + System.out.println("### Did not find it..."); + } + } + } + }; + } } diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/BaseNode.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/BaseNode.java index 7666e3aae0..3723057982 100755 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/BaseNode.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/BaseNode.java @@ -18,19 +18,11 @@ */ package org.sleuthkit.autopsy.mainui.nodes; -import java.awt.event.ActionEvent; -import java.beans.PropertyVetoException; -import java.util.logging.Level; -import javax.swing.AbstractAction; import javax.swing.Action; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; import org.openide.nodes.Sheet; import org.openide.util.Lookup; -import org.openide.explorer.ExplorerManager; -import org.openide.nodes.Node; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.directorytree.DataResultFilterNode; import org.sleuthkit.autopsy.mainui.datamodel.BaseRowDTO; import org.sleuthkit.autopsy.mainui.datamodel.SearchResultsDTO; import org.sleuthkit.autopsy.mainui.nodes.actions.ActionContext; @@ -82,48 +74,7 @@ abstract class BaseNode extend @Override public Action getPreferredAction() { System.out.println("### getPreferredAction for node of type: " + this.getClass().getSimpleName()); - DirectoryTreeTopComponent treeViewTopComponent = DirectoryTreeTopComponent.findInstance(); - ExplorerManager treeViewExplorerMgr = treeViewTopComponent.getExplorerManager(); - - // For now, skip .. case - if (treeViewExplorerMgr == null || treeViewExplorerMgr.getSelectedNodes().length == 0) { - return null; - } - final Node currentSelectionInDirectoryTree = treeViewExplorerMgr.getSelectedNodes()[0]; - final String currentNodeName = this.getDisplayName(); - - return new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - if (currentSelectionInDirectoryTree != null) { - // Find the filter version of the passed in dataModelNode. - final org.openide.nodes.Children children = currentSelectionInDirectoryTree.getChildren(); - // This call could break if the DirectoryTree is re-implemented with lazy ChildFactory objects. - System.out.println("### Looking for child with name " + currentNodeName); - Node newSelection = children.findChild(currentNodeName); - if (newSelection == null) { - System.out.println(" Did not find it"); - } else { - System.out.println(" Found it!"); - } - - /* - * We got null here when we were viewing a ZIP file in - * the Views -> Archives area and double clicking on it - * got to this code. It tried to find the child in the - * tree and didn't find it. An exception was then thrown - * from setting the selected node to be null. - */ - if (newSelection != null) { - try { - treeViewExplorerMgr.setExploredContextAndSelection(newSelection, new Node[]{newSelection}); - } catch (PropertyVetoException ex) { - Logger logger = Logger.getLogger(DataResultFilterNode.class.getName()); - logger.log(Level.WARNING, "Error: can't open the selected directory.", ex); //NON-NLS - } - } - } - } - }; + // TODO - figure out .. + return DirectoryTreeTopComponent.getOpenChildAction(getName()); } } diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java index c4ddbf366e..d17ee05a61 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java @@ -24,8 +24,10 @@ import java.util.Comparator; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import java.util.stream.Stream; +import javax.swing.Action; import org.openide.nodes.Children; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; +import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.autopsy.mainui.datamodel.FileExtDocumentFilter; import org.sleuthkit.autopsy.mainui.datamodel.FileExtExecutableFilter; @@ -103,6 +105,11 @@ public class ViewsTypeFactory { dataResultPanel.displayFileSizes(this.getItemData().getSearchParams()); } + @Override + public Action getPreferredAction() { + System.out.println("### getPreferredAction for node of type: " + this.getClass().getSimpleName()); + return DirectoryTreeTopComponent.getOpenChildAction(getName()); + } } } @@ -158,6 +165,12 @@ public class ViewsTypeFactory { Children.create(new FileMimeSuffixFactory(itemData.getSearchParams().getDataSourceId(), itemData.getSearchParams().getMimeType()), true), getDefaultLookup(itemData)); } + + @Override + public Action getPreferredAction() { + System.out.println("### getPreferredAction for node of type: " + this.getClass().getSimpleName()); + return DirectoryTreeTopComponent.getOpenChildAction(getName()); + } } } @@ -225,6 +238,11 @@ public class ViewsTypeFactory { dataResultPanel.displayFileMimes(this.getItemData().getSearchParams()); } + @Override + public Action getPreferredAction() { + System.out.println("### getPreferredAction for node of type: " + this.getClass().getSimpleName()); + return DirectoryTreeTopComponent.getOpenChildAction(getName()); + } } } @@ -322,6 +340,11 @@ public class ViewsTypeFactory { } } + @Override + public Action getPreferredAction() { + System.out.println("### getPreferredAction for node of type: " + this.getClass().getSimpleName()); + return DirectoryTreeTopComponent.getOpenChildAction(getName()); + } } } From 81024e4672e6fe50c0b77c8113be3c75bf89e010 Mon Sep 17 00:00:00 2001 From: apriestman Date: Fri, 3 Dec 2021 11:37:33 -0500 Subject: [PATCH 05/20] Add openParent. Cleanup. --- .../directorytree/DataResultFilterNode.java | 20 +------------- .../DirectoryTreeTopComponent.java | 27 +++++++++++++++++++ .../autopsy/mainui/nodes/BaseNode.java | 2 -- .../autopsy/mainui/nodes/DirectoryNode.java | 11 ++++++++ .../autopsy/mainui/nodes/FileNode.java | 6 +++++ .../mainui/nodes/ViewsTypeFactory.java | 4 --- 6 files changed, 45 insertions(+), 25 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index 2a6ef46699..b27f48a256 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -399,25 +399,7 @@ public class DataResultFilterNode extends FilterNode { * @return */ private AbstractAction openParent(AbstractNode node) { - if (sourceEm == null) { - return null; - } - // @@@ Why do we ignore node? - Node[] selectedFilterNodes = sourceEm.getSelectedNodes(); - Node selectedFilterNode = selectedFilterNodes[0]; - final Node parentNode = selectedFilterNode.getParentNode(); - - return new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - try { - sourceEm.setSelectedNodes(new Node[]{parentNode}); - } catch (PropertyVetoException ex) { - Logger logger = Logger.getLogger(DataResultFilterNode.class.getName()); - logger.log(Level.WARNING, "Error: can't open the parent directory.", ex); //NON-NLS - } - } - }; + return DirectoryTreeTopComponent.getOpenParentAction(); } } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 8f6c9c6bea..d1ed1083f1 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -1734,5 +1734,32 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat } }; } + + public static AbstractAction getOpenParentAction() { + DirectoryTreeTopComponent treeViewTopComponent = DirectoryTreeTopComponent.findInstance(); + ExplorerManager treeViewExplorerMgr = treeViewTopComponent.getExplorerManager(); + return getOpenParentAction(treeViewExplorerMgr); + } + public static AbstractAction getOpenParentAction(ExplorerManager explorerManager) { + if (explorerManager == null) { + return null; + } + // @@@ Why do we ignore node? + Node[] selectedFilterNodes = explorerManager.getSelectedNodes(); + Node selectedFilterNode = selectedFilterNodes[0]; + final Node parentNode = selectedFilterNode.getParentNode(); + + return new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + try { + explorerManager.setSelectedNodes(new Node[]{parentNode}); + } catch (PropertyVetoException ex) { + Logger logger = Logger.getLogger(DataResultFilterNode.class.getName()); + logger.log(Level.WARNING, "Error: can't open the parent directory.", ex); //NON-NLS + } + } + }; + } } diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/BaseNode.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/BaseNode.java index 3723057982..3f2b295556 100755 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/BaseNode.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/BaseNode.java @@ -73,8 +73,6 @@ abstract class BaseNode extend @Override public Action getPreferredAction() { - System.out.println("### getPreferredAction for node of type: " + this.getClass().getSimpleName()); - // TODO - figure out .. return DirectoryTreeTopComponent.getOpenChildAction(getName()); } } diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/DirectoryNode.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/DirectoryNode.java index 8b101d9244..2da927bfb3 100755 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/DirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/DirectoryNode.java @@ -19,7 +19,9 @@ package org.sleuthkit.autopsy.mainui.nodes; import java.util.Optional; +import javax.swing.Action; import org.openide.nodes.Children; +import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; import org.sleuthkit.autopsy.mainui.datamodel.ContentRowDTO.DirectoryRowDTO; import org.sleuthkit.autopsy.mainui.datamodel.SearchResultsDTO; import org.sleuthkit.datamodel.AbstractFile; @@ -83,4 +85,13 @@ public class DirectoryNode extends BaseNode { public boolean supportsContentTagAction() { return true; } + + @Override + public Action getPreferredAction() { + if (getDisplayName().equals(org.sleuthkit.autopsy.datamodel.DirectoryNode.DOTDOTDIR) + || getDisplayName().equals("..")) { + return DirectoryTreeTopComponent.getOpenParentAction(); + } + return DirectoryTreeTopComponent.getOpenChildAction(getName()); + } } diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/FileNode.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/FileNode.java index 790b75d485..b53d87997c 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/FileNode.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/FileNode.java @@ -26,6 +26,7 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.datamodel.FileTypeExtensions; +import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; import org.sleuthkit.autopsy.mainui.datamodel.SearchResultsDTO; import org.sleuthkit.autopsy.mainui.datamodel.FileRowDTO; import org.sleuthkit.autopsy.mainui.datamodel.ColumnKey; @@ -150,6 +151,11 @@ public class FileNode extends AbstractNode implements ActionContext { protected Sheet createSheet() { return ContentNodeUtil.setSheet(super.createSheet(), this.columns, this.fileData.getCellValues()); } + + @Override + public Action getPreferredAction() { + return DirectoryTreeTopComponent.getOpenChildAction(getName()); + } /** * A node for representing a LayoutFile. diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java index d17ee05a61..4e5d9d2011 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java @@ -107,7 +107,6 @@ public class ViewsTypeFactory { @Override public Action getPreferredAction() { - System.out.println("### getPreferredAction for node of type: " + this.getClass().getSimpleName()); return DirectoryTreeTopComponent.getOpenChildAction(getName()); } } @@ -168,7 +167,6 @@ public class ViewsTypeFactory { @Override public Action getPreferredAction() { - System.out.println("### getPreferredAction for node of type: " + this.getClass().getSimpleName()); return DirectoryTreeTopComponent.getOpenChildAction(getName()); } } @@ -240,7 +238,6 @@ public class ViewsTypeFactory { @Override public Action getPreferredAction() { - System.out.println("### getPreferredAction for node of type: " + this.getClass().getSimpleName()); return DirectoryTreeTopComponent.getOpenChildAction(getName()); } } @@ -342,7 +339,6 @@ public class ViewsTypeFactory { @Override public Action getPreferredAction() { - System.out.println("### getPreferredAction for node of type: " + this.getClass().getSimpleName()); return DirectoryTreeTopComponent.getOpenChildAction(getName()); } } From 7b4aaf1d62575a2b22f346dff2bbdd432565e8ec Mon Sep 17 00:00:00 2001 From: apriestman Date: Fri, 3 Dec 2021 12:29:36 -0500 Subject: [PATCH 06/20] Cleanup --- .../directorytree/DataResultFilterNode.java | 14 +------------- .../directorytree/DirectoryTreeTopComponent.java | 14 ++------------ 2 files changed, 3 insertions(+), 25 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index b27f48a256..6acc560258 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -133,7 +133,7 @@ public class DataResultFilterNode extends FilterNode { if (original instanceof SelectionResponder && original instanceof AbstractNode) { AbstractNode abstractNode = (AbstractNode)original; - return openChild(abstractNode); + return DirectoryTreeTopComponent.getOpenChildAction(abstractNode.getName(), sourceEm); } // Once had a org.openide.nodes.ChildFactory$WaitFilterNode passed in @@ -144,18 +144,6 @@ public class DataResultFilterNode extends FilterNode { final DisplayableItemNode originalNode = (DisplayableItemNode) this.getOriginal(); return originalNode.accept(getPreferredActionsDIV); } - - /** - * Tell the originating ExplorerManager to display the given - * dataModelNode. - * - * @param dataModelNode Original (non-filtered) dataModelNode to open - * - * @return - */ - private AbstractAction openChild(final AbstractNode dataModelNode) { - return DirectoryTreeTopComponent.getOpenChildAction(dataModelNode.getName(), sourceEm); - } @Override public Node.PropertySet[] getPropertySets() { diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index d1ed1083f1..413858b36b 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -1686,21 +1686,16 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat return getOpenChildAction(nodeName, treeViewExplorerMgr); } - public static AbstractAction getOpenChildAction(String nodeName, ExplorerManager explorerManager) { + static AbstractAction getOpenChildAction(String nodeName, ExplorerManager explorerManager) { // get the current selection from the directory tree explorer manager, // which is a DirectoryTreeFilterNode. One of that node's children // is a DirectoryTreeFilterNode that wraps the dataModelNode. We need // to set that wrapped node as the selection and root context of the // directory tree explorer manager (sourceEm) - if (explorerManager != null) { - System.out.println("### Selected node count: " + explorerManager.getSelectedNodes().length); - } if (explorerManager == null || explorerManager.getSelectedNodes().length == 0) { - System.out.println("### Returning early..."); return null; } final Node currentSelectionInDirectoryTree = explorerManager.getSelectedNodes()[0]; - System.out.println("### Current selection name: " + currentSelectionInDirectoryTree.getName()); return new AbstractAction() { @Override @@ -1709,7 +1704,6 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat // Find the filter version of the passed in dataModelNode. final org.openide.nodes.Children children = currentSelectionInDirectoryTree.getChildren(); // This call could break if the DirectoryTree is re-implemented with lazy ChildFactory objects. - System.out.println("### Looking for child with name: " + nodeName); Node newSelection = children.findChild(nodeName); /* @@ -1720,15 +1714,12 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat * from setting the selected node to be null. */ if (newSelection != null) { - System.out.println("### Found it!"); try { explorerManager.setExploredContextAndSelection(newSelection, new Node[]{newSelection}); } catch (PropertyVetoException ex) { Logger logger = Logger.getLogger(DataResultFilterNode.class.getName()); logger.log(Level.WARNING, "Error: can't open the selected directory.", ex); //NON-NLS } - } else { - System.out.println("### Did not find it..."); } } } @@ -1741,11 +1732,10 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat return getOpenParentAction(treeViewExplorerMgr); } - public static AbstractAction getOpenParentAction(ExplorerManager explorerManager) { + static AbstractAction getOpenParentAction(ExplorerManager explorerManager) { if (explorerManager == null) { return null; } - // @@@ Why do we ignore node? Node[] selectedFilterNodes = explorerManager.getSelectedNodes(); Node selectedFilterNode = selectedFilterNodes[0]; final Node parentNode = selectedFilterNode.getParentNode(); From e7844b7f914345bb76cadef925e2457ff3fd4fc1 Mon Sep 17 00:00:00 2001 From: apriestman Date: Mon, 6 Dec 2021 10:45:18 -0500 Subject: [PATCH 07/20] Handle case where getOpenChildAction is called from the directory tree. --- .../DirectoryTreeTopComponent.java | 39 ++++++++++++++++++- .../autopsy/mainui/nodes/TreeNode.java | 15 ++++++- .../mainui/nodes/ViewsTypeFactory.java | 20 ---------- 3 files changed, 52 insertions(+), 22 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 413858b36b..c9f1d65c5c 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -1680,22 +1680,47 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat DirectoryTreeTopComponent.this.addPropertyChangeListener(l); } + /** + * Gets the open child action for the given node name. Will return + * null if the nodeName matches the currently selected tree node. + * + * @param nodeName The child node to open. + * + * @return The openChild action or null if not valid. + */ public static AbstractAction getOpenChildAction(String nodeName) { DirectoryTreeTopComponent treeViewTopComponent = DirectoryTreeTopComponent.findInstance(); ExplorerManager treeViewExplorerMgr = treeViewTopComponent.getExplorerManager(); return getOpenChildAction(nodeName, treeViewExplorerMgr); } + /** + * Gets the open child action for the given node name. Will return + * null if the nodeName matches the currently selected tree node. + * + * @param nodeName The child node to open. + * @param explorerManager The explorer manager for the tree. + * + * @return The openChild action or null if not valid. + */ static AbstractAction getOpenChildAction(String nodeName, ExplorerManager explorerManager) { // get the current selection from the directory tree explorer manager, // which is a DirectoryTreeFilterNode. One of that node's children // is a DirectoryTreeFilterNode that wraps the dataModelNode. We need // to set that wrapped node as the selection and root context of the // directory tree explorer manager (sourceEm) - if (explorerManager == null || explorerManager.getSelectedNodes().length == 0) { + if (explorerManager == null || explorerManager.getSelectedNodes().length == 0 || nodeName == null) { return null; } final Node currentSelectionInDirectoryTree = explorerManager.getSelectedNodes()[0]; + + // We have several node types that are used in both the tree and the result viewer. + // For tree nodes, we don't want to do the open child action. + // When double-clicking on a tree node, the nodeName to open will be the same + // as the currently seleted node, so don't return an action if this is the case. + if (nodeName.equals(currentSelectionInDirectoryTree.getName())) { + return null; + } return new AbstractAction() { @Override @@ -1726,12 +1751,24 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat }; } + /** + * Gets the open parent action for the currently selected node. + * + * @return The openChild action. + */ public static AbstractAction getOpenParentAction() { DirectoryTreeTopComponent treeViewTopComponent = DirectoryTreeTopComponent.findInstance(); ExplorerManager treeViewExplorerMgr = treeViewTopComponent.getExplorerManager(); return getOpenParentAction(treeViewExplorerMgr); } + /** + * Gets the open parent action for the currently selected node. + * + * @param explorerManager The explorer manager for the tree. + * + * @return The open parent action or null if given an invalid ExplorerManager. + */ static AbstractAction getOpenParentAction(ExplorerManager explorerManager) { if (explorerManager == null) { return null; diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/TreeNode.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/TreeNode.java index 7fd7cf4593..11061139f7 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/TreeNode.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/TreeNode.java @@ -22,12 +22,14 @@ import org.sleuthkit.autopsy.corecomponents.SelectionResponder; import java.text.MessageFormat; import java.util.Objects; import java.util.logging.Level; +import javax.swing.Action; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; import org.openide.util.Lookup; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; import org.sleuthkit.autopsy.mainui.datamodel.TreeResultsDTO.TreeItemDTO; /** @@ -138,5 +140,16 @@ public abstract class TreeNode extends AbstractNode implements SelectionRespo dataResultPanel.setNode(this); } - + @Override + public Action getPreferredAction() { + // TreeNodes are used for both the result viewer and the tree viewer. For the result viewer, + // we want to open the child of the double-clicked node. For the tree viewer, we want the default + // action (explanding/closing the node). If getOpenChildAction() returns null, we likely + // have a tree node and want to call the default preferred action. + Action openChildAction = DirectoryTreeTopComponent.getOpenChildAction(getName()); + if (openChildAction == null) { + return super.getPreferredAction(); + } + return openChildAction; + } } diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java index 4e5d9d2011..1723c250c8 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java @@ -104,11 +104,6 @@ public class ViewsTypeFactory { public void respondSelection(DataResultTopComponent dataResultPanel) { dataResultPanel.displayFileSizes(this.getItemData().getSearchParams()); } - - @Override - public Action getPreferredAction() { - return DirectoryTreeTopComponent.getOpenChildAction(getName()); - } } } @@ -164,11 +159,6 @@ public class ViewsTypeFactory { Children.create(new FileMimeSuffixFactory(itemData.getSearchParams().getDataSourceId(), itemData.getSearchParams().getMimeType()), true), getDefaultLookup(itemData)); } - - @Override - public Action getPreferredAction() { - return DirectoryTreeTopComponent.getOpenChildAction(getName()); - } } } @@ -235,11 +225,6 @@ public class ViewsTypeFactory { public void respondSelection(DataResultTopComponent dataResultPanel) { dataResultPanel.displayFileMimes(this.getItemData().getSearchParams()); } - - @Override - public Action getPreferredAction() { - return DirectoryTreeTopComponent.getOpenChildAction(getName()); - } } } @@ -336,11 +321,6 @@ public class ViewsTypeFactory { super.respondSelection(dataResultPanel); } } - - @Override - public Action getPreferredAction() { - return DirectoryTreeTopComponent.getOpenChildAction(getName()); - } } } From d2c8db18130f6c43efdf10846374be3d3f1a7886 Mon Sep 17 00:00:00 2001 From: apriestman Date: Mon, 6 Dec 2021 10:51:27 -0500 Subject: [PATCH 08/20] Cleanup --- .../autopsy/corecomponents/Bundle.properties-MERGED | 6 +++--- .../sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED index cde18d3900..468e6d9430 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED @@ -72,9 +72,9 @@ DataContentViewerHex.totalPageLabel.text_1=100 DataContentViewerHex.pageLabel2.text=Page # Product Information panel -LBL_Description=
\n Product Version: {0} ({9})
Sleuth Kit Version: {7}
Netbeans RCP Build: {8}
Java: {1}; {2}
System: {3}; {4}; {5}
Userdir: {6}
+LBL_Description=
\n Product Version: {0} ({9})
Sleuth Kit Version: {7}
Netbeans RCP Build: {8}
Java: {1}; {2}
System: {3}; {4}; {5}
Userdir: {6}
Format_OperatingSystem_Value={0} version {1} running on {2} -LBL_Copyright=
Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools.
Copyright © 2003-2020.
+LBL_Copyright=
Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools.
Copyright © 2003-2020.
SortChooser.dialogTitle=Choose Sort Criteria ThumbnailViewChildren.progress.cancelling=(Cancelling) # {0} - file name @@ -97,7 +97,7 @@ DataContentViewerHex.goToPageTextField.text= DataContentViewerHex.goToPageLabel.text=Go to Page: DataResultViewerThumbnail.imagesLabel.text=Images: DataResultViewerThumbnail.imagesRangeLabel.text=- -DataResultViewerThumbnail.filePathLabel.text=\ +DataResultViewerThumbnail.filePathLabel.text=\ \ \ AdvancedConfigurationDialog.cancelButton.text=Cancel DataArtifactContentViewer.waitText=Retrieving and preparing data, please wait... DataArtifactContentViewer.errorText=Error retrieving result diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java index 1723c250c8..43941edb5d 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java @@ -24,10 +24,8 @@ import java.util.Comparator; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import java.util.stream.Stream; -import javax.swing.Action; import org.openide.nodes.Children; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; -import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.autopsy.mainui.datamodel.FileExtDocumentFilter; import org.sleuthkit.autopsy.mainui.datamodel.FileExtExecutableFilter; @@ -104,6 +102,7 @@ public class ViewsTypeFactory { public void respondSelection(DataResultTopComponent dataResultPanel) { dataResultPanel.displayFileSizes(this.getItemData().getSearchParams()); } + } } @@ -225,6 +224,7 @@ public class ViewsTypeFactory { public void respondSelection(DataResultTopComponent dataResultPanel) { dataResultPanel.displayFileMimes(this.getItemData().getSearchParams()); } + } } @@ -321,7 +321,8 @@ public class ViewsTypeFactory { super.respondSelection(dataResultPanel); } } + } } -} +} \ No newline at end of file From 5b105da718abacb2ed98315ffdee67bc7c7a5313 Mon Sep 17 00:00:00 2001 From: apriestman Date: Mon, 6 Dec 2021 10:58:08 -0500 Subject: [PATCH 09/20] Cleanup --- .../autopsy/corecomponents/Bundle.properties-MERGED | 6 +++--- .../sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED index 468e6d9430..cde18d3900 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED @@ -72,9 +72,9 @@ DataContentViewerHex.totalPageLabel.text_1=100 DataContentViewerHex.pageLabel2.text=Page # Product Information panel -LBL_Description=
\n Product Version: {0} ({9})
Sleuth Kit Version: {7}
Netbeans RCP Build: {8}
Java: {1}; {2}
System: {3}; {4}; {5}
Userdir: {6}
+LBL_Description=
\n Product Version: {0} ({9})
Sleuth Kit Version: {7}
Netbeans RCP Build: {8}
Java: {1}; {2}
System: {3}; {4}; {5}
Userdir: {6}
Format_OperatingSystem_Value={0} version {1} running on {2} -LBL_Copyright=
Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools.
Copyright © 2003-2020.
+LBL_Copyright=
Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools.
Copyright © 2003-2020.
SortChooser.dialogTitle=Choose Sort Criteria ThumbnailViewChildren.progress.cancelling=(Cancelling) # {0} - file name @@ -97,7 +97,7 @@ DataContentViewerHex.goToPageTextField.text= DataContentViewerHex.goToPageLabel.text=Go to Page: DataResultViewerThumbnail.imagesLabel.text=Images: DataResultViewerThumbnail.imagesRangeLabel.text=- -DataResultViewerThumbnail.filePathLabel.text=\ \ \ +DataResultViewerThumbnail.filePathLabel.text=\ AdvancedConfigurationDialog.cancelButton.text=Cancel DataArtifactContentViewer.waitText=Retrieving and preparing data, please wait... DataArtifactContentViewer.errorText=Error retrieving result diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java index 43941edb5d..c4ddbf366e 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java @@ -325,4 +325,4 @@ public class ViewsTypeFactory { } } -} \ No newline at end of file +} From cfec13e0fd41e8301d28f08d764629f71352d3bd Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Mon, 6 Dec 2021 13:00:27 -0500 Subject: [PATCH 10/20] Fixed the file selection --- .../corecomponents/DataResultPanel.java | 15 ++++-- .../corecomponents/DataResultViewerTable.java | 10 ++-- .../directorytree/ViewContextAction.java | 12 +++-- .../FileSystemContentSearchParam.java | 17 ++++++- .../mainui/nodes/FileSystemFactory.java | 15 +++++- .../mainui/nodes/SearchResultRootNode.java | 19 ++++++- .../mainui/nodes/TableNodeSelectionInfo.java | 49 +++++++++++++++++++ 7 files changed, 122 insertions(+), 15 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/mainui/nodes/TableNodeSelectionInfo.java diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java index 649f304356..fe94069bb2 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java @@ -1313,7 +1313,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C try { this.searchResultManager = new SearchManager(new FileSystemFetcher(fileSystemKey), getPageSize()); SearchResultsDTO results = searchResultManager.getResults(); - displaySearchResults(results, true); + displaySearchResults(results, true, fileSystemKey.getChildIdToSelect()); } catch (ExecutionException | IllegalArgumentException ex) { logger.log(Level.WARNING, MessageFormat.format( "There was an error fetching data for file system filter: {0}.", @@ -1374,16 +1374,23 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C "# {1} - pageCount", "DataResultPanel_pageIdxOfCount={0} of {1}" }) - private void displaySearchResults(SearchResultsDTO searchResults, boolean resetPaging) { + + private void displaySearchResults(SearchResultsDTO searchResults, boolean resetPaging) { + displaySearchResults(searchResults, resetPaging, null); + } + + private void displaySearchResults(SearchResultsDTO searchResults, boolean resetPaging, Long contentIdToSelect) { if (!SwingUtilities.isEventDispatchThread()) { - SwingUtilities.invokeLater(() -> displaySearchResults(searchResults, resetPaging)); + SwingUtilities.invokeLater(() -> displaySearchResults(searchResults, resetPaging, contentIdToSelect)); return; } if (searchResults == null) { setNode(null, resetPaging); } else { - setNode(new SearchResultRootNode(searchResults), resetPaging); + SearchResultRootNode node = new SearchResultRootNode(searchResults); + node.setChildIdToSelect(contentIdToSelect); + setNode(node, resetPaging); setNumberOfChildNodes( searchResults.getTotalResultsCount() > Integer.MAX_VALUE ? Integer.MAX_VALUE diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java index dffd0631ce..30f496cb7c 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java @@ -71,9 +71,8 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.datamodel.NodeProperty; -import org.sleuthkit.autopsy.datamodel.NodeSelectionInfo; -import org.sleuthkit.autopsy.mainui.nodes.SearchResultRootNode; import org.sleuthkit.autopsy.mainui.datamodel.SearchResultsDTO; +import org.sleuthkit.autopsy.mainui.nodes.TableNodeSelectionInfo; import org.sleuthkit.datamodel.Score.Significance; /** @@ -388,8 +387,8 @@ public class DataResultViewerTable extends AbstractDataResultViewer { * If one of the child nodes of the root node is to be selected, select * it. */ - if (rootNode instanceof TableFilterNode) { - NodeSelectionInfo selectedChildInfo = ((TableFilterNode) rootNode).getChildNodeSelectionInfo(); + if (rootNode instanceof TableNodeSelectionInfo) { + TableNodeSelectionInfo selectedChildInfo = ((TableNodeSelectionInfo) rootNode); if (null != selectedChildInfo) { Node[] childNodes = rootNode.getChildren().getNodes(true); for (int i = 0; i < childNodes.length; ++i) { @@ -406,7 +405,8 @@ public class DataResultViewerTable extends AbstractDataResultViewer { break; } } - ((TableFilterNode) rootNode).setChildNodeSelectionInfo(null); + // Once it is selected clear the id. + ((TableNodeSelectionInfo) rootNode).setChildIdToSelect(null); } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java index 323b340c7f..251a5c79ea 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java @@ -52,6 +52,7 @@ import org.sleuthkit.autopsy.datamodel.DataSourceFilesNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.PersonNode; import org.sleuthkit.autopsy.datamodel.RootContentChildren; +import org.sleuthkit.autopsy.mainui.nodes.TableNodeSelectionInfo; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Content; @@ -332,18 +333,23 @@ public class ViewContextAction extends AbstractAction { * tree view top component responds to the selection of the parent * node by pushing it into the results view top component. */ - DisplayableItemNode undecoratedParentNode = (DisplayableItemNode) ((DirectoryTreeFilterNode) parentTreeViewNode).getOriginal(); - undecoratedParentNode.setChildNodeSelectionInfo(new ContentNodeSelectionInfo(content)); + + Long childIdToSelect = content.getId(); + if (content instanceof BlackboardArtifact) { BlackboardArtifact artifact = ((BlackboardArtifact) content); long associatedId = artifact.getObjectID(); try { Content associatedFileContent = artifact.getSleuthkitCase().getContentById(associatedId); - undecoratedParentNode.setChildNodeSelectionInfo(new ContentNodeSelectionInfo(associatedFileContent)); + childIdToSelect = associatedFileContent.getId(); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Could not find associated content from artifact with id %d", artifact.getId()); } } + + if(parentTreeViewNode instanceof TableNodeSelectionInfo) { + ((TableNodeSelectionInfo) parentTreeViewNode).setChildIdToSelect(childIdToSelect); + } TreeView treeView = treeViewTopComponent.getTree(); treeView.expandNode(parentTreeViewNode); diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemContentSearchParam.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemContentSearchParam.java index ff74c0ab85..4408530ee2 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemContentSearchParam.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemContentSearchParam.java @@ -19,12 +19,17 @@ package org.sleuthkit.autopsy.mainui.datamodel; import java.util.Objects; +import org.sleuthkit.autopsy.mainui.nodes.TableNodeSelectionInfo; /** * Key for content object in order to retrieve data from DAO. */ -public class FileSystemContentSearchParam { +public class FileSystemContentSearchParam implements TableNodeSelectionInfo{ private final Long contentObjectId; + + // This param is can change, is not used as part of the search query and + // therefore is not included in the equals and hashcode methods. + private Long childContentToSelect; public FileSystemContentSearchParam(Long contentObjectId) { this.contentObjectId = contentObjectId; @@ -33,6 +38,16 @@ public class FileSystemContentSearchParam { public Long getContentObjectId() { return contentObjectId; } + + @Override + public void setChildIdToSelect(Long content) { + childContentToSelect = content; + } + + @Override + public Long getChildIdToSelect() { + return childContentToSelect; + } @Override public int hashCode() { diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/FileSystemFactory.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/FileSystemFactory.java index 1223132df5..354f6e34eb 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/FileSystemFactory.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/FileSystemFactory.java @@ -211,7 +211,9 @@ public class FileSystemFactory extends TreeChildFactory implements ActionContext { + public abstract static class FileSystemTreeNode extends TreeNode implements ActionContext, TableNodeSelectionInfo { + + private Long childContentToSelect; protected FileSystemTreeNode(String icon, TreeResultsDTO.TreeItemDTO itemData, Children children, Lookup lookup) { super(ContentNodeUtil.getContentName(itemData.getSearchParams().getContentObjectId()), icon, itemData, children, lookup); @@ -234,6 +236,7 @@ public class FileSystemFactory extends TreeChildFactory 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.mainui.nodes; + +import org.openide.nodes.Node; +import org.sleuthkit.datamodel.Content; + +/** + * An interface for nodes that support the view selected file\directory. + */ +public interface TableNodeSelectionInfo { + + void setChildIdToSelect(Long contentId); + + Long getChildIdToSelect(); + + /** + * Determine of the given node represents the child content to + * be selected. + * + * @param node + * + * @return True if there is a match. + */ + default boolean matches(Node node) { + Content content = node.getLookup().lookup(Content.class); + if (content != null && getChildIdToSelect() != null) { + return getChildIdToSelect().equals(content.getId()); + } + + return false; + } +} From 6c45c85226d4c4fa554b415c8de151accf9faf2c Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Mon, 6 Dec 2021 13:06:05 -0500 Subject: [PATCH 11/20] Cleanup --- .../org/sleuthkit/autopsy/directorytree/ViewContextAction.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java index 251a5c79ea..2a75a9b04d 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java @@ -46,10 +46,8 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode; import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; -import org.sleuthkit.autopsy.datamodel.ContentNodeSelectionInfo; import org.sleuthkit.autopsy.datamodel.DataSourcesNode; import org.sleuthkit.autopsy.datamodel.DataSourceFilesNode; -import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.PersonNode; import org.sleuthkit.autopsy.datamodel.RootContentChildren; import org.sleuthkit.autopsy.mainui.nodes.TableNodeSelectionInfo; From e652ce3eaad5e5bed45870127a3ec4c9d32f2919 Mon Sep 17 00:00:00 2001 From: apriestman Date: Tue, 7 Dec 2021 11:18:58 -0500 Subject: [PATCH 12/20] Display top label for more nodes. Fix pool icon. --- .../autopsy/directorytree/DirectoryTreeTopComponent.java | 6 ++++++ .../sleuthkit/autopsy/mainui/nodes/FileSystemFactory.java | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index bec78407d8..ea4c52106e 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -899,6 +899,12 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat } } else if (originNode.getLookup().lookup(String.class) != null) { displayName = originNode.getLookup().lookup(String.class); + } else { + if (originNode.getDisplayName() != null) { + displayName = originNode.getDisplayName().replaceAll("\\([0-9]+\\)", ""); + } else { + displayName = originNode.getName(); + } } dataResult.setPath(displayName); } diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/FileSystemFactory.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/FileSystemFactory.java index 1223132df5..b7489e94f7 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/FileSystemFactory.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/FileSystemFactory.java @@ -316,7 +316,7 @@ public class FileSystemFactory extends TreeChildFactory itemData) { - super(NodeIconUtil.VOLUME.getPath(), + super(NodeIconUtil.POOL.getPath(), itemData, createChildrenForContent(itemData.getSearchParams().getContentObjectId()), ContentNodeUtil.getLookup(pool)); From 5f6e94d373024ae8ca11642d136979761a99b093 Mon Sep 17 00:00:00 2001 From: apriestman Date: Tue, 7 Dec 2021 11:29:02 -0500 Subject: [PATCH 13/20] Add anchor to regex --- .../autopsy/directorytree/DirectoryTreeTopComponent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index ea4c52106e..346eca9316 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -901,7 +901,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat displayName = originNode.getLookup().lookup(String.class); } else { if (originNode.getDisplayName() != null) { - displayName = originNode.getDisplayName().replaceAll("\\([0-9]+\\)", ""); + displayName = originNode.getDisplayName().replaceAll("\\([0-9]+\\)$", ""); } else { displayName = originNode.getName(); } From 489180d20f4b9c3262bb626446a5dbc8fb07947c Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 7 Dec 2021 14:13:31 -0500 Subject: [PATCH 14/20] fix communications spelling --- .../org/sleuthkit/autopsy/mainui/nodes/Bundle.properties-MERGED | 2 +- .../sleuthkit/autopsy/mainui/nodes/DataArtifactTypeFactory.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/mainui/nodes/Bundle.properties-MERGED index 11ca64b00e..adeb23c964 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/Bundle.properties-MERGED @@ -1,5 +1,5 @@ AnalysisResultTypeFactory_adHocName=Adhoc Results -DataArtifactTypeFactory_AccountTypeParentNode_displayName=Communcation Accounts +DataArtifactTypeFactory_AccountTypeParentNode_displayName=Communication Accounts FileSystemFactory.FileSystemTreeNode.ExtractUnallocAction.text=Extract Unallocated Space to Single Files FileSystemFactory.UnsupportedTreeNode.displayName=Unsupported Content ImageNode_ExtractUnallocAction_text=Extract Unallocated Space to Single Files diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/DataArtifactTypeFactory.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/DataArtifactTypeFactory.java index 4ecbe55a08..511cc8486c 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/DataArtifactTypeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/DataArtifactTypeFactory.java @@ -118,7 +118,7 @@ public class DataArtifactTypeFactory extends TreeChildFactory { From eb088ec676e6ca9781111851d2eecc7dfb94ade4 Mon Sep 17 00:00:00 2001 From: apriestman Date: Tue, 7 Dec 2021 14:36:22 -0500 Subject: [PATCH 15/20] Change name of ad hoc node --- .../autopsy/mainui/nodes/AnalysisResultTypeFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/AnalysisResultTypeFactory.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/AnalysisResultTypeFactory.java index 6c17eb5daf..666e6d90f1 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/AnalysisResultTypeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/AnalysisResultTypeFactory.java @@ -240,7 +240,7 @@ public class AnalysisResultTypeFactory extends TreeChildFactory itemData) { - super(itemData.getSearchParams().getArtifactType().getTypeName(), + super("KEYWORD_SET_NODE_AD_HOC", getIconPath(itemData.getSearchParams().getArtifactType()), itemData, Children.create(new KeywordSearchTermFactory(itemData.getSearchParams()), true), From cb5177656652f494ad7a123f11a529719e5bde94 Mon Sep 17 00:00:00 2001 From: apriestman Date: Tue, 7 Dec 2021 15:43:32 -0500 Subject: [PATCH 16/20] Fix node names --- .../sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java | 5 +++-- .../autopsy/mainui/nodes/AnalysisResultTypeFactory.java | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java index 16280fee76..15e32c8687 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java @@ -26,6 +26,7 @@ import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.mainui.nodes.ContentNodeUtil; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.LocalFilesDataSource; @@ -52,13 +53,13 @@ class DataSourceGroupingNode extends DisplayableItemNode { if (dataSource instanceof Image) { Image image = (Image) dataSource; - super.setName(image.getName()); + super.setName(ContentNodeUtil.getContentName(image.getId())); super.setDisplayName(image.getName()); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/image.png"); } else if (dataSource instanceof LocalFilesDataSource) { LocalFilesDataSource localFilesDataSource = (LocalFilesDataSource) dataSource; - super.setName(localFilesDataSource.getName()); + super.setName(ContentNodeUtil.getContentName(localFilesDataSource.getId())); super.setDisplayName(localFilesDataSource.getName()); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); } diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/AnalysisResultTypeFactory.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/AnalysisResultTypeFactory.java index 666e6d90f1..2fb1d88848 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/AnalysisResultTypeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/AnalysisResultTypeFactory.java @@ -201,7 +201,7 @@ public class AnalysisResultTypeFactory extends TreeChildFactory itemData) { - super(itemData.getSearchParams().getArtifactType().getTypeName(), + super(itemData.getSearchParams().getArtifactType().getTypeName() + "_SET_" + itemData.getSearchParams().getSetName(), getIconPath(itemData.getSearchParams().getArtifactType()), itemData, Children.LEAF, @@ -240,7 +240,7 @@ public class AnalysisResultTypeFactory extends TreeChildFactory itemData) { - super("KEYWORD_SET_NODE_AD_HOC", + super("TSK_KEYWORD_HIT_SET_" + itemData.getSearchParams().getSetName(), getIconPath(itemData.getSearchParams().getArtifactType()), itemData, Children.create(new KeywordSearchTermFactory(itemData.getSearchParams()), true), From edc1fd4fc5a276602b25416a7c0e3df3e644e3ec Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 7 Dec 2021 15:50:28 -0500 Subject: [PATCH 17/20] Refactored to for work with other stories --- .../corecomponents/DataResultViewerTable.java | 8 +++--- .../directorytree/ViewContextAction.java | 6 ++--- .../FileSystemContentSearchParam.java | 4 +-- .../mainui/nodes/FileSystemFactory.java | 3 ++- ...ectionInfo.java => NodeSelectionInfo.java} | 27 ++++++++++--------- .../mainui/nodes/SearchResultRootNode.java | 7 ++--- 6 files changed, 28 insertions(+), 27 deletions(-) rename Core/src/org/sleuthkit/autopsy/mainui/nodes/{TableNodeSelectionInfo.java => NodeSelectionInfo.java} (67%) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java index 30f496cb7c..3563635974 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java @@ -72,7 +72,7 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.datamodel.NodeProperty; import org.sleuthkit.autopsy.mainui.datamodel.SearchResultsDTO; -import org.sleuthkit.autopsy.mainui.nodes.TableNodeSelectionInfo; +import org.sleuthkit.autopsy.mainui.nodes.NodeSelectionInfo.ContentNodeSelectionInfo; import org.sleuthkit.datamodel.Score.Significance; /** @@ -387,8 +387,8 @@ public class DataResultViewerTable extends AbstractDataResultViewer { * If one of the child nodes of the root node is to be selected, select * it. */ - if (rootNode instanceof TableNodeSelectionInfo) { - TableNodeSelectionInfo selectedChildInfo = ((TableNodeSelectionInfo) rootNode); + if (rootNode instanceof ContentNodeSelectionInfo) { + ContentNodeSelectionInfo selectedChildInfo = ((ContentNodeSelectionInfo) rootNode); if (null != selectedChildInfo) { Node[] childNodes = rootNode.getChildren().getNodes(true); for (int i = 0; i < childNodes.length; ++i) { @@ -406,7 +406,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { } } // Once it is selected clear the id. - ((TableNodeSelectionInfo) rootNode).setChildIdToSelect(null); + ((ContentNodeSelectionInfo) rootNode).setChildIdToSelect(null); } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java index 2a75a9b04d..2f8ca4da55 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java @@ -50,7 +50,7 @@ import org.sleuthkit.autopsy.datamodel.DataSourcesNode; import org.sleuthkit.autopsy.datamodel.DataSourceFilesNode; import org.sleuthkit.autopsy.datamodel.PersonNode; import org.sleuthkit.autopsy.datamodel.RootContentChildren; -import org.sleuthkit.autopsy.mainui.nodes.TableNodeSelectionInfo; +import org.sleuthkit.autopsy.mainui.nodes.NodeSelectionInfo.ContentNodeSelectionInfo; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Content; @@ -345,8 +345,8 @@ public class ViewContextAction extends AbstractAction { } } - if(parentTreeViewNode instanceof TableNodeSelectionInfo) { - ((TableNodeSelectionInfo) parentTreeViewNode).setChildIdToSelect(childIdToSelect); + if(parentTreeViewNode instanceof ContentNodeSelectionInfo) { + ((ContentNodeSelectionInfo) parentTreeViewNode).setChildIdToSelect(childIdToSelect); } TreeView treeView = treeViewTopComponent.getTree(); diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemContentSearchParam.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemContentSearchParam.java index 4408530ee2..71260b8aaa 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemContentSearchParam.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileSystemContentSearchParam.java @@ -19,12 +19,12 @@ package org.sleuthkit.autopsy.mainui.datamodel; import java.util.Objects; -import org.sleuthkit.autopsy.mainui.nodes.TableNodeSelectionInfo; +import org.sleuthkit.autopsy.mainui.nodes.NodeSelectionInfo.ContentNodeSelectionInfo; /** * Key for content object in order to retrieve data from DAO. */ -public class FileSystemContentSearchParam implements TableNodeSelectionInfo{ +public class FileSystemContentSearchParam implements ContentNodeSelectionInfo{ private final Long contentObjectId; // This param is can change, is not used as part of the search query and diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/FileSystemFactory.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/FileSystemFactory.java index 354f6e34eb..ff3c17f533 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/FileSystemFactory.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/FileSystemFactory.java @@ -43,6 +43,7 @@ import static org.sleuthkit.autopsy.mainui.nodes.NodeIconUtil.CARVED_FILE; import static org.sleuthkit.autopsy.mainui.nodes.NodeIconUtil.DELETED_FILE; import static org.sleuthkit.autopsy.mainui.nodes.NodeIconUtil.DELETED_FOLDER; import static org.sleuthkit.autopsy.mainui.nodes.NodeIconUtil.FOLDER; +import org.sleuthkit.autopsy.mainui.nodes.NodeSelectionInfo.ContentNodeSelectionInfo; import static org.sleuthkit.autopsy.mainui.nodes.TreeNode.getDefaultLookup; import org.sleuthkit.autopsy.mainui.nodes.actions.ActionContext; import org.sleuthkit.autopsy.mainui.nodes.actions.ActionsFactory; @@ -211,7 +212,7 @@ public class FileSystemFactory extends TreeChildFactory implements ActionContext, TableNodeSelectionInfo { + public abstract static class FileSystemTreeNode extends TreeNode implements ActionContext, ContentNodeSelectionInfo { private Long childContentToSelect; diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/TableNodeSelectionInfo.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/NodeSelectionInfo.java similarity index 67% rename from Core/src/org/sleuthkit/autopsy/mainui/nodes/TableNodeSelectionInfo.java rename to Core/src/org/sleuthkit/autopsy/mainui/nodes/NodeSelectionInfo.java index facbb10392..df02260e48 100755 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/TableNodeSelectionInfo.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/NodeSelectionInfo.java @@ -24,12 +24,7 @@ import org.sleuthkit.datamodel.Content; /** * An interface for nodes that support the view selected file\directory. */ -public interface TableNodeSelectionInfo { - - void setChildIdToSelect(Long contentId); - - Long getChildIdToSelect(); - +public interface NodeSelectionInfo { /** * Determine of the given node represents the child content to * be selected. @@ -38,12 +33,20 @@ public interface TableNodeSelectionInfo { * * @return True if there is a match. */ - default boolean matches(Node node) { - Content content = node.getLookup().lookup(Content.class); - if (content != null && getChildIdToSelect() != null) { - return getChildIdToSelect().equals(content.getId()); - } + boolean matches(Node node); + + public interface ContentNodeSelectionInfo extends NodeSelectionInfo{ + void setChildIdToSelect(Long contentId); - return false; + Long getChildIdToSelect(); + + default boolean matches(Node node) { + Content content = node.getLookup().lookup(Content.class); + if (content != null && getChildIdToSelect() != null) { + return getChildIdToSelect().equals(content.getId()); + } + + return false; + } } } diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/SearchResultRootNode.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/SearchResultRootNode.java index b8c45e226c..effa852f3e 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/SearchResultRootNode.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/SearchResultRootNode.java @@ -18,22 +18,19 @@ */ package org.sleuthkit.autopsy.mainui.nodes; -import java.util.Optional; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; -import org.openide.nodes.Node; import org.openide.nodes.Sheet; -import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.datamodel.NodeProperty; import org.sleuthkit.autopsy.mainui.datamodel.SearchResultsDTO; -import org.sleuthkit.datamodel.Content; +import org.sleuthkit.autopsy.mainui.nodes.NodeSelectionInfo.ContentNodeSelectionInfo; /** * A node whose children will be displayed in the results view and determines * children based on a SearchResultDTO. */ -public class SearchResultRootNode extends AbstractNode implements TableNodeSelectionInfo{ +public class SearchResultRootNode extends AbstractNode implements ContentNodeSelectionInfo{ private final SearchResultChildFactory factory; From 11133310140cc1795ea8786abbe94b51d37794f9 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 8 Dec 2021 09:26:51 -0500 Subject: [PATCH 18/20] suffix update --- .../autopsy/mainui/datamodel/TreeResultsDTO.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/TreeResultsDTO.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/TreeResultsDTO.java index 81f176190d..78a310530d 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/TreeResultsDTO.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/TreeResultsDTO.java @@ -80,12 +80,23 @@ public class TreeResultsDTO { return count; } + /** + * Returns the suffix to be added to a display string when displaying + * this count. + * + * NOTE: If this code changes, regex code in + * DirectoryTreeTopComponent.respondSelection will need to be updated as + * well. + * + * @return The suffix to be added to a display string when displaying + * this count. + */ public String getDisplaySuffix() { switch (this.type) { case DETERMINATE: return " (" + count + ")"; case INDETERMINATE: - return "..."; + return " (...)"; case NOT_SHOWN: default: return ""; From 54c231cc02ae306414c9670cb19bea55adfa5a47 Mon Sep 17 00:00:00 2001 From: apriestman Date: Wed, 8 Dec 2021 11:26:24 -0500 Subject: [PATCH 19/20] Remove indeterminate count from title --- .../autopsy/directorytree/DirectoryTreeTopComponent.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 346eca9316..7ff14bb475 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -901,7 +901,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat displayName = originNode.getLookup().lookup(String.class); } else { if (originNode.getDisplayName() != null) { - displayName = originNode.getDisplayName().replaceAll("\\([0-9]+\\)$", ""); + // Remove node count from name if present + displayName = originNode.getDisplayName().replaceAll("\\(([0-9]+|\\.\\.\\.)\\)$", ""); } else { displayName = originNode.getName(); } From e5847192289831c1e9a39bca610509b741d58b9b Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 9 Dec 2021 13:45:47 -0500 Subject: [PATCH 20/20] updates for file type extensions and size --- .../autopsy/mainui/datamodel/MainDAO.java | 3 +- .../autopsy/mainui/datamodel/ViewsDAO.java | 191 +++++++++++++----- .../events/FileTypeExtensionsEvent.java | 29 +-- .../datamodel/events/FileTypeSizeEvent.java | 19 +- .../mainui/nodes/TreeChildFactory.java | 44 ++-- .../mainui/nodes/ViewsTypeFactory.java | 44 +++- 6 files changed, 238 insertions(+), 92 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/MainDAO.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/MainDAO.java index 817a3e212c..148c606b46 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/MainDAO.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/MainDAO.java @@ -68,7 +68,8 @@ public class MainDAO extends AbstractDAO { Case.Events.OS_ACCOUNTS_ADDED.toString(), Case.Events.OS_ACCOUNTS_UPDATED.toString(), Case.Events.OS_ACCOUNTS_DELETED.toString(), - Case.Events.OS_ACCT_INSTANCES_ADDED.toString() + Case.Events.OS_ACCT_INSTANCES_ADDED.toString(), + Case.Events.DATA_SOURCE_ADDED.toString() ); private static final long WATCH_RESOLUTION_MILLIS = 30 * 1000; diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/ViewsDAO.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/ViewsDAO.java index f736313298..8804560afa 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/ViewsDAO.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/ViewsDAO.java @@ -25,6 +25,7 @@ import com.google.common.collect.ImmutableSet; import java.beans.PropertyChangeEvent; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -142,8 +143,8 @@ public class ViewsDAO extends AbstractDAO { } FileTypeExtensionsEvent extEvt = (FileTypeExtensionsEvent) eventData; - return key.getFilter().equals(extEvt.getExtensionFilter()) - && (key.getDataSourceId() == null || key.getDataSourceId().equals(extEvt.getDataSourceId())); + return (extEvt.getExtensionFilter() == null || key.getFilter().equals(extEvt.getExtensionFilter())) + && (key.getDataSourceId() == null || extEvt.getDataSourceId() == null || key.getDataSourceId().equals(extEvt.getDataSourceId())); } private boolean isFilesByMimeInvalidating(FileTypeMimeSearchParams key, DAOEvent eventData) { @@ -162,8 +163,8 @@ public class ViewsDAO extends AbstractDAO { } FileTypeSizeEvent sizeEvt = (FileTypeSizeEvent) eventData; - return sizeEvt.getSizeFilter().equals(key.getSizeFilter()) - && (key.getDataSourceId() == null || Objects.equals(key.getDataSourceId(), sizeEvt.getDataSourceId())); + return (sizeEvt.getSizeFilter() == null || sizeEvt.getSizeFilter().equals(key.getSizeFilter())) + && (key.getDataSourceId() == null || sizeEvt.getDataSourceId() == null || Objects.equals(key.getDataSourceId(), sizeEvt.getDataSourceId())); } /** @@ -347,11 +348,13 @@ public class ViewsDAO extends AbstractDAO { for (DAOEvent evt : this.treeCounts.getEnqueued()) { if (evt instanceof FileTypeExtensionsEvent) { FileTypeExtensionsEvent extEvt = (FileTypeExtensionsEvent) evt; - if (dataSourceId == null || Objects.equals(extEvt.getDataSourceId(), dataSourceId)) { - for (FileExtSearchFilter filter : filters) { - if (filter.getFilter().contains(evt)) { - indeterminateFilters.add(filter); - } + if (dataSourceId == null || extEvt.getDataSourceId() == null || Objects.equals(extEvt.getDataSourceId(), dataSourceId)) { + if (extEvt.getExtensionFilter() == null) { + // add all filters if extension filter is null and keep going + indeterminateFilters.addAll(filters); + break; + } else if (filters.contains(extEvt.getExtensionFilter())) { + indeterminateFilters.add(extEvt.getExtensionFilter()); } } } @@ -392,7 +395,7 @@ public class ViewsDAO extends AbstractDAO { FileTypeExtensionsSearchParams.getTypeId(), new FileTypeExtensionsSearchParams(filter, dataSourceId), filter, - filter.getDisplayName(), + filter == null ? "" : filter.getDisplayName(), displayCount); } @@ -412,8 +415,14 @@ public class ViewsDAO extends AbstractDAO { for (DAOEvent evt : this.treeCounts.getEnqueued()) { if (evt instanceof FileTypeSizeEvent) { FileTypeSizeEvent sizeEvt = (FileTypeSizeEvent) evt; - if (dataSourceId == null || Objects.equals(sizeEvt.getDataSourceId(), dataSourceId)) { - indeterminateFilters.add(sizeEvt.getSizeFilter()); + if (dataSourceId == null || sizeEvt.getDataSourceId() == null || Objects.equals(sizeEvt.getDataSourceId(), dataSourceId)) { + if (sizeEvt.getSizeFilter() == null) { + // if null size filter, indicates full refresh and all file sizes need refresh. + indeterminateFilters.addAll(Arrays.asList(FileSizeFilter.values())); + break; + } else { + indeterminateFilters.add(sizeEvt.getSizeFilter()); + } } } } @@ -453,7 +462,7 @@ public class ViewsDAO extends AbstractDAO { FileTypeSizeSearchParams.getTypeId(), new FileTypeSizeSearchParams(filter, dataSourceId), filter, - filter.getDisplayName(), + filter == null ? "" : filter.getDisplayName(), displayCount); } @@ -774,8 +783,21 @@ public class ViewsDAO extends AbstractDAO { @Override Set handleIngestComplete() { - return SubDAOUtils.getIngestCompleteEvents(this.treeCounts, + SubDAOUtils.invalidateKeys(this.searchParamsCache, + (searchParams) -> searchParamsMatchEvent(null, null, null, null, true, searchParams)); + + Set treeEvts = SubDAOUtils.getIngestCompleteEvents(this.treeCounts, (daoEvt, count) -> createTreeItem(daoEvt, count)); + + Set fileViewRefreshEvents = getFileViewRefreshEvents(null); + + List fileViewRefreshTreeEvents = fileViewRefreshEvents.stream() + .map(evt -> new TreeEvent(createTreeItem(evt, TreeDisplayCount.UNSPECIFIED), true)) + .collect(Collectors.toList()); + + return Stream.of(treeEvts, fileViewRefreshEvents, fileViewRefreshTreeEvents) + .flatMap(c -> c.stream()) + .collect(Collectors.toSet()); } @Override @@ -786,53 +808,85 @@ public class ViewsDAO extends AbstractDAO { @Override Set processEvent(PropertyChangeEvent evt) { - AbstractFile af = DAOEventUtils.getFileFromFileEvent(evt); - if (af == null) { - return Collections.emptySet(); - } else if (hideKnownFilesInViewsTree() && TskData.FileKnown.KNOWN.equals(af.getKnown())) { - return Collections.emptySet(); - } + Long dsId = null; + boolean dataSourceAdded = false; + Set evtExtFilters = null; + String evtMimeType = null; + FileSizeFilter evtFileSize = null; - long dsId = af.getDataSourceObjectId(); + if (Case.Events.DATA_SOURCE_ADDED.toString().equals(evt.getPropertyName())) { + dsId = evt.getNewValue() instanceof Long ? (Long) evt.getNewValue() : null; + dataSourceAdded = true; + } else { + AbstractFile af = DAOEventUtils.getFileFromFileEvent(evt); + if (af == null) { + return Collections.emptySet(); + } else if (hideKnownFilesInViewsTree() && TskData.FileKnown.KNOWN.equals(af.getKnown())) { + return Collections.emptySet(); + } - // create an extension mapping if extension present - Set evtExtFilters = (StringUtils.isBlank(af.getNameExtension()) || !TSK_FS_NAME_TYPE_ENUM.REG.equals(af.getDirType())) - ? Collections.emptySet() - : EXTENSION_FILTER_MAP.getOrDefault("." + af.getNameExtension(), Collections.emptySet()); + dsId = af.getDataSourceObjectId(); - // create a mime type mapping if mime type present - String evtMimeType = (StringUtils.isBlank(af.getMIMEType()) || !TSK_FS_NAME_TYPE_ENUM.REG.equals(af.getDirType())) || !getMimeDbFilesTypes().contains(af.getType()) - ? null - : af.getMIMEType(); + // create an extension mapping if extension present + if (StringUtils.isBlank(af.getNameExtension()) || !TSK_FS_NAME_TYPE_ENUM.REG.equals(af.getDirType())) { + evtExtFilters = EXTENSION_FILTER_MAP.getOrDefault("." + af.getNameExtension(), Collections.emptySet()); + } - // create a size mapping if size present in filters - FileSizeFilter evtFileSize = TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.equals(af.getType()) - ? null - : Stream.of(FileSizeFilter.values()) + // create a mime type mapping if mime type present + if (StringUtils.isBlank(af.getMIMEType()) || !TSK_FS_NAME_TYPE_ENUM.REG.equals(af.getDirType()) || !getMimeDbFilesTypes().contains(af.getType())) { + evtMimeType = af.getMIMEType(); + } + + // create a size mapping if size present in filters + if (TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.equals(af.getType())) { + evtFileSize = Stream.of(FileSizeFilter.values()) .filter(filter -> af.getSize() >= filter.getMinBound() && (filter.getMaxBound() == null || af.getSize() < filter.getMaxBound())) .findFirst() .orElse(null); + } - if (evtExtFilters.isEmpty() && evtMimeType == null && evtFileSize == null) { - return Collections.emptySet(); + if (evtExtFilters == null || evtExtFilters.isEmpty() && evtMimeType == null && evtFileSize == null) { + return Collections.emptySet(); + } } - SubDAOUtils.invalidateKeys(this.searchParamsCache, - (Predicate) (searchParams) -> searchParamsMatchEvent(evtExtFilters, evtMimeType, evtFileSize, dsId, searchParams)); + return invalidateAndReturnEvents(evtExtFilters, evtMimeType, evtFileSize, dsId, dataSourceAdded); + } - return getDAOEvents(evtExtFilters, evtMimeType, evtFileSize, dsId); + /** + * Handles invalidating caches and returning events based on digest. + * + * @param evtExtFilters The file extension filters or empty set. + * @param evtMimeType The mime type or null. + * @param evtFileSize The file size filter or null. + * @param dsId The data source id or null. + * @param dataSourceAdded Whether or not this is a data source added event. + * + * @return The set of dao events to be fired. + */ + private Set invalidateAndReturnEvents(Set evtExtFilters, String evtMimeType, + FileSizeFilter evtFileSize, Long dsId, boolean dataSourceAdded) { + + SubDAOUtils.invalidateKeys(this.searchParamsCache, + (Predicate) (searchParams) -> searchParamsMatchEvent(evtExtFilters, evtMimeType, + evtFileSize, dsId, dataSourceAdded, searchParams)); + + return getDAOEvents(evtExtFilters, evtMimeType, evtFileSize, dsId, dataSourceAdded); } private boolean searchParamsMatchEvent(Set evtExtFilters, String evtMimeType, FileSizeFilter evtFileSize, - long dsId, + Long dsId, + boolean dataSourceAdded, Object searchParams) { if (searchParams instanceof FileTypeExtensionsSearchParams) { FileTypeExtensionsSearchParams extParams = (FileTypeExtensionsSearchParams) searchParams; - return evtExtFilters.contains(extParams.getFilter()) - && (extParams.getDataSourceId() == null || Objects.equals(extParams.getDataSourceId(), dsId)); + // if data source added or evtExtFilters contain param filter + return (dataSourceAdded || (evtExtFilters != null && evtExtFilters.contains(extParams.getFilter()))) + // and data source is either null or they are equal data source ids + && (extParams.getDataSourceId() == null || dsId == null || Objects.equals(extParams.getDataSourceId(), dsId)); } else if (searchParams instanceof FileTypeMimeSearchParams) { FileTypeMimeSearchParams mimeParams = (FileTypeMimeSearchParams) searchParams; @@ -841,8 +895,10 @@ public class ViewsDAO extends AbstractDAO { } else if (searchParams instanceof FileTypeSizeSearchParams) { FileTypeSizeSearchParams sizeParams = (FileTypeSizeSearchParams) searchParams; - return Objects.equals(sizeParams.getSizeFilter(), evtFileSize) - && (sizeParams.getDataSourceId() == null || Objects.equals(sizeParams.getDataSourceId(), dsId)); + // if data source added or size filter is equal to param filter + return (dataSourceAdded || Objects.equals(sizeParams.getSizeFilter(), evtFileSize)) + // and data source is either null or they are equal data source ids + && (sizeParams.getDataSourceId() == null || dsId == null || Objects.equals(sizeParams.getDataSourceId(), dsId)); } else { return false; } @@ -852,21 +908,21 @@ public class ViewsDAO extends AbstractDAO { * Clears relevant cache entries from cache based on digest of autopsy * events. * - * @param extFilters The set of affected extension filters. - * @param mimeType The affected mime type or null. - * @param sizeFilter The affected size filter or null. - * @param dsId The file object id. + * @param extFilters The set of affected extension filters. + * @param mimeType The affected mime type or null. + * @param sizeFilter The affected size filter or null. + * @param dsId The file object id. + * @param dataSourceAdded A data source was added. * * @return The list of affected dao events. */ - private Set getDAOEvents(Set extFilters, - String mimeType, - FileSizeFilter sizeFilter, - long dsId) { + private Set getDAOEvents(Set extFilters, String mimeType, FileSizeFilter sizeFilter, Long dsId, boolean dataSourceAdded) { - List daoEvents = extFilters.stream() - .map(extFilter -> new FileTypeExtensionsEvent(extFilter, dsId)) - .collect(Collectors.toList()); + List daoEvents = extFilters == null + ? new ArrayList<>() + : extFilters.stream() + .map(extFilter -> new FileTypeExtensionsEvent(extFilter, dsId)) + .collect(Collectors.toList()); if (mimeType != null) { daoEvents.add(new FileTypeMimeEvent(mimeType, dsId)); @@ -880,11 +936,36 @@ public class ViewsDAO extends AbstractDAO { .map(daoEvt -> new TreeEvent(createTreeItem(daoEvt, TreeDisplayCount.INDETERMINATE), false)) .collect(Collectors.toList()); - return Stream.of(daoEvents, treeEvents) + // data source added events are not necessarily fired before ingest completed/cancelled, so don't handle dataSourceAdded events with delay. + Set forceRefreshEvents = (dataSourceAdded) + ? getFileViewRefreshEvents(dsId) + : Collections.emptySet(); + + List forceRefreshTreeEvents = forceRefreshEvents.stream() + .map(evt -> new TreeEvent(createTreeItem(evt, TreeDisplayCount.UNSPECIFIED), true)) + .collect(Collectors.toList()); + + return Stream.of(daoEvents, treeEvents, forceRefreshEvents, forceRefreshTreeEvents) .flatMap(lst -> lst.stream()) .collect(Collectors.toSet()); } + /** + * Returns events for when a full refresh is required because module content + * events will not necessarily provide events for files (i.e. data source + * added, ingest cancelled/completed). + * + * @param dataSourceId The data source id or null if not applicable. + * + * @return The set of events that apply in this situation. + */ + private Set getFileViewRefreshEvents(Long dataSourceId) { + return ImmutableSet.of( + new FileTypeSizeEvent(null, dataSourceId), + new FileTypeExtensionsEvent(null, dataSourceId) + ); + } + /** * Handles fetching and paging of data for file types by extension. */ diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/events/FileTypeExtensionsEvent.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/events/FileTypeExtensionsEvent.java index 21a389975a..354cb25010 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/events/FileTypeExtensionsEvent.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/events/FileTypeExtensionsEvent.java @@ -22,15 +22,22 @@ import java.util.Objects; import org.sleuthkit.autopsy.mainui.datamodel.FileExtSearchFilter; /** - * An event to signal that files have been added or removed - * with the given extension on the given data source. + * An event to signal that files have been added or removed with the given + * extension on the given data source. */ public class FileTypeExtensionsEvent implements DAOEvent { private final FileExtSearchFilter extensionFilter; - private final long dataSourceId; + private final Long dataSourceId; - public FileTypeExtensionsEvent(FileExtSearchFilter extensionFilter, long dataSourceId) { + /** + * Main constructor. + * + * @param extensionFilter The extension filter. If null, indicates full + * refresh necessary. + * @param dataSourceId The data source id. + */ + public FileTypeExtensionsEvent(FileExtSearchFilter extensionFilter, Long dataSourceId) { this.extensionFilter = extensionFilter; this.dataSourceId = dataSourceId; } @@ -39,15 +46,15 @@ public class FileTypeExtensionsEvent implements DAOEvent { return extensionFilter; } - public long getDataSourceId() { + public Long getDataSourceId() { return dataSourceId; } @Override public int hashCode() { - int hash = 7; - hash = 83 * hash + Objects.hashCode(this.extensionFilter); - hash = 83 * hash + (int) (this.dataSourceId ^ (this.dataSourceId >>> 32)); + int hash = 3; + hash = 89 * hash + Objects.hashCode(this.extensionFilter); + hash = 89 * hash + Objects.hashCode(this.dataSourceId); return hash; } @@ -63,17 +70,15 @@ public class FileTypeExtensionsEvent implements DAOEvent { return false; } final FileTypeExtensionsEvent other = (FileTypeExtensionsEvent) obj; - if (this.dataSourceId != other.dataSourceId) { + if (!Objects.equals(this.extensionFilter, other.extensionFilter)) { return false; } - if (!Objects.equals(this.extensionFilter, other.extensionFilter)) { + if (!Objects.equals(this.dataSourceId, other.dataSourceId)) { return false; } return true; } - - @Override public Type getType() { return Type.RESULT; diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/events/FileTypeSizeEvent.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/events/FileTypeSizeEvent.java index eb0f37f8a4..1fe4256130 100755 --- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/events/FileTypeSizeEvent.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/events/FileTypeSizeEvent.java @@ -22,14 +22,21 @@ import java.util.Objects; import org.sleuthkit.autopsy.mainui.datamodel.FileSizeFilter; /** - * An event to signal that files have been added or removed - * within the given size range on the given data source. + * An event to signal that files have been added or removed within the given + * size range on the given data source. */ public class FileTypeSizeEvent implements DAOEvent { private final FileSizeFilter sizeFilter; private final Long dataSourceId; + /** + * Main constructor. + * + * @param sizeFilter The size filter. If null, indicates full refresh is + * necessary. + * @param dataSourceId The data source id or null. + */ public FileTypeSizeEvent(FileSizeFilter sizeFilter, Long dataSourceId) { this.sizeFilter = sizeFilter; this.dataSourceId = dataSourceId; @@ -45,9 +52,9 @@ public class FileTypeSizeEvent implements DAOEvent { @Override public int hashCode() { - int hash = 7; - hash = 53 * hash + Objects.hashCode(this.sizeFilter); - hash = 53 * hash + Objects.hashCode(this.dataSourceId); + int hash = 5; + hash = 73 * hash + Objects.hashCode(this.sizeFilter); + hash = 73 * hash + Objects.hashCode(this.dataSourceId); return hash; } @@ -72,6 +79,8 @@ public class FileTypeSizeEvent implements DAOEvent { return true; } + + @Override public Type getType() { return Type.RESULT; diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/TreeChildFactory.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/TreeChildFactory.java index 02cbdf1513..0c339674fe 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/TreeChildFactory.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/TreeChildFactory.java @@ -48,21 +48,7 @@ public abstract class TreeChildFactory extends ChildFactory.Detachable { if (evt.getNewValue() instanceof DAOAggregateEvent) { - DAOAggregateEvent aggEvt = (DAOAggregateEvent) evt.getNewValue(); - for (DAOEvent daoEvt : aggEvt.getEvents()) { - if (daoEvt instanceof TreeEvent) { - TreeEvent treeEvt = (TreeEvent) daoEvt; - TreeItemDTO item = getOrCreateRelevantChild(treeEvt); - if (item != null) { - if (treeEvt.isRefreshRequired()) { - update(); - break; - } else { - updateNodeData(item); - } - } - } - } + handleDAOAggregateEvent((DAOAggregateEvent) evt.getNewValue()); } }; @@ -83,6 +69,30 @@ public abstract class TreeChildFactory extends ChildFactory.Detachable> idMapping = new HashMap<>(); + /** + * Handles processing and updating due to an aggregate event. This method + * can be overridden for custom behavior while handling DAO aggregate + * events. + * + * @param aggEvt The aggregate event. + */ + protected void handleDAOAggregateEvent(DAOAggregateEvent aggEvt) { + for (DAOEvent daoEvt : aggEvt.getEvents()) { + if (daoEvt instanceof TreeEvent) { + TreeEvent treeEvt = (TreeEvent) daoEvt; + TreeItemDTO item = getOrCreateRelevantChild(treeEvt); + if (item != null) { + if (treeEvt.isRefreshRequired()) { + update(); + break; + } else { + updateNodeData(item); + } + } + } + } + } + @Override protected boolean createKeys(List toPopulate) { List> itemsList; @@ -98,9 +108,9 @@ public abstract class TreeChildFactory extends ChildFactory.Detachable(curItemsList); + itemsList = new ArrayList<>(curItemsList); } - + // update existing cached nodes List curResultIds = new ArrayList<>(); for (TreeItemDTO dto : itemsList) { diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java index e59903225b..373a520088 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/ViewsTypeFactory.java @@ -37,6 +37,8 @@ import org.sleuthkit.autopsy.mainui.datamodel.FileTypeSizeSearchParams; import org.sleuthkit.autopsy.mainui.datamodel.MainDAO; import org.sleuthkit.autopsy.mainui.datamodel.TreeResultsDTO; import org.sleuthkit.autopsy.mainui.datamodel.TreeResultsDTO.TreeItemDTO; +import org.sleuthkit.autopsy.mainui.datamodel.events.DAOAggregateEvent; +import org.sleuthkit.autopsy.mainui.datamodel.events.DAOEvent; import org.sleuthkit.autopsy.mainui.datamodel.events.TreeEvent; /** @@ -73,12 +75,32 @@ public class ViewsTypeFactory { return MainDAO.getInstance().getViewsDAO().getFileSizeCounts(this.dataSourceId); } + @Override + protected void handleDAOAggregateEvent(DAOAggregateEvent aggEvt) { + for (DAOEvent evt : aggEvt.getEvents()) { + if (evt instanceof TreeEvent) { + TreeResultsDTO.TreeItemDTO treeItem = super.getTypedTreeItem((TreeEvent) evt, FileTypeSizeSearchParams.class); + // if file type size search params has null filter, trigger full refresh + if (treeItem != null && treeItem.getSearchParams().getSizeFilter() == null) { + super.update(); + return; + } + } + } + + super.handleDAOAggregateEvent(aggEvt); + } + @Override protected TreeResultsDTO.TreeItemDTO getOrCreateRelevantChild(TreeEvent treeEvt) { TreeResultsDTO.TreeItemDTO originalTreeItem = super.getTypedTreeItem(treeEvt, FileTypeSizeSearchParams.class); if (originalTreeItem != null - && (this.dataSourceId == null || Objects.equals(this.dataSourceId, originalTreeItem.getSearchParams().getDataSourceId()))) { + // only create child if size filter is present (if null, update should be triggered separately) + && originalTreeItem.getSearchParams().getSizeFilter() != null + && (this.dataSourceId == null + || originalTreeItem.getSearchParams().getDataSourceId() == null + || Objects.equals(this.dataSourceId, originalTreeItem.getSearchParams().getDataSourceId()))) { // generate new type so that if it is a subtree event (i.e. keyword hits), the right tree item is created. FileTypeSizeSearchParams searchParam = originalTreeItem.getSearchParams(); @@ -159,7 +181,7 @@ public class ViewsTypeFactory { if (indexOfSlash >= 0) { mimePrefix = mimePrefix.substring(0, indexOfSlash); } - + return new TreeResultsDTO.TreeItemDTO<>( AnalysisResultSearchParam.getTypeId(), new FileTypeMimeSearchParams(mimePrefix, this.dataSourceId), @@ -326,11 +348,29 @@ public class ViewsTypeFactory { return MainDAO.getInstance().getViewsDAO().getFileExtCounts(this.childFilters, this.dataSourceId); } + @Override + protected void handleDAOAggregateEvent(DAOAggregateEvent aggEvt) { + for (DAOEvent evt : aggEvt.getEvents()) { + if (evt instanceof TreeEvent) { + TreeResultsDTO.TreeItemDTO treeItem = super.getTypedTreeItem((TreeEvent) evt, FileTypeExtensionsSearchParams.class); + // if search params has null filter, trigger full refresh + if (treeItem != null && treeItem.getSearchParams().getFilter() == null) { + super.update(); + return; + } + } + } + + super.handleDAOAggregateEvent(aggEvt); + } + @Override protected TreeResultsDTO.TreeItemDTO getOrCreateRelevantChild(TreeEvent treeEvt) { TreeResultsDTO.TreeItemDTO originalTreeItem = super.getTypedTreeItem(treeEvt, FileTypeExtensionsSearchParams.class); if (originalTreeItem != null + // if filter is null, this should trigger a full refresh which should be handled in handleDAOAggregateEvent + && originalTreeItem.getSearchParams().getFilter() != null && this.childFilters.contains(originalTreeItem.getSearchParams().getFilter()) && (this.dataSourceId == null || Objects.equals(this.dataSourceId, originalTreeItem.getSearchParams().getDataSourceId()))) {