mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-20 11:26:53 +00:00
merge from 8183
This commit is contained in:
commit
c556d26f55
@ -41,7 +41,7 @@
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="0" gridWidth="7" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="17" weightX="0.0" weightY="0.0"/>
|
||||
<GridBagConstraints gridX="0" gridY="0" gridWidth="8" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="17" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
@ -53,7 +53,7 @@
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="8" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="5" insetsRight="5" anchor="13" weightX="0.0" weightY="0.0"/>
|
||||
<GridBagConstraints gridX="9" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="5" insetsRight="5" anchor="13" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
@ -69,7 +69,7 @@
|
||||
</AuxValues>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="9" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="5" insetsRight="0" anchor="13" weightX="0.0" weightY="0.0"/>
|
||||
<GridBagConstraints gridX="10" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="5" insetsRight="0" anchor="13" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
@ -252,7 +252,7 @@
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="2" gridWidth="10" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="1.0"/>
|
||||
<GridBagConstraints gridX="0" gridY="2" gridWidth="11" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="1.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
|
@ -878,7 +878,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);
|
||||
@ -886,7 +886,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);
|
||||
@ -894,7 +894,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);
|
||||
@ -1007,7 +1007,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;
|
||||
@ -1356,7 +1356,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}.",
|
||||
@ -1417,16 +1417,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
|
||||
|
@ -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.NodeSelectionInfo.ContentNodeSelectionInfo;
|
||||
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 ContentNodeSelectionInfo) {
|
||||
ContentNodeSelectionInfo selectedChildInfo = ((ContentNodeSelectionInfo) 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.
|
||||
((ContentNodeSelectionInfo) rootNode).setChildIdToSelect(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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;
|
||||
@ -127,6 +128,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 DirectoryTreeTopComponent.getOpenChildAction(abstractNode.getName(), sourceEm);
|
||||
}
|
||||
|
||||
// Once had a org.openide.nodes.ChildFactory$WaitFilterNode passed in
|
||||
if ((original instanceof DisplayableItemNode) == false) {
|
||||
return null;
|
||||
@ -356,43 +364,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -404,25 +376,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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
@ -899,6 +901,13 @@ 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) {
|
||||
// Remove node count from name if present
|
||||
displayName = originNode.getDisplayName().replaceAll("\\(([0-9]+|\\.\\.\\.)\\)$", "");
|
||||
} else {
|
||||
displayName = originNode.getName();
|
||||
}
|
||||
}
|
||||
dataResult.setPath(displayName);
|
||||
}
|
||||
@ -1677,5 +1686,114 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
public void addOnFinishedListener(PropertyChangeListener l) {
|
||||
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 || 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
|
||||
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(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) {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -46,12 +46,11 @@ 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.NodeSelectionInfo.ContentNodeSelectionInfo;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
@ -332,18 +331,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 ContentNodeSelectionInfo) {
|
||||
((ContentNodeSelectionInfo) parentTreeViewNode).setChildIdToSelect(childIdToSelect);
|
||||
}
|
||||
|
||||
TreeView treeView = treeViewTopComponent.getTree();
|
||||
treeView.expandNode(parentTreeViewNode);
|
||||
|
@ -19,11 +19,12 @@
|
||||
package org.sleuthkit.autopsy.mainui.datamodel;
|
||||
|
||||
import java.util.Objects;
|
||||
import org.sleuthkit.autopsy.mainui.nodes.NodeSelectionInfo.ContentNodeSelectionInfo;
|
||||
|
||||
/**
|
||||
* Key for content object in order to retrieve data from DAO.
|
||||
*/
|
||||
public class FileSystemContentSearchParam {
|
||||
public class FileSystemContentSearchParam implements ContentNodeSelectionInfo {
|
||||
|
||||
private static final String TYPE_ID = "FILE_SYSTEM_CONTENT";
|
||||
|
||||
@ -35,6 +36,10 @@ public class FileSystemContentSearchParam {
|
||||
}
|
||||
|
||||
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;
|
||||
@ -43,6 +48,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() {
|
||||
|
@ -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;
|
||||
|
@ -80,12 +80,23 @@ public class TreeResultsDTO<T> {
|
||||
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:
|
||||
case UNSPECIFIED:
|
||||
default:
|
||||
|
@ -25,6 +25,7 @@ import java.beans.PropertyChangeEvent;
|
||||
import java.sql.SQLException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@ -169,8 +170,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) {
|
||||
@ -189,8 +190,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()));
|
||||
}
|
||||
|
||||
private boolean isDeletedContentInvalidating(DeletedContentSearchParams params, DAOEvent eventData) {
|
||||
@ -433,11 +434,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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -478,7 +481,7 @@ public class ViewsDAO extends AbstractDAO {
|
||||
FileTypeExtensionsSearchParams.getTypeId(),
|
||||
new FileTypeExtensionsSearchParams(filter, dataSourceId),
|
||||
filter,
|
||||
filter.getDisplayName(),
|
||||
filter == null ? "" : filter.getDisplayName(),
|
||||
displayCount);
|
||||
}
|
||||
|
||||
@ -498,8 +501,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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -591,7 +600,7 @@ public class ViewsDAO extends AbstractDAO {
|
||||
FileTypeSizeSearchParams.getTypeId(),
|
||||
new FileTypeSizeSearchParams(filter, dataSourceId),
|
||||
filter,
|
||||
filter.getDisplayName(),
|
||||
filter == null ? "" : filter.getDisplayName(),
|
||||
displayCount);
|
||||
}
|
||||
|
||||
@ -920,8 +929,21 @@ public class ViewsDAO extends AbstractDAO {
|
||||
|
||||
@Override
|
||||
Set<? extends DAOEvent> handleIngestComplete() {
|
||||
return SubDAOUtils.getIngestCompleteEvents(this.treeCounts,
|
||||
SubDAOUtils.invalidateKeys(this.searchParamsCache,
|
||||
(searchParams) -> searchParamsMatchEvent(null, null, null, null, true, searchParams));
|
||||
|
||||
Set<? extends DAOEvent> treeEvts = SubDAOUtils.getIngestCompleteEvents(this.treeCounts,
|
||||
(daoEvt, count) -> createTreeItem(daoEvt, count));
|
||||
|
||||
Set<? extends DAOEvent> fileViewRefreshEvents = getFileViewRefreshEvents(null);
|
||||
|
||||
List<? extends DAOEvent> 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
|
||||
@ -932,56 +954,87 @@ public class ViewsDAO extends AbstractDAO {
|
||||
|
||||
@Override
|
||||
Set<DAOEvent> processEvent(PropertyChangeEvent evt) {
|
||||
AbstractFile af = DAOEventUtils.getFileFromFileEvent(evt);
|
||||
if (af == null) {
|
||||
return Collections.emptySet();
|
||||
} else if (hideKnownFilesInViewsTree() && FileKnown.KNOWN.equals(af.getKnown())) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
Long dsId = null;
|
||||
boolean dataSourceAdded = false;
|
||||
Set<FileExtSearchFilter> 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<FileExtSearchFilter> 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();
|
||||
|
||||
Set<DeletedContentFilter> deletedContentFilters = getMatchingDeletedContentFilters(af);
|
||||
// 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 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();
|
||||
Set<DeletedContentFilter> deletedContentFilters = getMatchingDeletedContentFilters(af);
|
||||
|
||||
// create a size mapping if size present in filters
|
||||
FileSizeFilter evtFileSize = 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() && deletedContentFilters.isEmpty() && evtMimeType == null && evtFileSize == null) {
|
||||
if (evtExtFilters == null || evtExtFilters.isEmpty() && deletedContentFilters.isEmpty() && evtMimeType == null && evtFileSize == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
SubDAOUtils.invalidateKeys(this.searchParamsCache,
|
||||
(Predicate<Object>) (searchParams) -> searchParamsMatchEvent(evtExtFilters, deletedContentFilters, evtMimeType, evtFileSize, dsId, searchParams));
|
||||
return invalidateAndReturnEvents(evtExtFilters, evtMimeType, evtFileSize, dsId, dataSourceAdded);
|
||||
}
|
||||
|
||||
return getDAOEvents(evtExtFilters, deletedContentFilters, 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<DAOEvent> invalidateAndReturnEvents(Set<FileExtSearchFilter> evtExtFilters, String evtMimeType,
|
||||
FileSizeFilter evtFileSize, Long dsId, boolean dataSourceAdded) {
|
||||
|
||||
SubDAOUtils.invalidateKeys(this.searchParamsCache,
|
||||
(searchParams) -> searchParamsMatchEvent(evtExtFilters, deletedContentFilters,
|
||||
evtMimeType, evtFileSize, dsId, dataSourceAdded, searchParams));
|
||||
|
||||
return getDAOEvents(evtExtFilters, deletedContentFilters, evtMimeType, evtFileSize, dsId, dataSourceAdded);
|
||||
}
|
||||
|
||||
private boolean searchParamsMatchEvent(Set<FileExtSearchFilter> evtExtFilters,
|
||||
Set<DeletedContentFilter> deletedContentFilters,
|
||||
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;
|
||||
@ -990,8 +1043,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 if (searchParams instanceof DeletedContentSearchParams) {
|
||||
DeletedContentSearchParams deletedParams = (DeletedContentSearchParams) searchParams;
|
||||
return deletedContentFilters.contains(deletedParams.getFilter())
|
||||
@ -1010,6 +1065,7 @@ public class ViewsDAO extends AbstractDAO {
|
||||
* @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.
|
||||
*/
|
||||
@ -1017,10 +1073,14 @@ public class ViewsDAO extends AbstractDAO {
|
||||
Set<DeletedContentFilter> deletedContentFilters,
|
||||
String mimeType,
|
||||
FileSizeFilter sizeFilter,
|
||||
long dsId) {
|
||||
long dsId,
|
||||
boolean dataSourceAdded) {
|
||||
|
||||
Stream<DAOEvent> extEvents = extFilters.stream()
|
||||
.map(extFilter -> new FileTypeExtensionsEvent(extFilter, dsId));
|
||||
List<DAOEvent> daoEvents = extFilters == null
|
||||
? new ArrayList<>()
|
||||
: extFilters.stream()
|
||||
.map(extFilter -> new FileTypeExtensionsEvent(extFilter, dsId))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Stream<DAOEvent> deletedEvents = deletedContentFilters.stream()
|
||||
.map(deletedFilter -> new DeletedContentEvent(deletedFilter, dsId));
|
||||
@ -1040,7 +1100,16 @@ 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<DAOEvent> forceRefreshEvents = (dataSourceAdded)
|
||||
? getFileViewRefreshEvents(dsId)
|
||||
: Collections.emptySet();
|
||||
|
||||
List<TreeEvent> 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());
|
||||
}
|
||||
@ -1067,6 +1136,22 @@ public class ViewsDAO extends AbstractDAO {
|
||||
return toRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<DAOEvent> 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.
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -235,7 +235,7 @@ public class AnalysisResultTypeFactory extends TreeChildFactory<AnalysisResultSe
|
||||
* @param itemData The data to display.
|
||||
*/
|
||||
public TreeSetTypeNode(TreeResultsDTO.TreeItemDTO<? extends AnalysisResultSetSearchParam> itemData) {
|
||||
super(itemData.getSearchParams().getArtifactType().getTypeName(),
|
||||
super(itemData.getSearchParams().getArtifactType().getTypeName() + "_SET_" + itemData.getSearchParams().getSetName(),
|
||||
getIconPath(itemData.getSearchParams().getArtifactType()),
|
||||
itemData,
|
||||
Children.LEAF,
|
||||
@ -274,7 +274,7 @@ public class AnalysisResultTypeFactory extends TreeChildFactory<AnalysisResultSe
|
||||
* @param itemData The data to display.
|
||||
*/
|
||||
public KeywordSetNode(TreeResultsDTO.TreeItemDTO<? extends AnalysisResultSetSearchParam> itemData) {
|
||||
super(itemData.getSearchParams().getArtifactType().getTypeName(),
|
||||
super("TSK_KEYWORD_HIT_SET_" + itemData.getSearchParams().getSetName(),
|
||||
getIconPath(itemData.getSearchParams().getArtifactType()),
|
||||
itemData,
|
||||
Children.create(new KeywordSearchTermFactory(itemData.getSearchParams()), true),
|
||||
|
@ -27,6 +27,7 @@ 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 +70,9 @@ abstract class BaseNode<S extends SearchResultsDTO, R extends BaseRowDTO> extend
|
||||
public Action[] getActions(boolean context) {
|
||||
return ActionsFactory.getActions(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action getPreferredAction() {
|
||||
return DirectoryTreeTopComponent.getOpenChildAction(getName());
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -118,7 +118,7 @@ public class DataArtifactTypeFactory extends TreeChildFactory<DataArtifactSearch
|
||||
* The account node that has nested children of account types.
|
||||
*/
|
||||
@Messages({
|
||||
"DataArtifactTypeFactory_AccountTypeParentNode_displayName=Communcation Accounts"
|
||||
"DataArtifactTypeFactory_AccountTypeParentNode_displayName=Communication Accounts"
|
||||
})
|
||||
static class AccountTypeParentNode extends TreeNode<DataArtifactSearchParam> {
|
||||
|
||||
|
@ -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<SearchResultsDTO, DirectoryRowDTO> {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
@ -159,6 +160,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.
|
||||
|
@ -47,6 +47,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;
|
||||
@ -241,7 +242,9 @@ public class FileSystemFactory extends TreeChildFactory<FileSystemContentSearchP
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"FileSystemFactory.FileSystemTreeNode.ExtractUnallocAction.text=Extract Unallocated Space to Single Files"})
|
||||
public abstract static class FileSystemTreeNode extends TreeNode<FileSystemContentSearchParam> implements ActionContext {
|
||||
public abstract static class FileSystemTreeNode extends TreeNode<FileSystemContentSearchParam> implements ActionContext, ContentNodeSelectionInfo {
|
||||
|
||||
private Long childContentToSelect;
|
||||
|
||||
protected FileSystemTreeNode(String icon, TreeResultsDTO.TreeItemDTO<? extends FileSystemContentSearchParam> itemData, Children children, Lookup lookup) {
|
||||
super(ContentNodeUtil.getContentName(itemData.getSearchParams().getContentObjectId()), icon, itemData, children, lookup);
|
||||
@ -264,6 +267,7 @@ public class FileSystemFactory extends TreeChildFactory<FileSystemContentSearchP
|
||||
|
||||
@Override
|
||||
public void respondSelection(DataResultTopComponent dataResultPanel) {
|
||||
getItemData().getSearchParams().setChildIdToSelect(childContentToSelect);
|
||||
dataResultPanel.displayFileSystemContent(this.getItemData().getSearchParams());
|
||||
}
|
||||
|
||||
@ -273,6 +277,16 @@ public class FileSystemFactory extends TreeChildFactory<FileSystemContentSearchP
|
||||
public Action[] getActions(boolean context) {
|
||||
return ActionsFactory.getActions(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChildIdToSelect(Long content) {
|
||||
childContentToSelect = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getChildIdToSelect() {
|
||||
return childContentToSelect;
|
||||
}
|
||||
}
|
||||
|
||||
static class ImageTreeNode extends FileSystemTreeNode {
|
||||
@ -346,7 +360,7 @@ public class FileSystemFactory extends TreeChildFactory<FileSystemContentSearchP
|
||||
Pool pool;
|
||||
|
||||
PoolTreeNode(Pool pool, TreeResultsDTO.TreeItemDTO<? extends FileSystemContentSearchParam> itemData) {
|
||||
super(NodeIconUtil.VOLUME.getPath(),
|
||||
super(NodeIconUtil.POOL.getPath(),
|
||||
itemData,
|
||||
createChildrenForContent(itemData.getSearchParams().getContentObjectId()),
|
||||
ContentNodeUtil.getLookup(pool));
|
||||
|
52
Core/src/org/sleuthkit/autopsy/mainui/nodes/NodeSelectionInfo.java
Executable file
52
Core/src/org/sleuthkit/autopsy/mainui/nodes/NodeSelectionInfo.java
Executable file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> 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 NodeSelectionInfo {
|
||||
/**
|
||||
* Determine of the given node represents the child content to
|
||||
* be selected.
|
||||
*
|
||||
* @param node
|
||||
*
|
||||
* @return True if there is a match.
|
||||
*/
|
||||
boolean matches(Node node);
|
||||
|
||||
public interface ContentNodeSelectionInfo extends NodeSelectionInfo{
|
||||
void setChildIdToSelect(Long contentId);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@ -21,18 +21,22 @@ package org.sleuthkit.autopsy.mainui.nodes;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||
import org.sleuthkit.autopsy.mainui.datamodel.SearchResultsDTO;
|
||||
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 {
|
||||
public class SearchResultRootNode extends AbstractNode implements ContentNodeSelectionInfo{
|
||||
|
||||
private final SearchResultChildFactory factory;
|
||||
|
||||
// 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 SearchResultRootNode(SearchResultsDTO initialResults) {
|
||||
this(initialResults, new SearchResultChildFactory(initialResults));
|
||||
@ -45,7 +49,17 @@ public class SearchResultRootNode extends AbstractNode {
|
||||
setName(initialResults.getTypeId());
|
||||
setDisplayName(initialResults.getDisplayName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChildIdToSelect(Long contentId) {
|
||||
childContentToSelect = contentId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getChildIdToSelect() {
|
||||
return childContentToSelect;
|
||||
}
|
||||
|
||||
@Messages({
|
||||
"SearchResultRootNode_noDesc=No Description",
|
||||
"SearchResultRootNode_createSheet_type_name=Name",
|
||||
|
@ -48,21 +48,7 @@ public abstract class TreeChildFactory<T> extends ChildFactory.Detachable<Object
|
||||
|
||||
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
|
||||
if (evt.getNewValue() instanceof DAOAggregateEvent) {
|
||||
DAOAggregateEvent aggEvt = (DAOAggregateEvent) evt.getNewValue();
|
||||
for (DAOEvent daoEvt : aggEvt.getEvents()) {
|
||||
if (daoEvt instanceof TreeEvent) {
|
||||
TreeEvent treeEvt = (TreeEvent) daoEvt;
|
||||
TreeItemDTO<? extends T> 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<T> extends ChildFactory.Detachable<Object
|
||||
// maps the Node key (ID) to its DTO
|
||||
private Map<Object, TreeItemDTO<? extends T>> 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<? extends T> item = getOrCreateRelevantChild(treeEvt);
|
||||
if (item != null) {
|
||||
if (treeEvt.isRefreshRequired()) {
|
||||
update();
|
||||
break;
|
||||
} else {
|
||||
updateNodeData(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<Object> toPopulate) {
|
||||
List<TreeItemDTO<? extends T>> itemsList;
|
||||
@ -98,9 +108,9 @@ public abstract class TreeChildFactory<T> extends ChildFactory.Detachable<Object
|
||||
}
|
||||
// make copy to avoid concurrent modification
|
||||
synchronized (resultsUpdateLock) {
|
||||
itemsList = new ArrayList<>(curItemsList);
|
||||
itemsList = new ArrayList<>(curItemsList);
|
||||
}
|
||||
|
||||
|
||||
// update existing cached nodes
|
||||
List<Object> curResultIds = new ArrayList<>();
|
||||
for (TreeItemDTO<? extends T> dto : itemsList) {
|
||||
|
@ -22,6 +22,7 @@ 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.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
@ -30,6 +31,7 @@ import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.mainui.datamodel.TreeResultsDTO.TreeDisplayCount;
|
||||
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
|
||||
import org.sleuthkit.autopsy.mainui.datamodel.TreeResultsDTO.TreeItemDTO;
|
||||
|
||||
/**
|
||||
@ -140,6 +142,19 @@ public abstract class TreeNode<T> 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tree node for displaying static content in the tree.
|
||||
@ -159,6 +174,6 @@ public abstract class TreeNode<T> extends AbstractNode implements SelectionRespo
|
||||
|
||||
public StaticTreeNode(String nodeName, String displayName, String icon, Children children, Lookup lookup) {
|
||||
super(nodeName, icon, new TreeItemDTO<String>(nodeName, nodeName, nodeName, displayName, TreeDisplayCount.NOT_SHOWN), children, lookup);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,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;
|
||||
import org.sleuthkit.autopsy.mainui.nodes.TreeNode.StaticTreeNode;
|
||||
|
||||
@ -261,12 +263,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<FileTypeSizeSearchParams> 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<? extends FileTypeSizeSearchParams> getOrCreateRelevantChild(TreeEvent treeEvt) {
|
||||
TreeResultsDTO.TreeItemDTO<FileTypeSizeSearchParams> 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();
|
||||
@ -514,11 +536,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<FileTypeExtensionsSearchParams> 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<? extends FileTypeExtensionsSearchParams> getOrCreateRelevantChild(TreeEvent treeEvt) {
|
||||
TreeResultsDTO.TreeItemDTO<FileTypeExtensionsSearchParams> 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()))) {
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user