Autopsy  4.0
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-2015 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.PropertyChangeSupport;
26 import java.beans.PropertyVetoException;
27 import java.io.IOException;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.HashSet;
31 import java.util.LinkedList;
32 import java.util.List;
33 import java.util.logging.Level;
34 import java.util.prefs.PreferenceChangeEvent;
35 import java.util.prefs.PreferenceChangeListener;
36 import javax.swing.Action;
37 import javax.swing.SwingUtilities;
38 import javax.swing.tree.TreeSelectionModel;
39 import org.openide.explorer.ExplorerManager;
40 import org.openide.explorer.ExplorerUtils;
41 import org.openide.explorer.view.BeanTreeView;
42 import org.openide.explorer.view.TreeView;
43 import org.openide.nodes.AbstractNode;
44 import org.openide.nodes.Children;
45 import org.openide.nodes.Node;
46 import org.openide.nodes.NodeNotFoundException;
47 import org.openide.nodes.NodeOp;
48 import org.openide.util.NbBundle;
49 import org.openide.windows.TopComponent;
50 import org.openide.windows.WindowManager;
76 import org.sleuthkit.datamodel.BlackboardArtifact;
77 import org.sleuthkit.datamodel.BlackboardAttribute;
78 import org.sleuthkit.datamodel.Content;
79 import org.sleuthkit.datamodel.SleuthkitCase;
80 import org.sleuthkit.datamodel.TskCoreException;
81 import org.sleuthkit.datamodel.TskException;
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 final PropertyChangeSupport pcs;
97  private static final Logger logger = Logger.getLogger(DirectoryTreeTopComponent.class.getName());
99 
104  initComponents();
105 
106  // only allow one item to be selected at a time
107  ((BeanTreeView) jScrollPane1).setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
108  // remove the close button
109  putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.TRUE);
110  setName(NbBundle.getMessage(DirectoryTreeTopComponent.class, "CTL_DirectoryTreeTopComponent"));
111  setToolTipText(NbBundle.getMessage(DirectoryTreeTopComponent.class, "HINT_DirectoryTreeTopComponent"));
112 
114  associateLookup(ExplorerUtils.createLookup(em, getActionMap()));
115 
116  this.pcs = new PropertyChangeSupport(this);
117 
118  // set the back & forward list and also disable the back & forward button
119  this.backList = new LinkedList<>();
120  this.forwardList = new LinkedList<>();
121  backButton.setEnabled(false);
122  forwardButton.setEnabled(false);
123  }
124 
128  private void subscribeToChangeEvents() {
129  UserPreferences.addChangeListener(new PreferenceChangeListener() {
130  @Override
131  public void preferenceChange(PreferenceChangeEvent evt) {
132  switch (evt.getKey()) {
135  break;
137  // TODO: Need a way to refresh the Views subtree
138  break;
139  }
140  }
141  });
142  Case.addEventSubscriber(new HashSet<>(Arrays.asList(Case.Events.CURRENT_CASE.toString(), Case.Events.DATA_SOURCE_ADDED.toString())), this);
143  this.em.addPropertyChangeListener(this);
146  }
147 
149  this.dataResult.requestActive();
150  }
151 
152  public void openDirectoryListing() {
153  this.dataResult.open();
154  }
155 
157  return this.dataResult;
158  }
159 
165  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
166  private void initComponents() {
167 
168  jScrollPane1 = new BeanTreeView();
169  backButton = new javax.swing.JButton();
170  forwardButton = new javax.swing.JButton();
171  jSeparator1 = new javax.swing.JSeparator();
172 
173  jScrollPane1.setBorder(null);
174 
175  backButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back.png"))); // NOI18N NON-NLS
176  org.openide.awt.Mnemonics.setLocalizedText(backButton, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.backButton.text")); // NOI18N
177  backButton.setBorderPainted(false);
178  backButton.setContentAreaFilled(false);
179  backButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_disabled.png"))); // NOI18N NON-NLS
180  backButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
181  backButton.setMaximumSize(new java.awt.Dimension(55, 100));
182  backButton.setMinimumSize(new java.awt.Dimension(5, 5));
183  backButton.setPreferredSize(new java.awt.Dimension(23, 23));
184  backButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_hover.png"))); // NOI18N NON-NLS
185  backButton.addActionListener(new java.awt.event.ActionListener() {
186  public void actionPerformed(java.awt.event.ActionEvent evt) {
188  }
189  });
190 
191  forwardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward.png"))); // NOI18N NON-NLS
192  org.openide.awt.Mnemonics.setLocalizedText(forwardButton, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.forwardButton.text")); // NOI18N
193  forwardButton.setBorderPainted(false);
194  forwardButton.setContentAreaFilled(false);
195  forwardButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_disabled.png"))); // NOI18N NON-NLS
196  forwardButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
197  forwardButton.setMaximumSize(new java.awt.Dimension(55, 100));
198  forwardButton.setMinimumSize(new java.awt.Dimension(5, 5));
199  forwardButton.setPreferredSize(new java.awt.Dimension(23, 23));
200  forwardButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_hover.png"))); // NOI18N NON-NLS
201  forwardButton.addActionListener(new java.awt.event.ActionListener() {
202  public void actionPerformed(java.awt.event.ActionEvent evt) {
204  }
205  });
206 
207  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
208  this.setLayout(layout);
209  layout.setHorizontalGroup(
210  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
211  .addGroup(layout.createSequentialGroup()
212  .addContainerGap()
213  .addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
214  .addGap(0, 0, 0)
215  .addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
216  .addContainerGap(206, Short.MAX_VALUE))
217  .addComponent(jSeparator1, javax.swing.GroupLayout.DEFAULT_SIZE, 262, Short.MAX_VALUE)
218  .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 262, Short.MAX_VALUE)
219  );
220  layout.setVerticalGroup(
221  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
222  .addGroup(layout.createSequentialGroup()
223  .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
224  .addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
225  .addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE))
226  .addGap(0, 0, 0)
227  .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 1, javax.swing.GroupLayout.PREFERRED_SIZE)
228  .addGap(0, 0, 0)
229  .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 860, Short.MAX_VALUE)
230  .addContainerGap())
231  );
232  }// </editor-fold>//GEN-END:initComponents
233 
234  private void backButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_backButtonActionPerformed
235  // change the cursor to "waiting cursor" for this operation
236  this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
237 
238  // the end is the current place,
239  String[] currentNodePath = backList.pollLast();
240  forwardList.addLast(currentNodePath);
241  forwardButton.setEnabled(true);
242 
243  /*
244  * We peek instead of poll because we use its existence in the list
245  * later on so that we do not reset the forward list after the selection
246  * occurs.
247  */
248  String[] newCurrentNodePath = backList.peekLast();
249 
250  // enable / disable the back and forward button
251  if (backList.size() > 1) {
252  backButton.setEnabled(true);
253  } else {
254  backButton.setEnabled(false);
255  }
256 
257  // update the selection on directory tree
258  setSelectedNode(newCurrentNodePath, null);
259 
260  this.setCursor(null);
261  }//GEN-LAST:event_backButtonActionPerformed
262 
263  private void forwardButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_forwardButtonActionPerformed
264  // change the cursor to "waiting cursor" for this operation
265  this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
266 
267  String[] newCurrentNodePath = forwardList.pollLast();
268  if (!forwardList.isEmpty()) {
269  forwardButton.setEnabled(true);
270  } else {
271  forwardButton.setEnabled(false);
272  }
273 
274  backList.addLast(newCurrentNodePath);
275  backButton.setEnabled(true);
276 
277  // update the selection on directory tree
278  setSelectedNode(newCurrentNodePath, null);
279 
280  this.setCursor(null);
281  }//GEN-LAST:event_forwardButtonActionPerformed
282  // Variables declaration - do not modify//GEN-BEGIN:variables
283  private javax.swing.JButton backButton;
284  private javax.swing.JButton forwardButton;
285  private javax.swing.JScrollPane jScrollPane1;
286  private javax.swing.JSeparator jSeparator1;
287  // End of variables declaration//GEN-END:variables
288 
295  public static synchronized DirectoryTreeTopComponent getDefault() {
296  if (instance == null) {
297  instance = new DirectoryTreeTopComponent();
298  }
299  return instance;
300  }
301 
306  public static synchronized DirectoryTreeTopComponent findInstance() {
307  WindowManager winManager = WindowManager.getDefault();
308  TopComponent win = winManager.findTopComponent(PREFERRED_ID);
309  if (win == null) {
310  logger.warning(
311  "Cannot find " + PREFERRED_ID + " component. It will not be located properly in the window system."); //NON-NLS
312  return getDefault();
313  }
314  if (win instanceof DirectoryTreeTopComponent) {
315  return (DirectoryTreeTopComponent) win;
316  }
317  logger.warning(
318  "There seem to be multiple components with the '" + PREFERRED_ID //NON-NLS
319  + "' ID. That is a potential source of errors and unexpected behavior."); //NON-NLS
320  return getDefault();
321  }
322 
329  @Override
330  public int getPersistenceType() {
331  return TopComponent.PERSISTENCE_NEVER;
332  }
333 
341  @Override
342  public void componentOpened() {
343  // change the cursor to "waiting cursor" for this operation
344  this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
345  try {
346  if (Case.existsCurrentCase()) {
347  Case currentCase = Case.getCurrentCase();
348 
349  // close the top component if there's no image in this case
350  if (currentCase.hasData() == false) {
351  //this.close();
352  ((BeanTreeView) this.jScrollPane1).setRootVisible(false); // hide the root
353  } else {
354  // if there's at least one image, load the image and open the top component
355  List<Object> items = new ArrayList<>();
356  final SleuthkitCase tskCase = currentCase.getSleuthkitCase();
357  items.add(new DataSources());
358  items.add(new Views(tskCase));
359  items.add(new Results(tskCase));
360  items.add(new Tags());
361  items.add(new Reports());
362  contentChildren = new RootContentChildren(items);
363  Node root = new AbstractNode(contentChildren) {
368  @Override
369  public Action[] getActions(boolean popup) {
370  return new Action[]{};
371  }
372 
373  // Overide the AbstractNode use of DefaultHandle to return
374  // a handle which can be serialized without a parent
375  @Override
376  public Node.Handle getHandle() {
377  return new Node.Handle() {
378  @Override
379  public Node getNode() throws IOException {
380  return em.getRootContext();
381  }
382  };
383  }
384  };
385 
386  root = new DirectoryTreeFilterNode(root, true);
387 
388  em.setRootContext(root);
389  em.getRootContext().setName(currentCase.getName());
390  em.getRootContext().setDisplayName(currentCase.getName());
391  ((BeanTreeView) this.jScrollPane1).setRootVisible(false); // hide the root
392 
393  // Reset the forward and back lists because we're resetting the root context
394  resetHistory();
395 
396  Children childNodes = em.getRootContext().getChildren();
397  TreeView tree = getTree();
398 
399  Node results = childNodes.findChild(ResultsNode.NAME);
400  tree.expandNode(results);
401 
402  Children resultsChilds = results.getChildren();
403  tree.expandNode(resultsChilds.findChild(KeywordHits.NAME));
404  tree.expandNode(resultsChilds.findChild(ExtractedContent.NAME));
405 
406  Node views = childNodes.findChild(ViewsNode.NAME);
407  Children viewsChilds = views.getChildren();
408  for (Node n : viewsChilds.getNodes()) {
409  tree.expandNode(n);
410  }
411 
412  tree.collapseNode(views);
413 
414  // if the dataResult is not opened
415  if (!dataResult.isOpened()) {
416  dataResult.open(); // open the data result top component as well when the directory tree is opened
417  }
418 
419  // select the first image node, if there is one
420  // (this has to happen after dataResult is opened, because the event
421  // of changing the selected node fires a handler that tries to make
422  // dataResult active)
423  if (childNodes.getNodesCount() > 0) {
424  try {
425  em.setSelectedNodes(new Node[]{childNodes.getNodeAt(0)});
426  } catch (Exception ex) {
427  logger.log(Level.SEVERE, "Error setting default selected node.", ex); //NON-NLS
428  }
429  }
430 
431  }
432  }
433  } finally {
434  this.setCursor(null);
435  }
436  }
437 
444  @Override
445  public void componentClosed() {
446  //@@@ push the selection node to null?
447  contentChildren = null;
448  }
449 
450  void writeProperties(java.util.Properties p) {
451  // better to version settings since initial version as advocated at
452  // http://wiki.apidesign.org/wiki/PropertyFiles
453  p.setProperty("version", "1.0");
454  // TODO store your settings
455  }
456 
457  Object readProperties(java.util.Properties p) {
458  if (instance == null) {
459  instance = this;
460  }
461  instance.readPropertiesImpl(p);
462  return instance;
463  }
464 
465  private void readPropertiesImpl(java.util.Properties p) {
466  String version = p.getProperty("version");
467  // TODO read your settings according to their version
468  }
469 
475  @Override
476  protected String preferredID() {
477  return PREFERRED_ID;
478  }
479 
480  @Override
481  public boolean canClose() {
482  return !Case.existsCurrentCase() || Case.getCurrentCase().hasData() == false; // only allow this window to be closed when there's no case opened or no image in this case
483  }
484 
490  @Override
491  public ExplorerManager getExplorerManager() {
492  return this.em;
493  }
494 
500  @Override
501  public Action[] getActions() {
502  return new Action[]{};
503  }
504 
510  public Node getSelectedNode() {
511  Node result = null;
512 
513  Node[] selectedNodes = this.getExplorerManager().getSelectedNodes();
514  if (selectedNodes.length > 0) {
515  result = selectedNodes[0];
516  }
517  return result;
518  }
519 
526  @Override
527  public void propertyChange(PropertyChangeEvent evt) {
529  String changed = evt.getPropertyName();
530  if (changed.equals(Case.Events.CURRENT_CASE.toString())) { // changed current case
531  // When a case is closed, the old value of this property is the
532  // closed Case object and the new value is null. When a case is
533  // opened, the old value is null and the new value is the new Case
534  // object.
535  // @@@ This needs to be revisited. Perhaps case closed and case
536  // opened events instead of property change events would be a better
537  // solution. Either way, more probably needs to be done to clean up
538  // data model objects when a case is closed.
539  if (evt.getOldValue() != null && evt.getNewValue() == null) {
540  // The current case has been closed. Reset the ExplorerManager.
541  SwingUtilities.invokeLater(() -> {
542  Node emptyNode = new AbstractNode(Children.LEAF);
543  em.setRootContext(emptyNode);
544  });
545  } else if (evt.getNewValue() != null) {
546  // A new case has been opened. Reset the ExplorerManager.
547  Case newCase = (Case) evt.getNewValue();
548  final String newCaseName = newCase.getName();
549  SwingUtilities.invokeLater(() -> {
550  em.getRootContext().setName(newCaseName);
551  em.getRootContext().setDisplayName(newCaseName);
552 
553  // Reset the forward and back
554  // buttons. Note that a call to CoreComponentControl.openCoreWindows()
555  // by the new Case object will lead to a componentOpened() call
556  // that will repopulate the tree.
557  // @@@ The repopulation of the tree in this fashion also merits
558  // reconsideration.
559  resetHistory();
560  });
561  }
562  } // if the image is added to the case
563  else if (changed.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
570  try {
571  Case currentCase = Case.getCurrentCase();
572  // We only need to trigger openCoreWindows() when the
573  // first data source is added.
574  if (currentCase.getDataSources().size() == 1) {
575  SwingUtilities.invokeLater(() -> {
577  });
578  }
579  } catch (IllegalStateException | TskCoreException notUsed) {
583  }
584  } // change in node selection
585  else if (changed.equals(ExplorerManager.PROP_SELECTED_NODES)) {
586  SwingUtilities.invokeLater(() -> {
587  respondSelection((Node[]) evt.getOldValue(), (Node[]) evt.getNewValue());
588  });
589  } else if (changed.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
590  // nothing to do here.
591  // all nodes should be listening for these events and update accordingly.
592  }
593  }
594  }
595 
604  private void respondSelection(final Node[] oldNodes, final Node[] newNodes) {
605  if (!Case.isCaseOpen()) {
606  //handle in-between condition when case is being closed
607  //and legacy selection events are pumped
608  return;
609  }
610 
611  // Some lock that prevents certain Node operations is set during the
612  // ExplorerManager selection-change, so we must handle changes after the
613  // selection-change event is processed.
614  //TODO find a different way to refresh data result viewer, scheduling this
615  //to EDT breaks loading of nodes in the background
616  EventQueue.invokeLater(new Runnable() {
617  @Override
618  public void run() {
619  // change the cursor to "waiting cursor" for this operation
620  DirectoryTreeTopComponent.this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
621  try {
622 
623  Node treeNode = DirectoryTreeTopComponent.this.getSelectedNode();
624  if (treeNode != null) {
625  DirectoryTreeFilterNode.OriginalNode origin = treeNode.getLookup().lookup(DirectoryTreeFilterNode.OriginalNode.class);
626  if (origin == null) {
627  return;
628  }
629  Node originNode = origin.getNode();
630 
631  //set node, wrap in filter node first to filter out children
632  Node drfn = new DataResultFilterNode(originNode, DirectoryTreeTopComponent.this.em);
633  Node kffn = new KnownFileFilterNode(drfn, KnownFileFilterNode.getSelectionContext(originNode));
634  /*
635  * TODO (AUT-1849): Correct or remove peristent column
636  * reordering code
637  *
638  * The following conditional was added to support this
639  * feature.
640  */
641 // if(originNode instanceof DisplayableItemNode) {
642 // dataResult.setNode(new TableFilterNode(kffn, true, ((DisplayableItemNode) originNode).getItemType()));
643 // } else {
644  dataResult.setNode(new TableFilterNode(kffn, true));
645 // }
646 
647  String displayName = "";
648  Content content = originNode.getLookup().lookup(Content.class);
649  if (content != null) {
650  try {
651  displayName = content.getUniquePath();
652  } catch (TskCoreException ex) {
653  logger.log(Level.SEVERE, "Exception while calling Content.getUniquePath() for node: " + originNode); //NON-NLS
654  }
655  } else if (originNode.getLookup().lookup(String.class) != null) {
656  displayName = originNode.getLookup().lookup(String.class);
657  }
658  dataResult.setPath(displayName);
659  }
660 
661  // set the directory listing to be active
662  if (oldNodes != null && newNodes != null
663  && (oldNodes.length == newNodes.length)) {
664  boolean sameNodes = true;
665  for (int i = 0; i < oldNodes.length; i++) {
666  sameNodes = sameNodes && oldNodes[i].getName().equals(newNodes[i].getName());
667  }
668  if (!sameNodes) {
669  dataResult.requestActive();
670  }
671  }
672  } finally {
673  setCursor(null);
674  }
675  }
676  });
677 
678  // update the back and forward list
679  updateHistory(em.getSelectedNodes());
680  }
681 
682  private void updateHistory(Node[] selectedNodes) {
683  if (selectedNodes.length == 0) {
684  return;
685  }
686 
687  Node selectedNode = selectedNodes[0];
688  String selectedNodeName = selectedNode.getName();
689 
690  /*
691  * get the previous entry to make sure we don't duplicate it. Motivation
692  * for this is also that if we used the back button, then we already
693  * added the 'current' node to 'back' and we will detect that and not
694  * reset the forward list.
695  */
696  String[] currentLast = backList.peekLast();
697  String lastNodeName = null;
698  if (currentLast != null) {
699  lastNodeName = currentLast[currentLast.length - 1];
700  }
701 
702  if (currentLast == null || !selectedNodeName.equals(lastNodeName)) {
703  //add to the list if the last if not the same as current
704  final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
705  backList.addLast(selectedPath); // add the node to the "backList"
706  if (backList.size() > 1) {
707  backButton.setEnabled(true);
708  } else {
709  backButton.setEnabled(false);
710  }
711 
712  forwardList.clear(); // clear the "forwardList"
713  forwardButton.setEnabled(false); // disable the forward Button
714  }
715  }
716 
721  private void resetHistory() {
722  // clear the back and forward list
723  backList.clear();
724  forwardList.clear();
725  backButton.setEnabled(false);
726  forwardButton.setEnabled(false);
727  }
728 
729  @Override
730  public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
731  pcs.addPropertyChangeListener(listener);
732  }
733 
734  @Override
735  public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
736  pcs.removePropertyChangeListener(listener);
737  }
738 
744  public BeanTreeView getTree() {
745  return (BeanTreeView) this.jScrollPane1;
746  }
747 
751  public void refreshContentTreeSafe() {
752  SwingUtilities.invokeLater(new Runnable() {
753  @Override
754  public void run() {
756  }
757  });
758  }
759 
763  private void refreshDataSourceTree() {
764  Node selectedNode = getSelectedNode();
765  final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
766 
767  Children rootChildren = em.getRootContext().getChildren();
768  Node dataSourcesFilterNode = rootChildren.findChild(DataSourcesNode.NAME);
769  if (dataSourcesFilterNode == null) {
770  logger.log(Level.SEVERE, "Cannot find data sources filter node, won't refresh the content tree"); //NON-NLS
771  return;
772  }
773  DirectoryTreeFilterNode.OriginalNode imagesNodeOrig = dataSourcesFilterNode.getLookup().lookup(DirectoryTreeFilterNode.OriginalNode.class);
774 
775  if (imagesNodeOrig == null) {
776  logger.log(Level.SEVERE, "Cannot find data sources node, won't refresh the content tree"); //NON-NLS
777  return;
778  }
779 
780  Node imagesNode = imagesNodeOrig.getNode();
781 
782  DataSourcesNode.DataSourcesNodeChildren contentRootChildren = (DataSourcesNode.DataSourcesNodeChildren) imagesNode.getChildren();
783  contentRootChildren.refreshContentKeys();
784 
785  //final TreeView tree = getTree();
786  //tree.expandNode(imagesNode);
787  setSelectedNode(selectedPath, DataSourcesNode.NAME);
788 
789  }
790 
798  private void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName) {
799  if (previouslySelectedNodePath == null) {
800  return;
801  }
802  SwingUtilities.invokeLater(new Runnable() {
803  @Override
804  public void run() {
805  if (previouslySelectedNodePath.length > 0 && (rootNodeName == null || previouslySelectedNodePath[0].equals(rootNodeName))) {
806  Node selectedNode = null;
807  ArrayList<String> selectedNodePath = new ArrayList<>(Arrays.asList(previouslySelectedNodePath));
808  while (null == selectedNode && !selectedNodePath.isEmpty()) {
809  try {
810  selectedNode = NodeOp.findPath(em.getRootContext(), selectedNodePath.toArray(new String[0]));
811  } catch (NodeNotFoundException ex) {
812  // The selected node may have been deleted (e.g., a deleted tag), so truncate the path and try again.
813  if (selectedNodePath.size() > 1) {
814  selectedNodePath.remove(selectedNodePath.size() - 1);
815  } else {
816  StringBuilder nodePath = new StringBuilder();
817  for (int i = 0; i < previouslySelectedNodePath.length; ++i) {
818  nodePath.append(previouslySelectedNodePath[i]).append("/");
819  }
820  logger.log(Level.WARNING, "Failed to find any nodes to select on path " + nodePath.toString(), ex); //NON-NLS
821  break;
822  }
823  }
824  }
825 
826  if (null != selectedNode) {
827  if (rootNodeName != null) {
828  //called from tree auto refresh context
829  //remove last from backlist, because auto select will result in duplication
830  backList.pollLast();
831  }
832  try {
833  em.setExploredContextAndSelection(selectedNode, new Node[]{selectedNode});
834  } catch (PropertyVetoException ex) {
835  logger.log(Level.WARNING, "Property veto from ExplorerManager setting selection to " + selectedNode.getName(), ex); //NON-NLS
836  }
837  }
838  }
839  }
840  });
841  }
842 
843  @Override
844  public TopComponent getTopComponent() {
845  return this;
846  }
847 
848  @Override
849  public boolean hasMenuOpenAction() {
850  return false;
851  }
852 
853  @Override
854  public void viewArtifact(final BlackboardArtifact art) {
855  int typeID = art.getArtifactTypeID();
856  String typeName = art.getArtifactTypeName();
857  Children rootChilds = em.getRootContext().getChildren();
858  Node treeNode = null;
859  Node resultsNode = rootChilds.findChild(ResultsNode.NAME);
860  Children resultsChilds = resultsNode.getChildren();
861  if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) {
862  Node hashsetRootNode = resultsChilds.findChild(typeName);
863  Children hashsetRootChilds = hashsetRootNode.getChildren();
864  try {
865  String setName = null;
866  List<BlackboardAttribute> attributes = art.getAttributes();
867  for (BlackboardAttribute att : attributes) {
868  int typeId = att.getAttributeType().getTypeID();
869  if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
870  setName = att.getValueString();
871  }
872  }
873  treeNode = hashsetRootChilds.findChild(setName);
874  } catch (TskException ex) {
875  logger.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
876  }
877  } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
878  Node keywordRootNode = resultsChilds.findChild(typeName);
879  Children keywordRootChilds = keywordRootNode.getChildren();
880  try {
881  String listName = null;
882  String keywordName = null;
883  List<BlackboardAttribute> attributes = art.getAttributes();
884  for (BlackboardAttribute att : attributes) {
885  int typeId = att.getAttributeType().getTypeID();
886  if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
887  listName = att.getValueString();
888  } else if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) {
889  keywordName = att.getValueString();
890  }
891  }
892  Node listNode = keywordRootChilds.findChild(listName);
893  if (listNode == null) {
894  return;
895  }
896  Children listChildren = listNode.getChildren();
897  if (listChildren == null) {
898  return;
899  }
900  treeNode = listChildren.findChild(keywordName);
901  } catch (TskException ex) {
902  logger.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
903  }
904  } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()
905  || typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
906  Node interestingItemsRootNode = resultsChilds.findChild(typeName);
907  Children interestingItemsRootChildren = interestingItemsRootNode.getChildren();
908  try {
909  String setName = null;
910  List<BlackboardAttribute> attributes = art.getAttributes();
911  for (BlackboardAttribute att : attributes) {
912  int typeId = att.getAttributeType().getTypeID();
913  if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
914  setName = att.getValueString();
915  }
916  }
917  treeNode = interestingItemsRootChildren.findChild(setName);
918  } catch (TskException ex) {
919  logger.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
920  }
921  } else {
922  Node extractedContent = resultsChilds.findChild(ExtractedContent.NAME);
923  Children extractedChilds = extractedContent.getChildren();
924  if (extractedChilds == null) {
925  return;
926  }
927  treeNode = extractedChilds.findChild(typeName);
928  }
929 
930  if (treeNode == null) {
931  return;
932  }
933 
934  try {
935  em.setExploredContextAndSelection(treeNode, new Node[]{treeNode});
936  } catch (PropertyVetoException ex) {
937  logger.log(Level.WARNING, "Property Veto: ", ex); //NON-NLS
938  }
939 
940  // Another thread is needed because we have to wait for dataResult to populate
941  EventQueue.invokeLater(new Runnable() {
942  @Override
943  public void run() {
944  Children resultChilds = dataResult.getRootNode().getChildren();
945  Node select = resultChilds.findChild(Long.toString(art.getArtifactID()));
946  if (select != null) {
947  dataResult.requestActive();
948  dataResult.setSelectedNodes(new Node[]{select});
949  fireViewerComplete();
950  }
951  }
952  });
953  }
954 
955  @Override
956  public void viewArtifactContent(BlackboardArtifact art) {
957  new ViewContextAction(
958  NbBundle.getMessage(this.getClass(), "DirectoryTreeTopComponent.action.viewArtContent.text"),
959  new BlackboardArtifactNode(art)).actionPerformed(null);
960  }
961 
962  @Override
963  public void addOnFinishedListener(PropertyChangeListener l) {
965  }
966 
967  void fireViewerComplete() {
968 
969  try {
970  firePropertyChange(BlackboardResultViewer.FINISHED_DISPLAY_EVT, 0, 1);
971  } catch (Exception e) {
972  logger.log(Level.SEVERE, "DirectoryTreeTopComponent listener threw exception", e); //NON-NLS
973  MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "DirectoryTreeTopComponent.moduleErr"),
974  NbBundle.getMessage(this.getClass(),
975  "DirectoryTreeTopComponent.moduleErr.msg"),
976  MessageNotifyUtil.MessageType.ERROR);
977  }
978  }
979 }
List< Content > getDataSources()
Definition: Case.java:1232
static final String HIDE_KNOWN_FILES_IN_DATA_SOURCES_TREE
static synchronized IngestManager getInstance()
static boolean existsCurrentCase()
Definition: Case.java:966
void respondSelection(final Node[] oldNodes, final Node[] newNodes)
void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName)
void addIngestJobEventListener(final PropertyChangeListener listener)
synchronized void addPropertyChangeListener(PropertyChangeListener listener)
synchronized void removePropertyChangeListener(PropertyChangeListener listener)
void addIngestModuleEventListener(final PropertyChangeListener listener)
synchronized static Logger getLogger(String name)
Definition: Logger.java:166
static void addChangeListener(PreferenceChangeListener listener)
static synchronized DirectoryTreeTopComponent findInstance()
static void addEventSubscriber(Set< String > eventNames, PropertyChangeListener subscriber)
Definition: Case.java:1318

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