19 package org.sleuthkit.autopsy.directorytree;
21 import java.awt.Cursor;
22 import java.awt.EventQueue;
23 import java.beans.PropertyChangeEvent;
24 import java.beans.PropertyChangeListener;
25 import java.beans.PropertyVetoException;
26 import java.io.IOException;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.HashSet;
30 import java.util.LinkedList;
31 import java.util.List;
32 import java.util.logging.Level;
33 import java.util.prefs.PreferenceChangeEvent;
34 import java.util.prefs.PreferenceChangeListener;
35 import javax.swing.Action;
36 import javax.swing.SwingUtilities;
37 import javax.swing.tree.TreeSelectionModel;
38 import org.openide.explorer.ExplorerManager;
39 import org.openide.explorer.ExplorerUtils;
40 import org.openide.explorer.view.BeanTreeView;
41 import org.openide.explorer.view.TreeView;
42 import org.openide.nodes.AbstractNode;
43 import org.openide.nodes.Children;
44 import org.openide.nodes.Node;
45 import org.openide.nodes.NodeNotFoundException;
46 import org.openide.nodes.NodeOp;
47 import org.openide.util.NbBundle;
48 import org.openide.windows.TopComponent;
49 import org.openide.windows.WindowManager;
88 private final transient ExplorerManager
em =
new ExplorerManager();
91 "DirectoryTreeTopComponent.title.text"));
94 private static final String
PREFERRED_ID =
"DirectoryTreeTopComponent";
105 ((BeanTreeView)
jScrollPane1).setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
107 putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.TRUE);
112 associateLookup(ExplorerUtils.createLookup(em, getActionMap()));
115 this.backList =
new LinkedList<>();
116 this.forwardList =
new LinkedList<>();
127 public void preferenceChange(PreferenceChangeEvent evt) {
128 switch (evt.getKey()) {
139 this.em.addPropertyChangeListener(
this);
145 this.dataResult.requestActive();
149 this.dataResult.
open();
171 backButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/directorytree/btn_step_back.png")));
175 backButton.setDisabledIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/directorytree/btn_step_back_disabled.png")));
176 backButton.setMargin(
new java.awt.Insets(2, 0, 2, 0));
177 backButton.setMaximumSize(
new java.awt.Dimension(55, 100));
178 backButton.setMinimumSize(
new java.awt.Dimension(5, 5));
179 backButton.setPreferredSize(
new java.awt.Dimension(23, 23));
180 backButton.setRolloverIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/directorytree/btn_step_back_hover.png")));
181 backButton.addActionListener(
new java.awt.event.ActionListener() {
182 public void actionPerformed(java.awt.event.ActionEvent evt) {
187 forwardButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/directorytree/btn_step_forward.png")));
191 forwardButton.setDisabledIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/directorytree/btn_step_forward_disabled.png")));
193 forwardButton.setMaximumSize(
new java.awt.Dimension(55, 100));
195 forwardButton.setPreferredSize(
new java.awt.Dimension(23, 23));
196 forwardButton.setRolloverIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/directorytree/btn_step_forward_hover.png")));
197 forwardButton.addActionListener(
new java.awt.event.ActionListener() {
198 public void actionPerformed(java.awt.event.ActionEvent evt) {
205 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
206 this.setLayout(layout);
207 layout.setHorizontalGroup(
208 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
209 .addComponent(
jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 262, Short.MAX_VALUE)
210 .addGroup(layout.createSequentialGroup()
212 .addComponent(
backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
214 .addComponent(
forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
215 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 46, Short.MAX_VALUE)
219 layout.setVerticalGroup(
220 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
221 .addGroup(layout.createSequentialGroup()
223 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
224 .addComponent(
forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
225 .addComponent(
backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
227 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
228 .addComponent(
jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 838, javax.swing.GroupLayout.PREFERRED_SIZE)
235 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
238 String[] currentNodePath = backList.pollLast();
239 forwardList.addLast(currentNodePath);
247 String[] newCurrentNodePath = backList.peekLast();
250 if (backList.size() > 1) {
259 this.setCursor(null);
264 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
266 String[] newCurrentNodePath = forwardList.pollLast();
267 if (!forwardList.isEmpty()) {
273 backList.addLast(newCurrentNodePath);
279 this.setCursor(null);
296 if (instance == null) {
307 WindowManager winManager = WindowManager.
getDefault();
308 TopComponent win = winManager.findTopComponent(PREFERRED_ID);
311 "Cannot find " + PREFERRED_ID +
" component. It will not be located properly in the window system.");
315 return (DirectoryTreeTopComponent) win;
318 "There seem to be multiple components with the '" + PREFERRED_ID
319 +
"' ID. That is a potential source of errors and unexpected behavior.");
331 return TopComponent.PERSISTENCE_NEVER;
344 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
350 if (currentCase.
hasData() ==
false) {
352 ((BeanTreeView) this.
jScrollPane1).setRootVisible(
false);
355 List<Object> items =
new ArrayList<>();
358 items.add(
new Views(tskCase));
359 items.add(
new Results(tskCase));
360 items.add(
new Tags());
364 Node root =
new AbstractNode(contentChildren) {
371 return new Action[]{};
377 public Node.Handle getHandle() {
378 return new Node.Handle() {
380 public Node getNode()
throws IOException {
381 return em.getRootContext();
387 root =
new DirectoryTreeFilterNode(root,
true);
389 em.setRootContext(root);
390 em.getRootContext().setName(currentCase.
getName());
391 em.getRootContext().setDisplayName(currentCase.
getName());
392 ((BeanTreeView) this.
jScrollPane1).setRootVisible(
false);
397 Children childNodes = em.getRootContext().getChildren();
401 tree.expandNode(results);
403 Children resultsChilds = results.getChildren();
412 Children viewsChilds = views.getChildren();
413 for (Node n : viewsChilds.getNodes()) {
417 tree.collapseNode(views);
420 if (!dataResult.isOpened()) {
428 if (childNodes.getNodesCount() > 0) {
430 em.setSelectedNodes(
new Node[]{childNodes.getNodeAt(0)});
431 }
catch (Exception ex) {
432 logger.log(Level.SEVERE,
"Error setting default selected node.", ex);
439 this.setCursor(null);
452 contentChildren = null;
455 void writeProperties(java.util.Properties p) {
458 p.setProperty(
"version",
"1.0");
462 Object readProperties(java.util.Properties p) {
463 if (instance == null) {
471 String version = p.getProperty(
"version");
507 return new Action[]{};
519 if (selectedNodes.length > 0) {
520 result = selectedNodes[0];
534 String changed = evt.getPropertyName();
544 if (evt.getOldValue() != null && evt.getNewValue() == null) {
546 SwingUtilities.invokeLater(() -> {
547 Node emptyNode =
new AbstractNode(Children.LEAF);
548 em.setRootContext(emptyNode);
550 }
else if (evt.getNewValue() != null) {
552 Case newCase = (
Case) evt.getNewValue();
553 final String newCaseName = newCase.
getName();
554 SwingUtilities.invokeLater(() -> {
555 em.getRootContext().setName(newCaseName);
556 em.getRootContext().setDisplayName(newCaseName);
580 SwingUtilities.invokeLater(() -> {
584 }
catch (IllegalStateException | TskCoreException notUsed) {
590 else if (changed.equals(ExplorerManager.PROP_SELECTED_NODES)) {
591 SwingUtilities.invokeLater(() -> {
621 EventQueue.invokeLater(
new Runnable() {
629 if (treeNode != null) {
630 DirectoryTreeFilterNode.OriginalNode origin = treeNode.getLookup().lookup(DirectoryTreeFilterNode.OriginalNode.class);
631 if (origin == null) {
634 Node originNode = origin.getNode();
652 String displayName =
"";
653 Content content = originNode.getLookup().lookup(Content.class);
654 if (content != null) {
656 displayName = content.getUniquePath();
657 }
catch (TskCoreException ex) {
658 logger.log(Level.SEVERE,
"Exception while calling Content.getUniquePath() for node: " + originNode);
660 }
else if (originNode.getLookup().lookup(String.class) != null) {
661 displayName = originNode.getLookup().lookup(String.class);
663 dataResult.
setPath(displayName);
667 if (oldNodes != null && newNodes != null
668 && (oldNodes.length == newNodes.length)) {
669 boolean sameNodes =
true;
670 for (
int i = 0; i < oldNodes.length; i++) {
671 sameNodes = sameNodes && oldNodes[i].getName().equals(newNodes[i].getName());
674 dataResult.requestActive();
688 if (selectedNodes.length == 0) {
692 Node selectedNode = selectedNodes[0];
693 String selectedNodeName = selectedNode.getName();
701 String[] currentLast = backList.peekLast();
702 String lastNodeName = null;
703 if (currentLast != null) {
704 lastNodeName = currentLast[currentLast.length - 1];
707 if (currentLast == null || !selectedNodeName.equals(lastNodeName)) {
709 final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
710 backList.addLast(selectedPath);
711 if (backList.size() > 1) {
747 SwingUtilities.invokeLater(
new Runnable() {
760 final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
762 Children rootChildren = em.getRootContext().getChildren();
764 if (dataSourcesFilterNode == null) {
765 logger.log(Level.SEVERE,
"Cannot find data sources filter node, won't refresh the content tree");
768 DirectoryTreeFilterNode.OriginalNode imagesNodeOrig = dataSourcesFilterNode.getLookup().lookup(DirectoryTreeFilterNode.OriginalNode.class);
770 if (imagesNodeOrig == null) {
771 logger.log(Level.SEVERE,
"Cannot find data sources node, won't refresh the content tree");
775 Node imagesNode = imagesNodeOrig.getNode();
793 private void setSelectedNode(
final String[] previouslySelectedNodePath,
final String rootNodeName) {
794 if (previouslySelectedNodePath == null) {
797 SwingUtilities.invokeLater(
new Runnable() {
800 if (previouslySelectedNodePath.length > 0 && (rootNodeName == null || previouslySelectedNodePath[0].equals(rootNodeName))) {
801 Node selectedNode = null;
802 ArrayList<String> selectedNodePath =
new ArrayList<>(Arrays.asList(previouslySelectedNodePath));
803 while (null == selectedNode && !selectedNodePath.isEmpty()) {
805 selectedNode = NodeOp.findPath(em.getRootContext(), selectedNodePath.toArray(
new String[0]));
806 }
catch (NodeNotFoundException ex) {
808 if (selectedNodePath.size() > 1) {
809 selectedNodePath.remove(selectedNodePath.size() - 1);
811 StringBuilder nodePath =
new StringBuilder();
812 for (
int i = 0; i < previouslySelectedNodePath.length; ++i) {
813 nodePath.append(previouslySelectedNodePath[i]).append(
"/");
815 logger.log(Level.WARNING,
"Failed to find any nodes to select on path " + nodePath.toString(), ex);
821 if (null != selectedNode) {
822 if (rootNodeName != null) {
828 em.setExploredContextAndSelection(selectedNode,
new Node[]{selectedNode});
829 }
catch (PropertyVetoException ex) {
830 logger.log(Level.WARNING,
"Property veto from ExplorerManager setting selection to " + selectedNode.getName(), ex);
850 int typeID = art.getArtifactTypeID();
851 String typeName = art.getArtifactTypeName();
852 Children rootChilds = em.getRootContext().getChildren();
853 Node treeNode = null;
855 Children resultsChilds = resultsNode.getChildren();
856 if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) {
857 Node hashsetRootNode = resultsChilds.findChild(typeName);
858 Children hashsetRootChilds = hashsetRootNode.getChildren();
860 String setName = null;
861 List<BlackboardAttribute> attributes = art.getAttributes();
862 for (BlackboardAttribute att : attributes) {
863 int typeId = att.getAttributeType().getTypeID();
864 if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
865 setName = att.getValueString();
868 treeNode = hashsetRootChilds.findChild(setName);
869 }
catch (TskException ex) {
870 logger.log(Level.WARNING,
"Error retrieving attributes", ex);
872 }
else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
873 Node keywordRootNode = resultsChilds.findChild(typeName);
874 Children keywordRootChilds = keywordRootNode.getChildren();
876 String listName = null;
877 String keywordName = null;
878 List<BlackboardAttribute> attributes = art.getAttributes();
879 for (BlackboardAttribute att : attributes) {
880 int typeId = att.getAttributeType().getTypeID();
881 if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
882 listName = att.getValueString();
883 }
else if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) {
884 keywordName = att.getValueString();
887 Node listNode = keywordRootChilds.findChild(listName);
888 if (listNode == null) {
891 Children listChildren = listNode.getChildren();
892 if (listChildren == null) {
895 treeNode = listChildren.findChild(keywordName);
896 }
catch (TskException ex) {
897 logger.log(Level.WARNING,
"Error retrieving attributes", ex);
899 }
else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()
900 || typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
901 Node interestingItemsRootNode = resultsChilds.findChild(typeName);
902 Children interestingItemsRootChildren = interestingItemsRootNode.getChildren();
904 String setName = null;
905 List<BlackboardAttribute> attributes = art.getAttributes();
906 for (BlackboardAttribute att : attributes) {
907 int typeId = att.getAttributeType().getTypeID();
908 if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
909 setName = att.getValueString();
912 treeNode = interestingItemsRootChildren.findChild(setName);
913 }
catch (TskException ex) {
914 logger.log(Level.WARNING,
"Error retrieving attributes", ex);
918 Children extractedChilds = extractedContent.getChildren();
919 if (extractedChilds == null) {
922 treeNode = extractedChilds.findChild(typeName);
925 if (treeNode == null) {
930 em.setExploredContextAndSelection(treeNode,
new Node[]{treeNode});
931 }
catch (PropertyVetoException ex) {
932 logger.log(Level.WARNING,
"Property Veto: ", ex);
936 EventQueue.invokeLater(
new Runnable() {
939 Children resultChilds = dataResult.
getRootNode().getChildren();
940 Node select = resultChilds.findChild(Long.toString(art.getArtifactID()));
941 if (select != null) {
942 dataResult.requestActive();
944 fireViewerComplete();
953 NbBundle.getMessage(
this.getClass(),
"DirectoryTreeTopComponent.action.viewArtContent.text"),
962 void fireViewerComplete() {
966 }
catch (Exception e) {
967 logger.log(Level.SEVERE,
"DirectoryTreeTopComponent listener threw exception", e);
968 MessageNotifyUtil.Notify.show(NbBundle.getMessage(
this.getClass(),
"DirectoryTreeTopComponent.moduleErr"),
969 NbBundle.getMessage(
this.getClass(),
970 "DirectoryTreeTopComponent.moduleErr.msg"),
971 MessageNotifyUtil.MessageType.ERROR);
List< Content > getDataSources()
TopComponent getTopComponent()
void viewArtifact(final BlackboardArtifact art)
static final Logger logger
final DataResultTopComponent dataResult
static final String HIDE_KNOWN_FILES_IN_DATA_SOURCES_TREE
static final String HIDE_KNOWN_FILES_IN_VIEWS_TREE
javax.swing.JCheckBox showRejectedCheckBox
static synchronized IngestManager getInstance()
DataResultTopComponent getDirectoryListing()
final LinkedList< String[]> forwardList
void setDirectoryListingActive()
final transient ExplorerManager em
RootContentChildren contentChildren
void respondSelection(final Node[] oldNodes, final Node[] newNodes)
void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName)
boolean hasMenuOpenAction()
void propertyChange(PropertyChangeEvent evt)
static void openCoreWindows()
javax.swing.JScrollPane jScrollPane1
void updateHistory(Node[] selectedNodes)
final LinkedList< String[]> backList
void openDirectoryListing()
void refreshContentTreeSafe()
void readPropertiesImpl(java.util.Properties p)
void backButtonActionPerformed(java.awt.event.ActionEvent evt)
static final String FINISHED_DISPLAY_EVT
DirectoryTreeTopComponent()
static synchronized DirectoryTreeTopComponent getDefault()
static final String PREFERRED_ID
javax.swing.JButton forwardButton
void addIngestJobEventListener(final PropertyChangeListener listener)
void refreshContentKeys()
void viewArtifactContent(BlackboardArtifact art)
static boolean coreComponentsAreActive()
void refreshDataSourceTree()
Action newToggleShowRejectedAction()
ExplorerManager getExplorerManager()
javax.swing.JButton backButton
SleuthkitCase getSleuthkitCase()
static SelectionContext getSelectionContext(Node n)
static DirectoryTreeTopComponent instance
void addOnFinishedListener(PropertyChangeListener l)
void addIngestModuleEventListener(final PropertyChangeListener listener)
static Case getCurrentCase()
synchronized static Logger getLogger(String name)
static void addChangeListener(PreferenceChangeListener listener)
void forwardButtonActionPerformed(java.awt.event.ActionEvent evt)
void setSelectedNodes(Node[] selected)
void subscribeToChangeEvents()
static synchronized DirectoryTreeTopComponent findInstance()
void setPath(String pathText)
static boolean isCaseOpen()
static void addEventSubscriber(Set< String > eventNames, PropertyChangeListener subscriber)
void setNode(Node selectedNode)