Merge pull request #7042 from gdicristofaro/7696-viewContextFix

7696 view context fix
This commit is contained in:
Richard Cordovano 2021-06-17 11:16:59 -04:00 committed by GitHub
commit e222445609
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -31,6 +31,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.AbstractAction;
import org.apache.commons.lang3.StringUtils;
import org.openide.nodes.AbstractNode;
import org.openide.explorer.ExplorerManager;
import org.openide.explorer.view.TreeView;
@ -168,55 +169,127 @@ public class ViewContextAction extends AbstractAction {
public void actionPerformed(ActionEvent event) {
EventQueue.invokeLater(() -> {
/*
* Get the parent content for the content to be selected in the
* results view. If the parent content is null, then the specified
* content is a data source, and the parent tree view node is the
* "Data Sources" node. Otherwise, the tree view needs to be
* searched to find the parent treeview node.
*/
Content parentContent = null;
try {
parentContent = content.getParent();
} catch (TskCoreException ex) {
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindDirectory());
logger.log(Level.SEVERE, String.format("Could not get parent of Content object: %s", content), ex); //NON-NLS
return;
}
Content parentContent = getParentContent(this.content);
if ((parentContent != null)
&& (parentContent instanceof UnsupportedContent)) {
if ((parentContent != null) && (parentContent instanceof UnsupportedContent)) {
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_unsupportedParent());
logger.log(Level.WARNING, String.format("Could not navigate to unsupported content with id: %d", parentContent.getId())); //NON-NLS
return;
}
/*
* Get the "Data Sources" node from the tree view.
*/
// Get the "Data Sources" node from the tree view.
DirectoryTreeTopComponent treeViewTopComponent = DirectoryTreeTopComponent.findInstance();
ExplorerManager treeViewExplorerMgr = treeViewTopComponent.getExplorerManager();
Node parentTreeViewNode = null;
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) { // 'Group by Data Source' view
if (parentContent != null) {
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
parentTreeViewNode = getParentNodeGroupedByPersonHost(treeViewExplorerMgr, parentContent);
} else {
parentTreeViewNode = getParentNodeGroupedByDataSource(treeViewExplorerMgr, parentContent);
}
}
// if no node is found, report error and do nothing
if (parentTreeViewNode == null) {
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindNode());
logger.log(Level.SEVERE, "Failed to locate data source node in tree."); //NON-NLS
return;
}
setNodeSelection(this.content, parentTreeViewNode, treeViewTopComponent, treeViewExplorerMgr);
});
}
/**
* Get the parent content for the content to be selected in the results
* view. If the parent content is null, then the specified content is a data
* source, and the parent tree view node is the "Data Sources" node.
* Otherwise, the tree view needs to be searched to find the parent treeview
* node.
*
* @param content The content whose parent will be returned. If this item is
* a datasource, it will be returned.
*
* @return The content if content is a data source or the parent of this
* content.
*/
private Content getParentContent(Content content) {
try {
return (content instanceof DataSource)
? content
: content.getParent();
} catch (TskCoreException ex) {
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindDirectory());
logger.log(Level.SEVERE, String.format("Could not get parent of Content object: %s", content), ex); //NON-NLS
return null;
}
}
/**
* Returns the node in the tree related to the parentContent or null if
* can't be found. This method should be used when view is grouped by data
* source.
*
* @param treeViewExplorerMgr The explorer manager.
* @param parentContent The content whose equivalent node will be
* returned if found.
*
* @return The node if found or null.
*/
private Node getParentNodeGroupedByDataSource(ExplorerManager treeViewExplorerMgr, Content parentContent) {
// Classic view
// Start the search at the DataSourcesNode
Children rootChildren = treeViewExplorerMgr.getRootContext().getChildren();
Node rootDsNode = rootChildren == null ? null : rootChildren.findChild(DataSourcesNode.getNameIdentifier());
if (rootDsNode != null) {
for (Node dataSourceLevelNode : getDataSourceLevelNodes(rootDsNode)) {
DataSource dataSource = dataSourceLevelNode.getLookup().lookup(DataSource.class);
if (dataSource != null) {
// the tree view needs to be searched to find the parent treeview node.
Node potentialParentTreeViewNode = findParentNodeInTree(parentContent, dataSourceLevelNode);
if (potentialParentTreeViewNode != null) {
return potentialParentTreeViewNode;
}
}
}
}
return null;
}
/**
* Returns the node in the tree related to the parentContent or null if
* can't be found. This method should be used when view is grouped by
* hosts/persons.
*
* @param treeViewExplorerMgr The explorer manager.
* @param parentContent The content whose equivalent node will be
* returned if found.
*
* @return The node if found or null.
*/
private Node getParentNodeGroupedByPersonHost(ExplorerManager treeViewExplorerMgr, Content parentContent) {
// 'Group by Data Source' view
SleuthkitCase skCase;
String dsname;
try {
// get the objid/name of the datasource of the selected content.
skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
long contentDSObjid = content.getDataSource().getId();
long contentDSObjid = parentContent.getDataSource().getId();
DataSource datasource = skCase.getDataSource(contentDSObjid);
dsname = datasource.getName();
Children rootChildren = treeViewExplorerMgr.getRootContext().getChildren();
if (null != parentContent) {
// the tree view needs to be searched to find the parent treeview node.
/* NOTE: we can't do a lookup by data source name here, becase if there
are multiple data sources with the same name, then "getChildren().findChild(dsname)"
simply returns the first one that it finds. Instead we have to loop over all
data sources with that name, and make sure we find the correct one.
*/
List<Node> dataSourceLevelNodes = Stream.of(rootChildren.getNodes())
List<Node> dataSourceLevelNodes = Stream.of(rootChildren.getNodes(true))
.flatMap(rootNode -> getDataSourceLevelNodes(rootNode).stream())
.collect(Collectors.toList());
@ -230,52 +303,28 @@ public class ViewContextAction extends AbstractAction {
Node datasourceGroupingNode = treeNode.getChildren().findChild(DataSourceFilesNode.getNameIdentifier());
// check whether this is the data source we are looking for
parentTreeViewNode = findParentNodeInTree(parentContent, datasourceGroupingNode);
Node parentTreeViewNode = findParentNodeInTree(parentContent, datasourceGroupingNode);
if (parentTreeViewNode != null) {
// found the data source node
break;
return parentTreeViewNode;
}
}
} else {
/* If the parent content is null, then the specified
* content is a data source, and the parent tree view node is the
* "Data Sources" node. */
Node datasourceGroupingNode = rootChildren.findChild(dsname);
if (!Objects.isNull(datasourceGroupingNode)) {
Children dsChildren = datasourceGroupingNode.getChildren();
parentTreeViewNode = dsChildren.findChild(DataSourceFilesNode.getNameIdentifier());
}
}
if (parentTreeViewNode == null) {
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindNode());
logger.log(Level.SEVERE, "Failed to locate data source node in tree."); //NON-NLS
return;
}
} catch (NoCurrentCaseException | TskDataException | TskCoreException ex) {
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindNode());
logger.log(Level.SEVERE, "Failed to locate data source node in tree.", ex); //NON-NLS
return;
}
} else { // Classic view
// Start the search at the DataSourcesNode
Children rootChildren = treeViewExplorerMgr.getRootContext().getChildren();
Node rootDsNode = rootChildren == null ? null : rootChildren.findChild(DataSourcesNode.getNameIdentifier());
if (rootDsNode != null) {
for (Node dataSourceLevelNode : getDataSourceLevelNodes(rootDsNode)) {
DataSource dataSource = dataSourceLevelNode.getLookup().lookup(DataSource.class);
if (dataSource != null) {
// the tree view needs to be searched to find the parent treeview node.
Node potentialParentTreeViewNode = findParentNodeInTree(parentContent, dataSourceLevelNode);
if (potentialParentTreeViewNode != null) {
parentTreeViewNode = potentialParentTreeViewNode;
break;
}
}
}
}
}
return null;
}
/**
* Set the node selection in the tree.
* @param content The content to select.
* @param parentTreeViewNode The node that is the parent of the content.
* @param treeViewTopComponent The DirectoryTreeTopComponent.
* @param treeViewExplorerMgr The ExplorerManager.
*/
private void setNodeSelection(Content content, Node parentTreeViewNode, DirectoryTreeTopComponent treeViewTopComponent, ExplorerManager treeViewExplorerMgr) {
/*
* Set the child selection info of the parent tree node, then select
* the parent node in the tree view. The results view will retrieve
@ -314,7 +363,6 @@ public class ViewContextAction extends AbstractAction {
logger.log(Level.SEVERE, "Failed to select the parent node in the tree view", ex); //NON-NLS
}
}
});
}
/**
@ -322,22 +370,23 @@ public class ViewContextAction extends AbstractAction {
* returns itself.
*
* @param node The node.
*
* @return The child nodes that are at the data source level.
*/
private List<Node> getDataSourceLevelNodes(Node node) {
if (node == null) {
return Collections.emptyList();
} else if (node.getLookup().lookup(Host.class) != null ||
node.getLookup().lookup(Person.class) != null ||
DataSourcesNode.getNameIdentifier().equals(node.getLookup().lookup(String.class)) ||
PersonNode.getUnknownPersonId().equals(node.getLookup().lookup(String.class))) {
} else if (node.getLookup().lookup(Host.class) != null
|| node.getLookup().lookup(Person.class) != null
|| DataSourcesNode.getNameIdentifier().equals(node.getLookup().lookup(String.class))
|| PersonNode.getUnknownPersonId().equals(node.getLookup().lookup(String.class))) {
Children children = node.getChildren();
Node[] childNodes = children == null ? null : children.getNodes();
Node[] childNodes = children == null ? null : children.getNodes(true);
if (childNodes == null) {
return Collections.emptyList();
}
return Stream.of(node.getChildren().getNodes())
return Stream.of(node.getChildren().getNodes(true))
.flatMap(parent -> getDataSourceLevelNodes(parent).stream())
.collect(Collectors.toList());
} else {
@ -351,6 +400,7 @@ public class ViewContextAction extends AbstractAction {
*
* @param parentContent parent content for the content to be searched for
* @param node Node tree to search
*
* @return Node object of the matching parent, NULL if not found
*/
private Node findParentNodeInTree(Content parentContent, Node node) {
@ -377,6 +427,11 @@ public class ViewContextAction extends AbstractAction {
Node dummyRootNode = new DirectoryTreeFilterNode(new AbstractNode(new RootContentChildren(contentBranch)), true);
Children ancestorChildren = dummyRootNode.getChildren();
// if content is the data source provided, return that.
if (ancestorChildren.getNodesCount() == 1 && StringUtils.equals(ancestorChildren.getNodeAt(0).getName(), node.getName())) {
return node;
}
/*
* Search the tree for the parent node. Note that this algorithm
* simply discards "extra" ancestor nodes not shown in the tree,
@ -387,8 +442,9 @@ public class ViewContextAction extends AbstractAction {
Node parentTreeViewNode = null;
for (int i = 0; i < ancestorChildren.getNodesCount(); i++) {
Node ancestorNode = ancestorChildren.getNodeAt(i);
for (int j = 0; j < treeNodeChildren.getNodesCount(); j++) {
Node treeNode = treeNodeChildren.getNodeAt(j);
Node[] treeNodeChilds = treeNodeChildren.getNodes(true);
for (int j = 0; j < treeNodeChilds.length; j++) {
Node treeNode = treeNodeChilds[j];
if (ancestorNode.getName().equals(treeNode.getName())) {
parentTreeViewNode = treeNode;
treeNodeChildren = treeNode.getChildren();