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 java.util.stream.Stream;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
import org.apache.commons.lang3.StringUtils;
import org.openide.nodes.AbstractNode; import org.openide.nodes.AbstractNode;
import org.openide.explorer.ExplorerManager; import org.openide.explorer.ExplorerManager;
import org.openide.explorer.view.TreeView; import org.openide.explorer.view.TreeView;
@ -168,55 +169,127 @@ public class ViewContextAction extends AbstractAction {
public void actionPerformed(ActionEvent event) { public void actionPerformed(ActionEvent event) {
EventQueue.invokeLater(() -> { EventQueue.invokeLater(() -> {
/* Content parentContent = getParentContent(this.content);
* 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;
}
if ((parentContent != null) if ((parentContent != null) && (parentContent instanceof UnsupportedContent)) {
&& (parentContent instanceof UnsupportedContent)) {
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_unsupportedParent()); 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 logger.log(Level.WARNING, String.format("Could not navigate to unsupported content with id: %d", parentContent.getId())); //NON-NLS
return; return;
} }
/* // Get the "Data Sources" node from the tree view.
* Get the "Data Sources" node from the tree view.
*/
DirectoryTreeTopComponent treeViewTopComponent = DirectoryTreeTopComponent.findInstance(); DirectoryTreeTopComponent treeViewTopComponent = DirectoryTreeTopComponent.findInstance();
ExplorerManager treeViewExplorerMgr = treeViewTopComponent.getExplorerManager(); ExplorerManager treeViewExplorerMgr = treeViewTopComponent.getExplorerManager();
Node parentTreeViewNode = null; 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; SleuthkitCase skCase;
String dsname; String dsname;
try { try {
// get the objid/name of the datasource of the selected content. // get the objid/name of the datasource of the selected content.
skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
long contentDSObjid = content.getDataSource().getId(); long contentDSObjid = parentContent.getDataSource().getId();
DataSource datasource = skCase.getDataSource(contentDSObjid); DataSource datasource = skCase.getDataSource(contentDSObjid);
dsname = datasource.getName(); dsname = datasource.getName();
Children rootChildren = treeViewExplorerMgr.getRootContext().getChildren(); Children rootChildren = treeViewExplorerMgr.getRootContext().getChildren();
if (null != parentContent) {
// the tree view needs to be searched to find the parent treeview node. // 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 /* 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)" 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 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. 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()) .flatMap(rootNode -> getDataSourceLevelNodes(rootNode).stream())
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -230,52 +303,28 @@ public class ViewContextAction extends AbstractAction {
Node datasourceGroupingNode = treeNode.getChildren().findChild(DataSourceFilesNode.getNameIdentifier()); Node datasourceGroupingNode = treeNode.getChildren().findChild(DataSourceFilesNode.getNameIdentifier());
// check whether this is the data source we are looking for // check whether this is the data source we are looking for
parentTreeViewNode = findParentNodeInTree(parentContent, datasourceGroupingNode); Node parentTreeViewNode = findParentNodeInTree(parentContent, datasourceGroupingNode);
if (parentTreeViewNode != null) { if (parentTreeViewNode != null) {
// found the data source node // 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) { } catch (NoCurrentCaseException | TskDataException | TskCoreException ex) {
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindNode()); MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindNode());
logger.log(Level.SEVERE, "Failed to locate data source node in tree.", ex); //NON-NLS 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 * Set the child selection info of the parent tree node, then select
* the parent node in the tree view. The results view will retrieve * 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 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. * returns itself.
* *
* @param node The node. * @param node The node.
*
* @return The child nodes that are at the data source level. * @return The child nodes that are at the data source level.
*/ */
private List<Node> getDataSourceLevelNodes(Node node) { private List<Node> getDataSourceLevelNodes(Node node) {
if (node == null) { if (node == null) {
return Collections.emptyList(); return Collections.emptyList();
} else if (node.getLookup().lookup(Host.class) != null || } else if (node.getLookup().lookup(Host.class) != null
node.getLookup().lookup(Person.class) != null || || node.getLookup().lookup(Person.class) != null
DataSourcesNode.getNameIdentifier().equals(node.getLookup().lookup(String.class)) || || DataSourcesNode.getNameIdentifier().equals(node.getLookup().lookup(String.class))
PersonNode.getUnknownPersonId().equals(node.getLookup().lookup(String.class))) { || PersonNode.getUnknownPersonId().equals(node.getLookup().lookup(String.class))) {
Children children = node.getChildren(); Children children = node.getChildren();
Node[] childNodes = children == null ? null : children.getNodes(); Node[] childNodes = children == null ? null : children.getNodes(true);
if (childNodes == null) { if (childNodes == null) {
return Collections.emptyList(); return Collections.emptyList();
} }
return Stream.of(node.getChildren().getNodes()) return Stream.of(node.getChildren().getNodes(true))
.flatMap(parent -> getDataSourceLevelNodes(parent).stream()) .flatMap(parent -> getDataSourceLevelNodes(parent).stream())
.collect(Collectors.toList()); .collect(Collectors.toList());
} else { } else {
@ -351,6 +400,7 @@ public class ViewContextAction extends AbstractAction {
* *
* @param parentContent parent content for the content to be searched for * @param parentContent parent content for the content to be searched for
* @param node Node tree to search * @param node Node tree to search
*
* @return Node object of the matching parent, NULL if not found * @return Node object of the matching parent, NULL if not found
*/ */
private Node findParentNodeInTree(Content parentContent, Node node) { 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); Node dummyRootNode = new DirectoryTreeFilterNode(new AbstractNode(new RootContentChildren(contentBranch)), true);
Children ancestorChildren = dummyRootNode.getChildren(); 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 * Search the tree for the parent node. Note that this algorithm
* simply discards "extra" ancestor nodes not shown in the tree, * simply discards "extra" ancestor nodes not shown in the tree,
@ -387,8 +442,9 @@ public class ViewContextAction extends AbstractAction {
Node parentTreeViewNode = null; Node parentTreeViewNode = null;
for (int i = 0; i < ancestorChildren.getNodesCount(); i++) { for (int i = 0; i < ancestorChildren.getNodesCount(); i++) {
Node ancestorNode = ancestorChildren.getNodeAt(i); Node ancestorNode = ancestorChildren.getNodeAt(i);
for (int j = 0; j < treeNodeChildren.getNodesCount(); j++) { Node[] treeNodeChilds = treeNodeChildren.getNodes(true);
Node treeNode = treeNodeChildren.getNodeAt(j); for (int j = 0; j < treeNodeChilds.length; j++) {
Node treeNode = treeNodeChilds[j];
if (ancestorNode.getName().equals(treeNode.getName())) { if (ancestorNode.getName().equals(treeNode.getName())) {
parentTreeViewNode = treeNode; parentTreeViewNode = treeNode;
treeNodeChildren = treeNode.getChildren(); treeNodeChildren = treeNode.getChildren();