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;
89 private final transient ExplorerManager
em =
new ExplorerManager();
92 "DirectoryTreeTopComponent.title.text"));
95 private static final String
PREFERRED_ID =
"DirectoryTreeTopComponent";
106 ((BeanTreeView)
jScrollPane1).setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
108 putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.TRUE);
113 associateLookup(ExplorerUtils.createLookup(em, getActionMap()));
116 this.backList =
new LinkedList<>();
117 this.forwardList =
new LinkedList<>();
128 public void preferenceChange(PreferenceChangeEvent evt) {
129 switch (evt.getKey()) {
142 this.em.addPropertyChangeListener(
this);
148 this.dataResult.requestActive();
152 this.dataResult.
open();
174 backButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/directorytree/btn_step_back.png")));
178 backButton.setDisabledIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/directorytree/btn_step_back_disabled.png")));
179 backButton.setMargin(
new java.awt.Insets(2, 0, 2, 0));
180 backButton.setMaximumSize(
new java.awt.Dimension(55, 100));
181 backButton.setMinimumSize(
new java.awt.Dimension(5, 5));
182 backButton.setPreferredSize(
new java.awt.Dimension(23, 23));
183 backButton.setRolloverIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/directorytree/btn_step_back_hover.png")));
184 backButton.addActionListener(
new java.awt.event.ActionListener() {
185 public void actionPerformed(java.awt.event.ActionEvent evt) {
190 forwardButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/directorytree/btn_step_forward.png")));
194 forwardButton.setDisabledIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/directorytree/btn_step_forward_disabled.png")));
196 forwardButton.setMaximumSize(
new java.awt.Dimension(55, 100));
198 forwardButton.setPreferredSize(
new java.awt.Dimension(23, 23));
199 forwardButton.setRolloverIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/directorytree/btn_step_forward_hover.png")));
200 forwardButton.addActionListener(
new java.awt.event.ActionListener() {
201 public void actionPerformed(java.awt.event.ActionEvent evt) {
208 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
209 this.setLayout(layout);
210 layout.setHorizontalGroup(
211 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
212 .addComponent(
jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 262, Short.MAX_VALUE)
213 .addGroup(layout.createSequentialGroup()
215 .addComponent(
backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
217 .addComponent(
forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
218 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 46, Short.MAX_VALUE)
222 layout.setVerticalGroup(
223 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
224 .addGroup(layout.createSequentialGroup()
226 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
227 .addComponent(
forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
228 .addComponent(
backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
230 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
231 .addComponent(
jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 854, Short.MAX_VALUE)
238 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
241 String[] currentNodePath = backList.pollLast();
242 forwardList.addLast(currentNodePath);
250 String[] newCurrentNodePath = backList.peekLast();
253 if (backList.size() > 1) {
262 this.setCursor(null);
267 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
269 String[] newCurrentNodePath = forwardList.pollLast();
270 if (!forwardList.isEmpty()) {
276 backList.addLast(newCurrentNodePath);
282 this.setCursor(null);
301 if (instance == null) {
314 WindowManager winManager = WindowManager.
getDefault();
315 TopComponent win = winManager.findTopComponent(PREFERRED_ID);
318 "Cannot find " + PREFERRED_ID +
" component. It will not be located properly in the window system.");
322 return (DirectoryTreeTopComponent) win;
325 "There seem to be multiple components with the '" + PREFERRED_ID
326 +
"' ID. That is a potential source of errors and unexpected behavior.");
338 return TopComponent.PERSISTENCE_NEVER;
351 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
353 Case currentCase = null;
356 }
catch (IllegalStateException ex) {
363 if (null == currentCase || currentCase.
hasData() ==
false) {
367 List<Object> items =
new ArrayList<>();
370 items.add(
new Views(tskCase));
371 items.add(
new Results(tskCase));
372 items.add(
new Tags());
376 Node root =
new AbstractNode(contentChildren) {
383 return new Action[]{};
389 public Node.Handle getHandle() {
390 return new Node.Handle() {
392 public Node getNode()
throws IOException {
393 return em.getRootContext();
399 root =
new DirectoryTreeFilterNode(root,
true);
401 em.setRootContext(root);
402 em.getRootContext().setName(currentCase.
getName());
403 em.getRootContext().setDisplayName(currentCase.
getName());
409 Children childNodes = em.getRootContext().getChildren();
413 tree.expandNode(results);
415 Children resultsChilds = results.getChildren();
416 for (Node n : resultsChilds.getNodes()) {
425 Children viewsChilds = views.getChildren();
426 for (Node n : viewsChilds.getNodes()) {
430 tree.collapseNode(views);
433 if (!dataResult.isOpened()) {
441 if (childNodes.getNodesCount() > 0) {
443 em.setSelectedNodes(
new Node[]{childNodes.getNodeAt(0)});
444 }
catch (PropertyVetoException ex) {
445 LOGGER.log(Level.SEVERE,
"Error setting default selected node.", ex);
451 this.setCursor(null);
464 contentChildren = null;
467 void writeProperties(java.util.Properties p) {
470 p.setProperty(
"version",
"1.0");
474 Object readProperties(java.util.Properties p) {
475 if (instance == null) {
483 String version = p.getProperty(
"version");
524 return new Action[]{};
536 if (selectedNodes.length > 0) {
537 result = selectedNodes[0];
551 String changed = evt.getPropertyName();
561 if (evt.getOldValue() != null && evt.getNewValue() == null) {
563 SwingUtilities.invokeLater(() -> {
564 Node emptyNode =
new AbstractNode(Children.LEAF);
565 em.setRootContext(emptyNode);
567 }
else if (evt.getNewValue() != null) {
569 Case newCase = (
Case) evt.getNewValue();
570 final String newCaseName = newCase.
getName();
571 SwingUtilities.invokeLater(() -> {
572 em.getRootContext().setName(newCaseName);
573 em.getRootContext().setDisplayName(newCaseName);
597 SwingUtilities.invokeLater(() -> {
607 else if (changed.equals(ExplorerManager.PROP_SELECTED_NODES)) {
608 SwingUtilities.invokeLater(() -> {
618 @NbBundle.Messages(
"DirectoryTreeTopComponent.emptyMimeNode.text=Data not available. Run file type identification module.")
639 EventQueue.invokeLater(
new Runnable() {
647 if (treeNode != null) {
648 DirectoryTreeFilterNode.OriginalNode origin = treeNode.getLookup().lookup(DirectoryTreeFilterNode.OriginalNode.class);
649 if (origin == null) {
653 Node originNode = origin.getNode();
662 EmptyNode emptyNode =
new EmptyNode(Bundle.DirectoryTreeTopComponent_emptyMimeNode_text());
670 String displayName =
"";
672 if (content != null) {
676 LOGGER.log(Level.SEVERE,
"Exception while calling Content.getUniquePath() for node: {0}", originNode);
678 }
else if (originNode.getLookup().lookup(String.class) != null) {
679 displayName = originNode.getLookup().lookup(String.class);
681 dataResult.
setPath(displayName);
685 if (oldNodes != null && newNodes != null
686 && (oldNodes.length == newNodes.length)) {
687 boolean sameNodes =
true;
688 for (
int i = 0; i < oldNodes.length; i++) {
689 sameNodes = sameNodes && oldNodes[i].getName().equals(newNodes[i].getName());
692 dataResult.requestActive();
706 if (selectedNodes.length == 0) {
710 Node selectedNode = selectedNodes[0];
711 String selectedNodeName = selectedNode.getName();
719 String[] currentLast = backList.peekLast();
720 String lastNodeName = null;
721 if (currentLast != null) {
722 lastNodeName = currentLast[currentLast.length - 1];
725 if (currentLast == null || !selectedNodeName.equals(lastNodeName)) {
727 final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
728 backList.addLast(selectedPath);
729 if (backList.size() > 1) {
765 SwingUtilities.invokeLater(
new Runnable() {
778 final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
780 Children rootChildren = em.getRootContext().getChildren();
782 if (dataSourcesFilterNode == null) {
783 LOGGER.log(Level.SEVERE,
"Cannot find data sources filter node, won't refresh the content tree");
786 DirectoryTreeFilterNode.OriginalNode imagesNodeOrig = dataSourcesFilterNode.getLookup().lookup(DirectoryTreeFilterNode.OriginalNode.class);
788 if (imagesNodeOrig == null) {
789 LOGGER.log(Level.SEVERE,
"Cannot find data sources node, won't refresh the content tree");
793 Node imagesNode = imagesNodeOrig.getNode();
811 private void setSelectedNode(
final String[] previouslySelectedNodePath,
final String rootNodeName) {
812 if (previouslySelectedNodePath == null) {
815 SwingUtilities.invokeLater(
new Runnable() {
818 if (previouslySelectedNodePath.length > 0 && (rootNodeName == null || previouslySelectedNodePath[0].equals(rootNodeName))) {
819 Node selectedNode = null;
820 ArrayList<String> selectedNodePath =
new ArrayList<>(Arrays.asList(previouslySelectedNodePath));
821 while (null == selectedNode && !selectedNodePath.isEmpty()) {
823 selectedNode = NodeOp.findPath(em.getRootContext(), selectedNodePath.toArray(
new String[0]));
824 }
catch (NodeNotFoundException ex) {
826 if (selectedNodePath.size() > 1) {
827 selectedNodePath.remove(selectedNodePath.size() - 1);
829 StringBuilder nodePath =
new StringBuilder();
830 for (
int i = 0; i < previouslySelectedNodePath.length; ++i) {
831 nodePath.append(previouslySelectedNodePath[i]).append(
"/");
833 LOGGER.log(Level.WARNING,
"Failed to find any nodes to select on path " + nodePath.toString(), ex);
839 if (null != selectedNode) {
840 if (rootNodeName != null) {
846 em.setExploredContextAndSelection(selectedNode,
new Node[]{selectedNode});
847 }
catch (PropertyVetoException ex) {
848 LOGGER.log(Level.WARNING,
"Property veto from ExplorerManager setting selection to " + selectedNode.getName(), ex);
870 Children rootChilds = em.getRootContext().getChildren();
871 Node treeNode = null;
873 Children resultsChilds = resultsNode.getChildren();
875 Node hashsetRootNode = resultsChilds.findChild(typeName);
876 Children hashsetRootChilds = hashsetRootNode.getChildren();
878 String setName = null;
881 int typeId = att.getAttributeType().getTypeID();
883 setName = att.getValueString();
886 treeNode = hashsetRootChilds.findChild(setName);
888 LOGGER.log(Level.WARNING,
"Error retrieving attributes", ex);
891 Node keywordRootNode = resultsChilds.findChild(typeName);
892 Children keywordRootChilds = keywordRootNode.getChildren();
894 String listName = null;
895 String keywordName = null;
898 int typeId = att.getAttributeType().getTypeID();
900 listName = att.getValueString();
902 keywordName = att.getValueString();
905 Node listNode = keywordRootChilds.findChild(listName);
906 if (listNode == null) {
909 Children listChildren = listNode.getChildren();
910 if (listChildren == null) {
913 treeNode = listChildren.findChild(keywordName);
915 LOGGER.log(Level.WARNING,
"Error retrieving attributes", ex);
919 Node interestingItemsRootNode = resultsChilds.findChild(typeName);
920 Children interestingItemsRootChildren = interestingItemsRootNode.getChildren();
922 String setName = null;
925 int typeId = att.getAttributeType().getTypeID();
927 setName = att.getValueString();
930 treeNode = interestingItemsRootChildren.findChild(setName);
932 LOGGER.log(Level.WARNING,
"Error retrieving attributes", ex);
936 Children extractedChilds = extractedContent.getChildren();
937 if (extractedChilds == null) {
940 treeNode = extractedChilds.findChild(typeName);
943 if (treeNode == null) {
948 em.setExploredContextAndSelection(treeNode,
new Node[]{treeNode});
949 }
catch (PropertyVetoException ex) {
950 LOGGER.log(Level.WARNING,
"Property Veto: ", ex);
954 EventQueue.invokeLater(
new Runnable() {
957 Children resultChilds = dataResult.
getRootNode().getChildren();
958 Node select = resultChilds.findChild(Long.toString(art.
getArtifactID()));
959 if (select != null) {
960 dataResult.requestActive();
962 fireViewerComplete();
971 NbBundle.getMessage(
this.getClass(),
"DirectoryTreeTopComponent.action.viewArtContent.text"),
980 void fireViewerComplete() {
984 }
catch (Exception e) {
985 LOGGER.log(Level.SEVERE,
"DirectoryTreeTopComponent listener threw exception", e);
986 MessageNotifyUtil.Notify.show(NbBundle.getMessage(
this.getClass(),
"DirectoryTreeTopComponent.moduleErr"),
987 NbBundle.getMessage(
this.getClass(),
988 "DirectoryTreeTopComponent.moduleErr.msg"),
989 MessageNotifyUtil.MessageType.ERROR);
List< Content > getDataSources()
TSK_INTERESTING_ARTIFACT_HIT
TopComponent getTopComponent()
void viewArtifact(final BlackboardArtifact art)
static final String HIDE_SLACK_FILES_IN_VIEWS_TREE
final DataResultTopComponent dataResult
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()
static boolean runningWithGUI
final transient ExplorerManager em
RootContentChildren contentChildren
String getArtifactTypeName()
void respondSelection(final Node[] oldNodes, final Node[] newNodes)
void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName)
static final Logger LOGGER
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
static final String HIDE_KNOWN_FILES_IN_DATA_SRCS_TREE
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)
void refreshDataSourceTree()
Action newToggleShowRejectedAction()
ExplorerManager getExplorerManager()
javax.swing.JButton backButton
static final String HIDE_SLACK_FILES_IN_DATA_SRCS_TREE
SleuthkitCase getSleuthkitCase()
List< BlackboardAttribute > getAttributes()
static DirectoryTreeTopComponent instance
void addOnFinishedListener(PropertyChangeListener l)
void addIngestModuleEventListener(final PropertyChangeListener listener)
static boolean isEmptyMimeTypeNode(Node node)
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)