Autopsy  4.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
DirectoryTreeTopComponent.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2017 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.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;
82 
86 // Registered as a service provider for DataExplorer in layer.xml
87 public final class DirectoryTreeTopComponent extends TopComponent implements DataExplorer, ExplorerManager.Provider, BlackboardResultViewer {
88 
89  private final transient ExplorerManager em = new ExplorerManager();
91  private final DataResultTopComponent dataResult = new DataResultTopComponent(true, NbBundle.getMessage(this.getClass(),
92  "DirectoryTreeTopComponent.title.text"));
93  private final LinkedList<String[]> backList;
94  private final LinkedList<String[]> forwardList;
95  private static final String PREFERRED_ID = "DirectoryTreeTopComponent"; //NON-NLS
96  private static final Logger LOGGER = Logger.getLogger(DirectoryTreeTopComponent.class.getName());
98 
103  initComponents();
104 
105  // only allow one item to be selected at a time
106  ((BeanTreeView) jScrollPane1).setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
107  // remove the close button
108  putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.TRUE);
109  setName(NbBundle.getMessage(DirectoryTreeTopComponent.class, "CTL_DirectoryTreeTopComponent"));
110  setToolTipText(NbBundle.getMessage(DirectoryTreeTopComponent.class, "HINT_DirectoryTreeTopComponent"));
111 
113  associateLookup(ExplorerUtils.createLookup(em, getActionMap()));
114 
115  // set the back & forward list and also disable the back & forward button
116  this.backList = new LinkedList<>();
117  this.forwardList = new LinkedList<>();
118  backButton.setEnabled(false);
119  forwardButton.setEnabled(false);
120  }
121 
125  private void subscribeToChangeEvents() {
126  UserPreferences.addChangeListener(new PreferenceChangeListener() {
127  @Override
128  public void preferenceChange(PreferenceChangeEvent evt) {
129  switch (evt.getKey()) {
133  break;
136  // TODO: Need a way to refresh the Views subtree
137  break;
138  }
139  }
140  });
141  Case.addEventSubscriber(new HashSet<>(Arrays.asList(Case.Events.CURRENT_CASE.toString(), Case.Events.DATA_SOURCE_ADDED.toString())), this);
142  this.em.addPropertyChangeListener(this);
145  }
146 
148  this.dataResult.requestActive();
149  }
150 
151  public void openDirectoryListing() {
152  this.dataResult.open();
153  }
154 
156  return this.dataResult;
157  }
158 
164  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
165  private void initComponents() {
166 
167  jScrollPane1 = new BeanTreeView();
168  backButton = new javax.swing.JButton();
169  forwardButton = new javax.swing.JButton();
170  showRejectedCheckBox = new javax.swing.JCheckBox();
171 
172  jScrollPane1.setBorder(null);
173 
174  backButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back.png"))); // NOI18N
175  org.openide.awt.Mnemonics.setLocalizedText(backButton, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.backButton.text")); // NOI18N
176  backButton.setBorderPainted(false);
177  backButton.setContentAreaFilled(false);
178  backButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_disabled.png"))); // NOI18N
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"))); // NOI18N
184  backButton.addActionListener(new java.awt.event.ActionListener() {
185  public void actionPerformed(java.awt.event.ActionEvent evt) {
187  }
188  });
189 
190  forwardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward.png"))); // NOI18N
191  org.openide.awt.Mnemonics.setLocalizedText(forwardButton, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.forwardButton.text")); // NOI18N
192  forwardButton.setBorderPainted(false);
193  forwardButton.setContentAreaFilled(false);
194  forwardButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_disabled.png"))); // NOI18N
195  forwardButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
196  forwardButton.setMaximumSize(new java.awt.Dimension(55, 100));
197  forwardButton.setMinimumSize(new java.awt.Dimension(5, 5));
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"))); // NOI18N
200  forwardButton.addActionListener(new java.awt.event.ActionListener() {
201  public void actionPerformed(java.awt.event.ActionEvent evt) {
203  }
204  });
205 
206  org.openide.awt.Mnemonics.setLocalizedText(showRejectedCheckBox, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.showRejectedCheckBox.text")); // NOI18N
207 
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()
214  .addGap(5, 5, 5)
215  .addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
216  .addGap(0, 0, 0)
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)
219  .addComponent(showRejectedCheckBox)
220  .addContainerGap())
221  );
222  layout.setVerticalGroup(
223  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
224  .addGroup(layout.createSequentialGroup()
225  .addGap(5, 5, 5)
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)
229  .addComponent(showRejectedCheckBox))
230  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
231  .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 854, Short.MAX_VALUE)
232  .addGap(0, 0, 0))
233  );
234  }// </editor-fold>//GEN-END:initComponents
235 
236  private void backButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_backButtonActionPerformed
237  // change the cursor to "waiting cursor" for this operation
238  this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
239 
240  // the end is the current place,
241  String[] currentNodePath = backList.pollLast();
242  forwardList.addLast(currentNodePath);
243  forwardButton.setEnabled(true);
244 
245  /*
246  * We peek instead of poll because we use its existence in the list
247  * later on so that we do not reset the forward list after the selection
248  * occurs.
249  */
250  String[] newCurrentNodePath = backList.peekLast();
251 
252  // enable / disable the back and forward button
253  if (backList.size() > 1) {
254  backButton.setEnabled(true);
255  } else {
256  backButton.setEnabled(false);
257  }
258 
259  // update the selection on directory tree
260  setSelectedNode(newCurrentNodePath, null);
261 
262  this.setCursor(null);
263  }//GEN-LAST:event_backButtonActionPerformed
264 
265  private void forwardButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_forwardButtonActionPerformed
266  // change the cursor to "waiting cursor" for this operation
267  this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
268 
269  String[] newCurrentNodePath = forwardList.pollLast();
270  if (!forwardList.isEmpty()) {
271  forwardButton.setEnabled(true);
272  } else {
273  forwardButton.setEnabled(false);
274  }
275 
276  backList.addLast(newCurrentNodePath);
277  backButton.setEnabled(true);
278 
279  // update the selection on directory tree
280  setSelectedNode(newCurrentNodePath, null);
281 
282  this.setCursor(null);
283  }//GEN-LAST:event_forwardButtonActionPerformed
284 
285  // Variables declaration - do not modify//GEN-BEGIN:variables
286  private javax.swing.JButton backButton;
287  private javax.swing.JButton forwardButton;
288  private javax.swing.JScrollPane jScrollPane1;
289  private javax.swing.JCheckBox showRejectedCheckBox;
290  // End of variables declaration//GEN-END:variables
291 
300  public static synchronized DirectoryTreeTopComponent getDefault() {
301  if (instance == null) {
302  instance = new DirectoryTreeTopComponent();
303  }
304  return instance;
305  }
306 
313  public static synchronized DirectoryTreeTopComponent findInstance() {
314  WindowManager winManager = WindowManager.getDefault();
315  TopComponent win = winManager.findTopComponent(PREFERRED_ID);
316  if (win == null) {
317  LOGGER.warning(
318  "Cannot find " + PREFERRED_ID + " component. It will not be located properly in the window system."); //NON-NLS
319  return getDefault();
320  }
321  if (win instanceof DirectoryTreeTopComponent) {
322  return (DirectoryTreeTopComponent) win;
323  }
324  LOGGER.warning(
325  "There seem to be multiple components with the '" + PREFERRED_ID //NON-NLS
326  + "' ID. That is a potential source of errors and unexpected behavior."); //NON-NLS
327  return getDefault();
328  }
329 
336  @Override
337  public int getPersistenceType() {
338  return TopComponent.PERSISTENCE_NEVER;
339  }
340 
348  @Override
349  public void componentOpened() {
350  // change the cursor to "waiting cursor" for this operation
351  this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
352  try {
353  Case currentCase = null;
354  try {
355  currentCase = Case.getCurrentCase();
356  } catch (IllegalStateException ex) {
357  /*
358  * No open case.
359  */
360  }
361 
362  // close the top component if there's no image in this case
363  if (null == currentCase || currentCase.hasData() == false) {
364  ((TreeView) this.jScrollPane1).setRootVisible(false); // hide the root
365  } else {
366  // if there's at least one image, load the image and open the top component
367  List<Object> items = new ArrayList<>();
368  final SleuthkitCase tskCase = currentCase.getSleuthkitCase();
369  items.add(new DataSources());
370  items.add(new Views(tskCase));
371  items.add(new Results(tskCase));
372  items.add(new Tags());
373  items.add(new Reports());
374  contentChildren = new RootContentChildren(items);
375 
376  Node root = new AbstractNode(contentChildren) {
381  @Override
382  public Action[] getActions(boolean popup) {
383  return new Action[]{};
384  }
385 
386  // Overide the AbstractNode use of DefaultHandle to return
387  // a handle which can be serialized without a parent
388  @Override
389  public Node.Handle getHandle() {
390  return new Node.Handle() {
391  @Override
392  public Node getNode() throws IOException {
393  return em.getRootContext();
394  }
395  };
396  }
397  };
398 
399  root = new DirectoryTreeFilterNode(root, true);
400 
401  em.setRootContext(root);
402  em.getRootContext().setName(currentCase.getName());
403  em.getRootContext().setDisplayName(currentCase.getName());
404  ((TreeView) this.jScrollPane1).setRootVisible(false); // hide the root
405 
406  // Reset the forward and back lists because we're resetting the root context
407  resetHistory();
408 
409  Children childNodes = em.getRootContext().getChildren();
410  TreeView tree = getTree();
411 
412  Node results = childNodes.findChild(ResultsNode.NAME);
413  tree.expandNode(results);
414 
415  Children resultsChilds = results.getChildren();
416  for (Node n : resultsChilds.getNodes()) {
417  tree.expandNode(n);
418  }
419 
420  Accounts accounts = resultsChilds.findChild(Accounts.NAME).getLookup().lookup(Accounts.class);
422  showRejectedCheckBox.setSelected(false);
423 
424  Node views = childNodes.findChild(ViewsNode.NAME);
425  Children viewsChilds = views.getChildren();
426  for (Node n : viewsChilds.getNodes()) {
427  tree.expandNode(n);
428  }
429 
430  tree.collapseNode(views);
431 
432  // if the dataResult is not opened
433  if (!dataResult.isOpened()) {
434  dataResult.open(); // open the data result top component as well when the directory tree is opened
435  }
436 
437  // select the first image node, if there is one
438  // (this has to happen after dataResult is opened, because the event
439  // of changing the selected node fires a handler that tries to make
440  // dataResult active)
441  if (childNodes.getNodesCount() > 0) {
442  try {
443  em.setSelectedNodes(new Node[]{childNodes.getNodeAt(0)});
444  } catch (PropertyVetoException ex) {
445  LOGGER.log(Level.SEVERE, "Error setting default selected node.", ex); //NON-NLS
446  }
447  }
448 
449  }
450  } finally {
451  this.setCursor(null);
452  }
453  }
454 
461  @Override
462  public void componentClosed() {
463  //@@@ push the selection node to null?
464  contentChildren = null;
465  }
466 
467  void writeProperties(java.util.Properties p) {
468  // better to version settings since initial version as advocated at
469  // http://wiki.apidesign.org/wiki/PropertyFiles
470  p.setProperty("version", "1.0");
471  // TODO store your settings
472  }
473 
474  Object readProperties(java.util.Properties p) {
475  if (instance == null) {
476  instance = this;
477  }
478  instance.readPropertiesImpl(p);
479  return instance;
480  }
481 
482  private void readPropertiesImpl(java.util.Properties p) {
483  String version = p.getProperty("version");
484  // TODO read your settings according to their version
485  }
486 
492  @Override
493  protected String preferredID() {
494  return PREFERRED_ID;
495  }
496 
497  @Override
498  public boolean canClose() {
499  /*
500  * Only allow the main tree view in the left side of the main window to
501  * be closed if there is no opne case or the open case has no data
502  * sources.
503  */
504  return !Case.isCaseOpen() || Case.getCurrentCase().hasData() == false;
505  }
506 
512  @Override
513  public ExplorerManager getExplorerManager() {
514  return this.em;
515  }
516 
522  @Override
523  public Action[] getActions() {
524  return new Action[]{};
525  }
526 
532  public Node getSelectedNode() {
533  Node result = null;
534 
535  Node[] selectedNodes = this.getExplorerManager().getSelectedNodes();
536  if (selectedNodes.length > 0) {
537  result = selectedNodes[0];
538  }
539  return result;
540  }
541 
548  @Override
549  public void propertyChange(PropertyChangeEvent evt) {
551  String changed = evt.getPropertyName();
552  if (changed.equals(Case.Events.CURRENT_CASE.toString())) { // changed current case
553  // When a case is closed, the old value of this property is the
554  // closed Case object and the new value is null. When a case is
555  // opened, the old value is null and the new value is the new Case
556  // object.
557  // @@@ This needs to be revisited. Perhaps case closed and case
558  // opened events instead of property change events would be a better
559  // solution. Either way, more probably needs to be done to clean up
560  // data model objects when a case is closed.
561  if (evt.getOldValue() != null && evt.getNewValue() == null) {
562  // The current case has been closed. Reset the ExplorerManager.
563  SwingUtilities.invokeLater(() -> {
564  Node emptyNode = new AbstractNode(Children.LEAF);
565  em.setRootContext(emptyNode);
566  });
567  } else if (evt.getNewValue() != null) {
568  // A new case has been opened. Reset the ExplorerManager.
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);
574 
575  // Reset the forward and back
576  // buttons. Note that a call to CoreComponentControl.openCoreWindows()
577  // by the new Case object will lead to a componentOpened() call
578  // that will repopulate the tree.
579  // @@@ The repopulation of the tree in this fashion also merits
580  // reconsideration.
581  resetHistory();
582  });
583  }
584  } // if the image is added to the case
585  else if (changed.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
592  try {
593  Case currentCase = Case.getCurrentCase();
594  // We only need to trigger openCoreWindows() when the
595  // first data source is added.
596  if (currentCase.getDataSources().size() == 1) {
597  SwingUtilities.invokeLater(() -> {
599  });
600  }
601  } catch (IllegalStateException | TskCoreException notUsed) {
605  }
606  } // change in node selection
607  else if (changed.equals(ExplorerManager.PROP_SELECTED_NODES)) {
608  SwingUtilities.invokeLater(() -> {
609  respondSelection((Node[]) evt.getOldValue(), (Node[]) evt.getNewValue());
610  });
611  } else if (changed.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
612  // nothing to do here.
613  // all nodes should be listening for these events and update accordingly.
614  }
615  }
616  }
617 
618  @NbBundle.Messages("DirectoryTreeTopComponent.emptyMimeNode.text=Data not available. Run file type identification module.")
627  private void respondSelection(final Node[] oldNodes, final Node[] newNodes) {
628  if (!Case.isCaseOpen()) {
629  //handle in-between condition when case is being closed
630  //and legacy selection events are pumped
631  return;
632  }
633 
634  // Some lock that prevents certain Node operations is set during the
635  // ExplorerManager selection-change, so we must handle changes after the
636  // selection-change event is processed.
637  //TODO find a different way to refresh data result viewer, scheduling this
638  //to EDT breaks loading of nodes in the background
639  EventQueue.invokeLater(new Runnable() {
640  @Override
641  public void run() {
642  // change the cursor to "waiting cursor" for this operation
643  DirectoryTreeTopComponent.this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
644  try {
645 
646  Node treeNode = DirectoryTreeTopComponent.this.getSelectedNode();
647  if (treeNode != null) {
648  DirectoryTreeFilterNode.OriginalNode origin = treeNode.getLookup().lookup(DirectoryTreeFilterNode.OriginalNode.class);
649  if (origin == null) {
650  return;
651  }
652 
653  Node originNode = origin.getNode();
654 
655  //set node, wrap in filter node first to filter out children
656  Node drfn = new DataResultFilterNode(originNode, DirectoryTreeTopComponent.this.em);
657 
658  // Create a TableFilterNode with knowledge of the node's type to allow for column order settings
659  if (FileTypesByMimeType.isEmptyMimeTypeNode(originNode)) {
660  //Special case for when File Type Identification has not yet been run and
661  //there are no mime types to populate Files by Mime Type Tree
662  EmptyNode emptyNode = new EmptyNode(Bundle.DirectoryTreeTopComponent_emptyMimeNode_text());
663  dataResult.setNode(new TableFilterNode(emptyNode, true, "This Node Is Empty")); //NON-NLS
664  } else if (originNode instanceof DisplayableItemNode) {
665  dataResult.setNode(new TableFilterNode(drfn, true, ((DisplayableItemNode) originNode).getItemType()));
666  } else {
667  dataResult.setNode(new TableFilterNode(drfn, true));
668  }
669 
670  String displayName = "";
671  Content content = originNode.getLookup().lookup(Content.class);
672  if (content != null) {
673  try {
674  displayName = content.getUniquePath();
675  } catch (TskCoreException ex) {
676  LOGGER.log(Level.SEVERE, "Exception while calling Content.getUniquePath() for node: {0}", originNode); //NON-NLS
677  }
678  } else if (originNode.getLookup().lookup(String.class) != null) {
679  displayName = originNode.getLookup().lookup(String.class);
680  }
681  dataResult.setPath(displayName);
682  }
683 
684  // set the directory listing to be active
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());
690  }
691  if (!sameNodes) {
692  dataResult.requestActive();
693  }
694  }
695  } finally {
696  setCursor(null);
697  }
698  }
699  });
700 
701  // update the back and forward list
702  updateHistory(em.getSelectedNodes());
703  }
704 
705  private void updateHistory(Node[] selectedNodes) {
706  if (selectedNodes.length == 0) {
707  return;
708  }
709 
710  Node selectedNode = selectedNodes[0];
711  String selectedNodeName = selectedNode.getName();
712 
713  /*
714  * get the previous entry to make sure we don't duplicate it. Motivation
715  * for this is also that if we used the back button, then we already
716  * added the 'current' node to 'back' and we will detect that and not
717  * reset the forward list.
718  */
719  String[] currentLast = backList.peekLast();
720  String lastNodeName = null;
721  if (currentLast != null) {
722  lastNodeName = currentLast[currentLast.length - 1];
723  }
724 
725  if (currentLast == null || !selectedNodeName.equals(lastNodeName)) {
726  //add to the list if the last if not the same as current
727  final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
728  backList.addLast(selectedPath); // add the node to the "backList"
729  if (backList.size() > 1) {
730  backButton.setEnabled(true);
731  } else {
732  backButton.setEnabled(false);
733  }
734 
735  forwardList.clear(); // clear the "forwardList"
736  forwardButton.setEnabled(false); // disable the forward Button
737  }
738  }
739 
744  private void resetHistory() {
745  // clear the back and forward list
746  backList.clear();
747  forwardList.clear();
748  backButton.setEnabled(false);
749  forwardButton.setEnabled(false);
750  }
751 
757  public BeanTreeView getTree() {
758  return (BeanTreeView) this.jScrollPane1;
759  }
760 
764  public void refreshContentTreeSafe() {
765  SwingUtilities.invokeLater(new Runnable() {
766  @Override
767  public void run() {
769  }
770  });
771  }
772 
776  private void refreshDataSourceTree() {
777  Node selectedNode = getSelectedNode();
778  final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
779 
780  Children rootChildren = em.getRootContext().getChildren();
781  Node dataSourcesFilterNode = rootChildren.findChild(DataSourcesNode.NAME);
782  if (dataSourcesFilterNode == null) {
783  LOGGER.log(Level.SEVERE, "Cannot find data sources filter node, won't refresh the content tree"); //NON-NLS
784  return;
785  }
786  DirectoryTreeFilterNode.OriginalNode imagesNodeOrig = dataSourcesFilterNode.getLookup().lookup(DirectoryTreeFilterNode.OriginalNode.class);
787 
788  if (imagesNodeOrig == null) {
789  LOGGER.log(Level.SEVERE, "Cannot find data sources node, won't refresh the content tree"); //NON-NLS
790  return;
791  }
792 
793  Node imagesNode = imagesNodeOrig.getNode();
794 
795  DataSourcesNode.DataSourcesNodeChildren contentRootChildren = (DataSourcesNode.DataSourcesNodeChildren) imagesNode.getChildren();
796  contentRootChildren.refreshContentKeys();
797 
798  //final TreeView tree = getTree();
799  //tree.expandNode(imagesNode);
800  setSelectedNode(selectedPath, DataSourcesNode.NAME);
801 
802  }
803 
811  private void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName) {
812  if (previouslySelectedNodePath == null) {
813  return;
814  }
815  SwingUtilities.invokeLater(new Runnable() {
816  @Override
817  public void run() {
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()) {
822  try {
823  selectedNode = NodeOp.findPath(em.getRootContext(), selectedNodePath.toArray(new String[0]));
824  } catch (NodeNotFoundException ex) {
825  // The selected node may have been deleted (e.g., a deleted tag), so truncate the path and try again.
826  if (selectedNodePath.size() > 1) {
827  selectedNodePath.remove(selectedNodePath.size() - 1);
828  } else {
829  StringBuilder nodePath = new StringBuilder();
830  for (int i = 0; i < previouslySelectedNodePath.length; ++i) {
831  nodePath.append(previouslySelectedNodePath[i]).append("/");
832  }
833  LOGGER.log(Level.WARNING, "Failed to find any nodes to select on path " + nodePath.toString(), ex); //NON-NLS
834  break;
835  }
836  }
837  }
838 
839  if (null != selectedNode) {
840  if (rootNodeName != null) {
841  //called from tree auto refresh context
842  //remove last from backlist, because auto select will result in duplication
843  backList.pollLast();
844  }
845  try {
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); //NON-NLS
849  }
850  }
851  }
852  }
853  });
854  }
855 
856  @Override
857  public TopComponent getTopComponent() {
858  return this;
859  }
860 
861  @Override
862  public boolean hasMenuOpenAction() {
863  return false;
864  }
865 
866  @Override
867  public void viewArtifact(final BlackboardArtifact art) {
868  int typeID = art.getArtifactTypeID();
869  String typeName = art.getArtifactTypeName();
870  Children rootChilds = em.getRootContext().getChildren();
871  Node treeNode = null;
872  Node resultsNode = rootChilds.findChild(ResultsNode.NAME);
873  Children resultsChilds = resultsNode.getChildren();
874  if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) {
875  Node hashsetRootNode = resultsChilds.findChild(typeName);
876  Children hashsetRootChilds = hashsetRootNode.getChildren();
877  try {
878  String setName = null;
879  List<BlackboardAttribute> attributes = art.getAttributes();
880  for (BlackboardAttribute att : attributes) {
881  int typeId = att.getAttributeType().getTypeID();
882  if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
883  setName = att.getValueString();
884  }
885  }
886  treeNode = hashsetRootChilds.findChild(setName);
887  } catch (TskException ex) {
888  LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
889  }
890  } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
891  Node keywordRootNode = resultsChilds.findChild(typeName);
892  Children keywordRootChilds = keywordRootNode.getChildren();
893  try {
894  String listName = null;
895  String keywordName = null;
896  List<BlackboardAttribute> attributes = art.getAttributes();
897  for (BlackboardAttribute att : attributes) {
898  int typeId = att.getAttributeType().getTypeID();
899  if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
900  listName = att.getValueString();
901  } else if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) {
902  keywordName = att.getValueString();
903  }
904  }
905  Node listNode = keywordRootChilds.findChild(listName);
906  if (listNode == null) {
907  return;
908  }
909  Children listChildren = listNode.getChildren();
910  if (listChildren == null) {
911  return;
912  }
913  treeNode = listChildren.findChild(keywordName);
914  } catch (TskException ex) {
915  LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
916  }
917  } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()
919  Node interestingItemsRootNode = resultsChilds.findChild(typeName);
920  Children interestingItemsRootChildren = interestingItemsRootNode.getChildren();
921  try {
922  String setName = null;
923  List<BlackboardAttribute> attributes = art.getAttributes();
924  for (BlackboardAttribute att : attributes) {
925  int typeId = att.getAttributeType().getTypeID();
926  if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
927  setName = att.getValueString();
928  }
929  }
930  treeNode = interestingItemsRootChildren.findChild(setName);
931  } catch (TskException ex) {
932  LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
933  }
934  } else {
935  Node extractedContent = resultsChilds.findChild(ExtractedContent.NAME);
936  Children extractedChilds = extractedContent.getChildren();
937  if (extractedChilds == null) {
938  return;
939  }
940  treeNode = extractedChilds.findChild(typeName);
941  }
942 
943  if (treeNode == null) {
944  return;
945  }
946 
947  try {
948  em.setExploredContextAndSelection(treeNode, new Node[]{treeNode});
949  } catch (PropertyVetoException ex) {
950  LOGGER.log(Level.WARNING, "Property Veto: ", ex); //NON-NLS
951  }
952 
953  // Another thread is needed because we have to wait for dataResult to populate
954  EventQueue.invokeLater(new Runnable() {
955  @Override
956  public void run() {
957  Children resultChilds = dataResult.getRootNode().getChildren();
958  Node select = resultChilds.findChild(Long.toString(art.getArtifactID()));
959  if (select != null) {
960  dataResult.requestActive();
961  dataResult.setSelectedNodes(new Node[]{select});
962  fireViewerComplete();
963  }
964  }
965  });
966  }
967 
968  @Override
970  new ViewContextAction(
971  NbBundle.getMessage(this.getClass(), "DirectoryTreeTopComponent.action.viewArtContent.text"),
972  new BlackboardArtifactNode(art)).actionPerformed(null);
973  }
974 
975  @Override
976  public void addOnFinishedListener(PropertyChangeListener l) {
977  DirectoryTreeTopComponent.this.addPropertyChangeListener(l);
978  }
979 
980  void fireViewerComplete() {
981 
982  try {
983  firePropertyChange(BlackboardResultViewer.FINISHED_DISPLAY_EVT, 0, 1);
984  } catch (Exception e) {
985  LOGGER.log(Level.SEVERE, "DirectoryTreeTopComponent listener threw exception", e); //NON-NLS
986  MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "DirectoryTreeTopComponent.moduleErr"),
987  NbBundle.getMessage(this.getClass(),
988  "DirectoryTreeTopComponent.moduleErr.msg"),
989  MessageNotifyUtil.MessageType.ERROR);
990  }
991  }
992 }
static synchronized IngestManager getInstance()
void respondSelection(final Node[] oldNodes, final Node[] newNodes)
void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName)
void addIngestJobEventListener(final PropertyChangeListener listener)
List< BlackboardAttribute > getAttributes()
void addIngestModuleEventListener(final PropertyChangeListener listener)
synchronized static Logger getLogger(String name)
Definition: Logger.java:161
static void addChangeListener(PreferenceChangeListener listener)
static void addEventSubscriber(Set< String > eventNames, PropertyChangeListener subscriber)
Definition: Case.java:396

Copyright © 2012-2016 Basis Technology. Generated on: Mon Apr 24 2017
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.