Autopsy  4.14.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ViewContextAction.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2018 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.directorytree;
20 
21 import java.awt.EventQueue;
22 import java.awt.event.ActionEvent;
23 import java.beans.PropertyVetoException;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.List;
27 import java.util.Objects;
28 import java.util.logging.Level;
30 import javax.swing.AbstractAction;
31 import org.openide.nodes.AbstractNode;
32 import org.openide.explorer.ExplorerManager;
33 import org.openide.explorer.view.TreeView;
34 import org.openide.nodes.Children;
35 import org.openide.nodes.Node;
36 import org.openide.util.NbBundle.Messages;
49 import org.sleuthkit.datamodel.AbstractFile;
50 import org.sleuthkit.datamodel.BlackboardArtifact;
51 import org.sleuthkit.datamodel.Content;
52 import org.sleuthkit.datamodel.ContentVisitor;
53 import org.sleuthkit.datamodel.DataSource;
54 import org.sleuthkit.datamodel.FileSystem;
55 import org.sleuthkit.datamodel.SleuthkitCase;
56 import org.sleuthkit.datamodel.TskCoreException;
57 import org.sleuthkit.datamodel.TskData;
58 import org.sleuthkit.datamodel.TskDataException;
59 import org.sleuthkit.datamodel.VolumeSystem;
60 
67 public class ViewContextAction extends AbstractAction {
68 
69  private static final long serialVersionUID = 1L;
70  private static final Logger logger = Logger.getLogger(ViewContextAction.class.getName());
71  private final Content content;
72 
82  public ViewContextAction(String displayName, BlackboardArtifactNode artifactNode) {
83  super(displayName);
84  this.content = artifactNode.getLookup().lookup(Content.class);
85  if (this.content != null && this.content instanceof AbstractFile) {
86  AbstractFile file = (AbstractFile) content;
87  //disable the action if the content is a file and the file is hidden
88  if ((TskData.FileKnown.KNOWN == file.getKnown() && UserPreferences.hideKnownFilesInDataSourcesTree())
89  || (TskData.TSK_DB_FILES_TYPE_ENUM.SLACK == file.getType() && UserPreferences.hideSlackFilesInDataSourcesTree())) {
90  this.setEnabled(false);
91  }
92  }
93  }
94 
105  public ViewContextAction(String displayName, AbstractFsContentNode<? extends AbstractFile> fileSystemContentNode) {
106  super(displayName);
107  this.content = fileSystemContentNode.getLookup().lookup(Content.class);
108  }
109 
120  public ViewContextAction(String displayName, AbstractAbstractFileNode<? extends AbstractFile> abstractAbstractFileNode) {
121  super(displayName);
122  this.content = abstractAbstractFileNode.getLookup().lookup(Content.class);
123  }
124 
134  public ViewContextAction(String displayName, Content content) {
135  super(displayName);
136  this.content = content;
137  }
138 
147  @Override
148  @Messages({
149  "ViewContextAction.errorMessage.cannotFindDirectory=Failed to locate directory.",
150  "ViewContextAction.errorMessage.cannotSelectDirectory=Failed to select directory in tree.",
151  "ViewContextAction.errorMessage.cannotFindNode=Failed to locate data source node in tree."
152  })
153  public void actionPerformed(ActionEvent event) {
154  EventQueue.invokeLater(() -> {
155 
156  /*
157  * Get the parent content for the content to be selected in the
158  * results view. If the parent content is null, then the specified
159  * content is a data source, and the parent tree view node is the
160  * "Data Sources" node. Otherwise, the tree view needs to be
161  * searched to find the parent treeview node.
162  */
163  Content parentContent = null;
164  try {
165  parentContent = content.getParent();
166  } catch (TskCoreException ex) {
167  MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindDirectory());
168  logger.log(Level.SEVERE, String.format("Could not get parent of Content object: %s", content), ex); //NON-NLS
169  return;
170  }
171 
172  /*
173  * Get the "Data Sources" node from the tree view.
174  */
176  ExplorerManager treeViewExplorerMgr = treeViewTopComponent.getExplorerManager();
177  Node parentTreeViewNode = null;
178  if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) { // 'Group by Data Source' view
179 
180  SleuthkitCase skCase;
181  String dsname;
182  try {
183  // get the objid/name of the datasource of the selected content.
185  long contentDSObjid = content.getDataSource().getId();
186  DataSource datasource = skCase.getDataSource(contentDSObjid);
187  dsname = datasource.getName();
188  Children rootChildren = treeViewExplorerMgr.getRootContext().getChildren();
189 
190  if (null != parentContent) {
191  // the tree view needs to be searched to find the parent treeview node.
192  /* NOTE: we can't do a lookup by data source name here, becase if there
193  are multiple data sources with the same name, then "getChildren().findChild(dsname)"
194  simply returns the first one that it finds. Instead we have to loop over all
195  data sources with that name, and make sure we find the correct one.
196  */
197  for (int i = 0; i < rootChildren.getNodesCount(); i++) {
198  // in the root, look for a data source node with the name of interest
199  Node treeNode = rootChildren.getNodeAt(i);
200  if (!(treeNode.getName().equals(dsname))) {
201  continue;
202  }
203 
204  // for this data source, get the "Data Sources" child node
205  Node datasourceGroupingNode = treeNode.getChildren().findChild(DataSourcesNode.NAME);
206 
207  // check whether this is the data source we are looking for
208  parentTreeViewNode = findParentNodeInTree(parentContent, datasourceGroupingNode);
209  if (parentTreeViewNode != null) {
210  // found the data source node
211  break;
212  }
213  }
214  } else {
215  /* If the parent content is null, then the specified
216  * content is a data source, and the parent tree view node is the
217  * "Data Sources" node. */
218  Node datasourceGroupingNode = rootChildren.findChild(dsname);
219  if (!Objects.isNull(datasourceGroupingNode)) {
220  Children dsChildren = datasourceGroupingNode.getChildren();
221  parentTreeViewNode = dsChildren.findChild(DataSourcesNode.NAME);
222  }
223  }
224 
225  if (parentTreeViewNode == null) {
226  MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindNode());
227  logger.log(Level.SEVERE, "Failed to locate data source node in tree."); //NON-NLS
228  return;
229  }
230  } catch (NoCurrentCaseException | TskDataException | TskCoreException ex) {
231  MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindNode());
232  logger.log(Level.SEVERE, "Failed to locate data source node in tree.", ex); //NON-NLS
233  return;
234  }
235  } else { // Classic view
236  // Start the search at the DataSourcesNode
237  parentTreeViewNode = treeViewExplorerMgr.getRootContext().getChildren().findChild(DataSourcesNode.NAME);
238 
239  if (null != parentContent) {
240  // the tree view needs to be searched to find the parent treeview node.
241  Node potentialParentTreeViewNode = findParentNodeInTree(parentContent, parentTreeViewNode);
242  if (potentialParentTreeViewNode != null) {
243  parentTreeViewNode = potentialParentTreeViewNode;
244  }
245  }
246  }
247 
248  /*
249  * Set the child selection info of the parent tree node, then select
250  * the parent node in the tree view. The results view will retrieve
251  * this selection info and use it to complete this action when the
252  * tree view top component responds to the selection of the parent
253  * node by pushing it into the results view top component.
254  */
255  DisplayableItemNode undecoratedParentNode = (DisplayableItemNode) ((DirectoryTreeFilterNode) parentTreeViewNode).getOriginal();
256  undecoratedParentNode.setChildNodeSelectionInfo(new ContentNodeSelectionInfo(content));
257  if (content instanceof BlackboardArtifact) {
258  BlackboardArtifact artifact = ((BlackboardArtifact) content);
259  long associatedId = artifact.getObjectID();
260  try {
261  Content associatedFileContent = artifact.getSleuthkitCase().getContentById(associatedId);
262  undecoratedParentNode.setChildNodeSelectionInfo(new ContentNodeSelectionInfo(associatedFileContent));
263  } catch (TskCoreException ex) {
264  logger.log(Level.SEVERE, "Could not find associated content from artifact with id %d", artifact.getId());
265  }
266  }
267 
268  TreeView treeView = treeViewTopComponent.getTree();
269  treeView.expandNode(parentTreeViewNode);
270  if (treeViewTopComponent.getSelectedNode().equals(parentTreeViewNode)) {
271  //In the case where our tree view already has the destination directory selected
272  //due to an optimization in the ExplorerManager.setExploredContextAndSelection method
273  //the property change we listen for to call DirectoryTreeTopComponent.respondSelection
274  //will not be sent so we call it manually ourselves after making
275  //the directory listing the active tab.
276  treeViewTopComponent.setDirectoryListingActive();
277  treeViewTopComponent.respondSelection(treeViewExplorerMgr.getSelectedNodes(), new Node[]{parentTreeViewNode});
278  } else {
279  try {
280  treeViewExplorerMgr.setExploredContextAndSelection(parentTreeViewNode, new Node[]{parentTreeViewNode});
281  } catch (PropertyVetoException ex) {
282  MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotSelectDirectory());
283  logger.log(Level.SEVERE, "Failed to select the parent node in the tree view", ex); //NON-NLS
284  }
285  }
286  });
287  }
288 
297  private Node findParentNodeInTree(Content parentContent, Node node) {
298  /*
299  * Get an ordered list of the ancestors of the specified
300  * content, starting with its data source.
301  *
302  */
303  AncestorVisitor ancestorVisitor = new AncestorVisitor();
304  List<Content> contentBranch = parentContent.accept(ancestorVisitor);
305  Collections.reverse(contentBranch);
306 
318  Node dummyRootNode = new DirectoryTreeFilterNode(new AbstractNode(new RootContentChildren(contentBranch)), true);
319  Children ancestorChildren = dummyRootNode.getChildren();
320 
321  /*
322  * Search the tree for the parent node. Note that this algorithm
323  * simply discards "extra" ancestor nodes not shown in the tree,
324  * such as the root directory of the file system for file system
325  * content.
326  */
327  Children treeNodeChildren = node.getChildren();
328  Node parentTreeViewNode = null;
329  for (int i = 0; i < ancestorChildren.getNodesCount(); i++) {
330  Node ancestorNode = ancestorChildren.getNodeAt(i);
331  for (int j = 0; j < treeNodeChildren.getNodesCount(); j++) {
332  Node treeNode = treeNodeChildren.getNodeAt(j);
333  if (ancestorNode.getName().equals(treeNode.getName())) {
334  parentTreeViewNode = treeNode;
335  treeNodeChildren = treeNode.getChildren();
336  break;
337  }
338  }
339  }
340  return parentTreeViewNode;
341  }
342 
348  private static class AncestorVisitor extends ContentVisitor.Default<List<Content>> {
349 
350  List<Content> lineage = new ArrayList<>();
351 
352  @Override
353  protected List<Content> defaultVisit(Content content) {
354  lineage.add(content);
355  Content parent = null;
356  try {
357  parent = content.getParent();
358  } catch (TskCoreException ex) {
359  logger.log(Level.SEVERE, String.format("Could not get parent of Content object: %s", content), ex); //NON-NLS
360  }
361  return parent == null ? lineage : parent.accept(this);
362  }
363 
364  @Override
365  public List<Content> visit(VolumeSystem volumeSystem) {
366  /*
367  * Volume systems are not shown in the tree view. This is not
368  * strictly necesssary given the algorithm above, but it is a simple
369  * optimization.
370  */
371  return skipToParent(volumeSystem);
372  }
373 
374  @Override
375  public List<Content> visit(FileSystem fileSystem) {
376  /*
377  * File systems are not shown in the tree view. This is not strictly
378  * necesssary given the algorithm above, but it is a simple
379  * optimization.
380  */
381  return skipToParent(fileSystem);
382  }
383 
384  private List<Content> skipToParent(Content content) {
385  Content parent = null;
386  try {
387  parent = content.getParent();
388  } catch (TskCoreException ex) {
389  logger.log(Level.SEVERE, String.format("Could not get parent of Content object: %s", content), ex); //NON-NLS
390  }
391  return parent == null ? lineage : parent.accept(this);
392  }
393  }
394 
395 }
ViewContextAction(String displayName, Content content)
ViewContextAction(String displayName, BlackboardArtifactNode artifactNode)
ViewContextAction(String displayName, AbstractFsContentNode<?extends AbstractFile > fileSystemContentNode)
Node findParentNodeInTree(Content parentContent, Node node)
ViewContextAction(String displayName, AbstractAbstractFileNode<?extends AbstractFile > abstractAbstractFileNode)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
void setChildNodeSelectionInfo(NodeSelectionInfo selectedChildNodeInfo)
static synchronized DirectoryTreeTopComponent findInstance()

Copyright © 2012-2020 Basis Technology. Generated on: Wed Apr 8 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.