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-2016 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;
75 import org.sleuthkit.datamodel.BlackboardArtifact;
76 import org.sleuthkit.datamodel.BlackboardAttribute;
77 import org.sleuthkit.datamodel.Content;
78 import org.sleuthkit.datamodel.SleuthkitCase;
79 import org.sleuthkit.datamodel.TskCoreException;
80 import org.sleuthkit.datamodel.TskException;
81 
85 // Registered as a service provider for DataExplorer in layer.xml
86 public final class DirectoryTreeTopComponent extends TopComponent implements DataExplorer, ExplorerManager.Provider, BlackboardResultViewer {
87 
88  private final transient ExplorerManager em = new ExplorerManager();
90  private final DataResultTopComponent dataResult = new DataResultTopComponent(true, NbBundle.getMessage(this.getClass(),
91  "DirectoryTreeTopComponent.title.text"));
92  private final LinkedList<String[]> backList;
93  private final LinkedList<String[]> forwardList;
94  private static final String PREFERRED_ID = "DirectoryTreeTopComponent"; //NON-NLS
95  private static final Logger logger = Logger.getLogger(DirectoryTreeTopComponent.class.getName());
97 
102  initComponents();
103 
104  // only allow one item to be selected at a time
105  ((BeanTreeView) jScrollPane1).setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
106  // remove the close button
107  putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.TRUE);
108  setName(NbBundle.getMessage(DirectoryTreeTopComponent.class, "CTL_DirectoryTreeTopComponent"));
109  setToolTipText(NbBundle.getMessage(DirectoryTreeTopComponent.class, "HINT_DirectoryTreeTopComponent"));
110 
112  associateLookup(ExplorerUtils.createLookup(em, getActionMap()));
113 
114  // set the back & forward list and also disable the back & forward button
115  this.backList = new LinkedList<>();
116  this.forwardList = new LinkedList<>();
117  backButton.setEnabled(false);
118  forwardButton.setEnabled(false);
119  }
120 
124  private void subscribeToChangeEvents() {
125  UserPreferences.addChangeListener(new PreferenceChangeListener() {
126  @Override
127  public void preferenceChange(PreferenceChangeEvent evt) {
128  switch (evt.getKey()) {
131  break;
133  // TODO: Need a way to refresh the Views subtree
134  break;
135  }
136  }
137  });
138  Case.addEventSubscriber(new HashSet<>(Arrays.asList(Case.Events.CURRENT_CASE.toString(), Case.Events.DATA_SOURCE_ADDED.toString())), this);
139  this.em.addPropertyChangeListener(this);
142  }
143 
145  this.dataResult.requestActive();
146  }
147 
148  public void openDirectoryListing() {
149  this.dataResult.open();
150  }
151 
153  return this.dataResult;
154  }
155 
161  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
162  private void initComponents() {
163 
164  jScrollPane1 = new BeanTreeView();
165  backButton = new javax.swing.JButton();
166  forwardButton = new javax.swing.JButton();
167  showRejectedCheckBox = new javax.swing.JCheckBox();
168 
169  jScrollPane1.setBorder(null);
170 
171  backButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back.png"))); // NOI18N
172  org.openide.awt.Mnemonics.setLocalizedText(backButton, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.backButton.text")); // NOI18N
173  backButton.setBorderPainted(false);
174  backButton.setContentAreaFilled(false);
175  backButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_disabled.png"))); // NOI18N
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"))); // NOI18N
181  backButton.addActionListener(new java.awt.event.ActionListener() {
182  public void actionPerformed(java.awt.event.ActionEvent evt) {
184  }
185  });
186 
187  forwardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward.png"))); // NOI18N
188  org.openide.awt.Mnemonics.setLocalizedText(forwardButton, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.forwardButton.text")); // NOI18N
189  forwardButton.setBorderPainted(false);
190  forwardButton.setContentAreaFilled(false);
191  forwardButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_disabled.png"))); // NOI18N
192  forwardButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
193  forwardButton.setMaximumSize(new java.awt.Dimension(55, 100));
194  forwardButton.setMinimumSize(new java.awt.Dimension(5, 5));
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"))); // NOI18N
197  forwardButton.addActionListener(new java.awt.event.ActionListener() {
198  public void actionPerformed(java.awt.event.ActionEvent evt) {
200  }
201  });
202 
203  org.openide.awt.Mnemonics.setLocalizedText(showRejectedCheckBox, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.showRejectedCheckBox.text")); // NOI18N
204 
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()
211  .addGap(5, 5, 5)
212  .addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
213  .addGap(0, 0, 0)
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)
216  .addComponent(showRejectedCheckBox)
217  .addContainerGap())
218  );
219  layout.setVerticalGroup(
220  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
221  .addGroup(layout.createSequentialGroup()
222  .addGap(5, 5, 5)
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)
226  .addComponent(showRejectedCheckBox))
227  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
228  .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 838, javax.swing.GroupLayout.PREFERRED_SIZE)
229  .addContainerGap())
230  );
231  }// </editor-fold>//GEN-END:initComponents
232 
233  private void backButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_backButtonActionPerformed
234  // change the cursor to "waiting cursor" for this operation
235  this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
236 
237  // the end is the current place,
238  String[] currentNodePath = backList.pollLast();
239  forwardList.addLast(currentNodePath);
240  forwardButton.setEnabled(true);
241 
242  /*
243  * We peek instead of poll because we use its existence in the list
244  * later on so that we do not reset the forward list after the selection
245  * occurs.
246  */
247  String[] newCurrentNodePath = backList.peekLast();
248 
249  // enable / disable the back and forward button
250  if (backList.size() > 1) {
251  backButton.setEnabled(true);
252  } else {
253  backButton.setEnabled(false);
254  }
255 
256  // update the selection on directory tree
257  setSelectedNode(newCurrentNodePath, null);
258 
259  this.setCursor(null);
260  }//GEN-LAST:event_backButtonActionPerformed
261 
262  private void forwardButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_forwardButtonActionPerformed
263  // change the cursor to "waiting cursor" for this operation
264  this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
265 
266  String[] newCurrentNodePath = forwardList.pollLast();
267  if (!forwardList.isEmpty()) {
268  forwardButton.setEnabled(true);
269  } else {
270  forwardButton.setEnabled(false);
271  }
272 
273  backList.addLast(newCurrentNodePath);
274  backButton.setEnabled(true);
275 
276  // update the selection on directory tree
277  setSelectedNode(newCurrentNodePath, null);
278 
279  this.setCursor(null);
280  }//GEN-LAST:event_forwardButtonActionPerformed
281 
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.JCheckBox showRejectedCheckBox;
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.isCaseOpen()) {
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 
364  Node root = new AbstractNode(contentChildren) {
369  @Override
370  public Action[] getActions(boolean popup) {
371  return new Action[]{};
372  }
373 
374  // Overide the AbstractNode use of DefaultHandle to return
375  // a handle which can be serialized without a parent
376  @Override
377  public Node.Handle getHandle() {
378  return new Node.Handle() {
379  @Override
380  public Node getNode() throws IOException {
381  return em.getRootContext();
382  }
383  };
384  }
385  };
386 
387  root = new DirectoryTreeFilterNode(root, true);
388 
389  em.setRootContext(root);
390  em.getRootContext().setName(currentCase.getName());
391  em.getRootContext().setDisplayName(currentCase.getName());
392  ((BeanTreeView) this.jScrollPane1).setRootVisible(false); // hide the root
393 
394  // Reset the forward and back lists because we're resetting the root context
395  resetHistory();
396 
397  Children childNodes = em.getRootContext().getChildren();
398  TreeView tree = getTree();
399 
400  Node results = childNodes.findChild(ResultsNode.NAME);
401  tree.expandNode(results);
402 
403  Children resultsChilds = results.getChildren();
404  tree.expandNode(resultsChilds.findChild(KeywordHits.NAME));
405  tree.expandNode(resultsChilds.findChild(ExtractedContent.NAME));
406 
407  Accounts accounts = resultsChilds.findChild(Accounts.NAME).getLookup().lookup(Accounts.class);
409  showRejectedCheckBox.setSelected(false);
410 
411  Node views = childNodes.findChild(ViewsNode.NAME);
412  Children viewsChilds = views.getChildren();
413  for (Node n : viewsChilds.getNodes()) {
414  tree.expandNode(n);
415  }
416 
417  tree.collapseNode(views);
418 
419  // if the dataResult is not opened
420  if (!dataResult.isOpened()) {
421  dataResult.open(); // open the data result top component as well when the directory tree is opened
422  }
423 
424  // select the first image node, if there is one
425  // (this has to happen after dataResult is opened, because the event
426  // of changing the selected node fires a handler that tries to make
427  // dataResult active)
428  if (childNodes.getNodesCount() > 0) {
429  try {
430  em.setSelectedNodes(new Node[]{childNodes.getNodeAt(0)});
431  } catch (Exception ex) {
432  logger.log(Level.SEVERE, "Error setting default selected node.", ex); //NON-NLS
433  }
434  }
435 
436  }
437  }
438  } finally {
439  this.setCursor(null);
440  }
441  }
442 
449  @Override
450  public void componentClosed() {
451  //@@@ push the selection node to null?
452  contentChildren = null;
453  }
454 
455  void writeProperties(java.util.Properties p) {
456  // better to version settings since initial version as advocated at
457  // http://wiki.apidesign.org/wiki/PropertyFiles
458  p.setProperty("version", "1.0");
459  // TODO store your settings
460  }
461 
462  Object readProperties(java.util.Properties p) {
463  if (instance == null) {
464  instance = this;
465  }
466  instance.readPropertiesImpl(p);
467  return instance;
468  }
469 
470  private void readPropertiesImpl(java.util.Properties p) {
471  String version = p.getProperty("version");
472  // TODO read your settings according to their version
473  }
474 
480  @Override
481  protected String preferredID() {
482  return PREFERRED_ID;
483  }
484 
485  @Override
486  public boolean canClose() {
487  return !Case.isCaseOpen() || Case.getCurrentCase().hasData() == false; // only allow this window to be closed when there's no case opened or no image in this case
488  }
489 
495  @Override
496  public ExplorerManager getExplorerManager() {
497  return this.em;
498  }
499 
505  @Override
506  public Action[] getActions() {
507  return new Action[]{};
508  }
509 
515  public Node getSelectedNode() {
516  Node result = null;
517 
518  Node[] selectedNodes = this.getExplorerManager().getSelectedNodes();
519  if (selectedNodes.length > 0) {
520  result = selectedNodes[0];
521  }
522  return result;
523  }
524 
531  @Override
532  public void propertyChange(PropertyChangeEvent evt) {
534  String changed = evt.getPropertyName();
535  if (changed.equals(Case.Events.CURRENT_CASE.toString())) { // changed current case
536  // When a case is closed, the old value of this property is the
537  // closed Case object and the new value is null. When a case is
538  // opened, the old value is null and the new value is the new Case
539  // object.
540  // @@@ This needs to be revisited. Perhaps case closed and case
541  // opened events instead of property change events would be a better
542  // solution. Either way, more probably needs to be done to clean up
543  // data model objects when a case is closed.
544  if (evt.getOldValue() != null && evt.getNewValue() == null) {
545  // The current case has been closed. Reset the ExplorerManager.
546  SwingUtilities.invokeLater(() -> {
547  Node emptyNode = new AbstractNode(Children.LEAF);
548  em.setRootContext(emptyNode);
549  });
550  } else if (evt.getNewValue() != null) {
551  // A new case has been opened. Reset the ExplorerManager.
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);
557 
558  // Reset the forward and back
559  // buttons. Note that a call to CoreComponentControl.openCoreWindows()
560  // by the new Case object will lead to a componentOpened() call
561  // that will repopulate the tree.
562  // @@@ The repopulation of the tree in this fashion also merits
563  // reconsideration.
564  resetHistory();
565  });
566  }
567  } // if the image is added to the case
568  else if (changed.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
575  try {
576  Case currentCase = Case.getCurrentCase();
577  // We only need to trigger openCoreWindows() when the
578  // first data source is added.
579  if (currentCase.getDataSources().size() == 1) {
580  SwingUtilities.invokeLater(() -> {
582  });
583  }
584  } catch (IllegalStateException | TskCoreException notUsed) {
588  }
589  } // change in node selection
590  else if (changed.equals(ExplorerManager.PROP_SELECTED_NODES)) {
591  SwingUtilities.invokeLater(() -> {
592  respondSelection((Node[]) evt.getOldValue(), (Node[]) evt.getNewValue());
593  });
594  } else if (changed.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
595  // nothing to do here.
596  // all nodes should be listening for these events and update accordingly.
597  }
598  }
599  }
600 
609  private void respondSelection(final Node[] oldNodes, final Node[] newNodes) {
610  if (!Case.isCaseOpen()) {
611  //handle in-between condition when case is being closed
612  //and legacy selection events are pumped
613  return;
614  }
615 
616  // Some lock that prevents certain Node operations is set during the
617  // ExplorerManager selection-change, so we must handle changes after the
618  // selection-change event is processed.
619  //TODO find a different way to refresh data result viewer, scheduling this
620  //to EDT breaks loading of nodes in the background
621  EventQueue.invokeLater(new Runnable() {
622  @Override
623  public void run() {
624  // change the cursor to "waiting cursor" for this operation
625  DirectoryTreeTopComponent.this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
626  try {
627 
628  Node treeNode = DirectoryTreeTopComponent.this.getSelectedNode();
629  if (treeNode != null) {
630  DirectoryTreeFilterNode.OriginalNode origin = treeNode.getLookup().lookup(DirectoryTreeFilterNode.OriginalNode.class);
631  if (origin == null) {
632  return;
633  }
634  Node originNode = origin.getNode();
635 
636  //set node, wrap in filter node first to filter out children
637  Node drfn = new DataResultFilterNode(originNode, DirectoryTreeTopComponent.this.em);
638  Node kffn = new KnownFileFilterNode(drfn, KnownFileFilterNode.getSelectionContext(originNode));
639  /*
640  * TODO (AUT-1849): Correct or remove peristent column
641  * reordering code
642  *
643  * The following conditional was added to support this
644  * feature.
645  */
646 // if(originNode instanceof DisplayableItemNode) {
647 // dataResult.setNode(new TableFilterNode(kffn, true, ((DisplayableItemNode) originNode).getItemType()));
648 // } else {
649  dataResult.setNode(new TableFilterNode(kffn, true));
650 // }
651 
652  String displayName = "";
653  Content content = originNode.getLookup().lookup(Content.class);
654  if (content != null) {
655  try {
656  displayName = content.getUniquePath();
657  } catch (TskCoreException ex) {
658  logger.log(Level.SEVERE, "Exception while calling Content.getUniquePath() for node: " + originNode); //NON-NLS
659  }
660  } else if (originNode.getLookup().lookup(String.class) != null) {
661  displayName = originNode.getLookup().lookup(String.class);
662  }
663  dataResult.setPath(displayName);
664  }
665 
666  // set the directory listing to be active
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());
672  }
673  if (!sameNodes) {
674  dataResult.requestActive();
675  }
676  }
677  } finally {
678  setCursor(null);
679  }
680  }
681  });
682 
683  // update the back and forward list
684  updateHistory(em.getSelectedNodes());
685  }
686 
687  private void updateHistory(Node[] selectedNodes) {
688  if (selectedNodes.length == 0) {
689  return;
690  }
691 
692  Node selectedNode = selectedNodes[0];
693  String selectedNodeName = selectedNode.getName();
694 
695  /*
696  * get the previous entry to make sure we don't duplicate it. Motivation
697  * for this is also that if we used the back button, then we already
698  * added the 'current' node to 'back' and we will detect that and not
699  * reset the forward list.
700  */
701  String[] currentLast = backList.peekLast();
702  String lastNodeName = null;
703  if (currentLast != null) {
704  lastNodeName = currentLast[currentLast.length - 1];
705  }
706 
707  if (currentLast == null || !selectedNodeName.equals(lastNodeName)) {
708  //add to the list if the last if not the same as current
709  final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
710  backList.addLast(selectedPath); // add the node to the "backList"
711  if (backList.size() > 1) {
712  backButton.setEnabled(true);
713  } else {
714  backButton.setEnabled(false);
715  }
716 
717  forwardList.clear(); // clear the "forwardList"
718  forwardButton.setEnabled(false); // disable the forward Button
719  }
720  }
721 
726  private void resetHistory() {
727  // clear the back and forward list
728  backList.clear();
729  forwardList.clear();
730  backButton.setEnabled(false);
731  forwardButton.setEnabled(false);
732  }
733 
739  public BeanTreeView getTree() {
740  return (BeanTreeView) this.jScrollPane1;
741  }
742 
746  public void refreshContentTreeSafe() {
747  SwingUtilities.invokeLater(new Runnable() {
748  @Override
749  public void run() {
751  }
752  });
753  }
754 
758  private void refreshDataSourceTree() {
759  Node selectedNode = getSelectedNode();
760  final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
761 
762  Children rootChildren = em.getRootContext().getChildren();
763  Node dataSourcesFilterNode = rootChildren.findChild(DataSourcesNode.NAME);
764  if (dataSourcesFilterNode == null) {
765  logger.log(Level.SEVERE, "Cannot find data sources filter node, won't refresh the content tree"); //NON-NLS
766  return;
767  }
768  DirectoryTreeFilterNode.OriginalNode imagesNodeOrig = dataSourcesFilterNode.getLookup().lookup(DirectoryTreeFilterNode.OriginalNode.class);
769 
770  if (imagesNodeOrig == null) {
771  logger.log(Level.SEVERE, "Cannot find data sources node, won't refresh the content tree"); //NON-NLS
772  return;
773  }
774 
775  Node imagesNode = imagesNodeOrig.getNode();
776 
777  DataSourcesNode.DataSourcesNodeChildren contentRootChildren = (DataSourcesNode.DataSourcesNodeChildren) imagesNode.getChildren();
778  contentRootChildren.refreshContentKeys();
779 
780  //final TreeView tree = getTree();
781  //tree.expandNode(imagesNode);
782  setSelectedNode(selectedPath, DataSourcesNode.NAME);
783 
784  }
785 
793  private void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName) {
794  if (previouslySelectedNodePath == null) {
795  return;
796  }
797  SwingUtilities.invokeLater(new Runnable() {
798  @Override
799  public void run() {
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()) {
804  try {
805  selectedNode = NodeOp.findPath(em.getRootContext(), selectedNodePath.toArray(new String[0]));
806  } catch (NodeNotFoundException ex) {
807  // The selected node may have been deleted (e.g., a deleted tag), so truncate the path and try again.
808  if (selectedNodePath.size() > 1) {
809  selectedNodePath.remove(selectedNodePath.size() - 1);
810  } else {
811  StringBuilder nodePath = new StringBuilder();
812  for (int i = 0; i < previouslySelectedNodePath.length; ++i) {
813  nodePath.append(previouslySelectedNodePath[i]).append("/");
814  }
815  logger.log(Level.WARNING, "Failed to find any nodes to select on path " + nodePath.toString(), ex); //NON-NLS
816  break;
817  }
818  }
819  }
820 
821  if (null != selectedNode) {
822  if (rootNodeName != null) {
823  //called from tree auto refresh context
824  //remove last from backlist, because auto select will result in duplication
825  backList.pollLast();
826  }
827  try {
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); //NON-NLS
831  }
832  }
833  }
834  }
835  });
836  }
837 
838  @Override
839  public TopComponent getTopComponent() {
840  return this;
841  }
842 
843  @Override
844  public boolean hasMenuOpenAction() {
845  return false;
846  }
847 
848  @Override
849  public void viewArtifact(final BlackboardArtifact art) {
850  int typeID = art.getArtifactTypeID();
851  String typeName = art.getArtifactTypeName();
852  Children rootChilds = em.getRootContext().getChildren();
853  Node treeNode = null;
854  Node resultsNode = rootChilds.findChild(ResultsNode.NAME);
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();
859  try {
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();
866  }
867  }
868  treeNode = hashsetRootChilds.findChild(setName);
869  } catch (TskException ex) {
870  logger.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
871  }
872  } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
873  Node keywordRootNode = resultsChilds.findChild(typeName);
874  Children keywordRootChilds = keywordRootNode.getChildren();
875  try {
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();
885  }
886  }
887  Node listNode = keywordRootChilds.findChild(listName);
888  if (listNode == null) {
889  return;
890  }
891  Children listChildren = listNode.getChildren();
892  if (listChildren == null) {
893  return;
894  }
895  treeNode = listChildren.findChild(keywordName);
896  } catch (TskException ex) {
897  logger.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
898  }
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();
903  try {
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();
910  }
911  }
912  treeNode = interestingItemsRootChildren.findChild(setName);
913  } catch (TskException ex) {
914  logger.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
915  }
916  } else {
917  Node extractedContent = resultsChilds.findChild(ExtractedContent.NAME);
918  Children extractedChilds = extractedContent.getChildren();
919  if (extractedChilds == null) {
920  return;
921  }
922  treeNode = extractedChilds.findChild(typeName);
923  }
924 
925  if (treeNode == null) {
926  return;
927  }
928 
929  try {
930  em.setExploredContextAndSelection(treeNode, new Node[]{treeNode});
931  } catch (PropertyVetoException ex) {
932  logger.log(Level.WARNING, "Property Veto: ", ex); //NON-NLS
933  }
934 
935  // Another thread is needed because we have to wait for dataResult to populate
936  EventQueue.invokeLater(new Runnable() {
937  @Override
938  public void run() {
939  Children resultChilds = dataResult.getRootNode().getChildren();
940  Node select = resultChilds.findChild(Long.toString(art.getArtifactID()));
941  if (select != null) {
942  dataResult.requestActive();
943  dataResult.setSelectedNodes(new Node[]{select});
944  fireViewerComplete();
945  }
946  }
947  });
948  }
949 
950  @Override
951  public void viewArtifactContent(BlackboardArtifact art) {
952  new ViewContextAction(
953  NbBundle.getMessage(this.getClass(), "DirectoryTreeTopComponent.action.viewArtContent.text"),
954  new BlackboardArtifactNode(art)).actionPerformed(null);
955  }
956 
957  @Override
958  public void addOnFinishedListener(PropertyChangeListener l) {
959  DirectoryTreeTopComponent.this.addPropertyChangeListener(l);
960  }
961 
962  void fireViewerComplete() {
963 
964  try {
965  firePropertyChange(BlackboardResultViewer.FINISHED_DISPLAY_EVT, 0, 1);
966  } catch (Exception e) {
967  logger.log(Level.SEVERE, "DirectoryTreeTopComponent listener threw exception", e); //NON-NLS
968  MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "DirectoryTreeTopComponent.moduleErr"),
969  NbBundle.getMessage(this.getClass(),
970  "DirectoryTreeTopComponent.moduleErr.msg"),
971  MessageNotifyUtil.MessageType.ERROR);
972  }
973  }
974 }
List< Content > getDataSources()
Definition: Case.java:617
static final String HIDE_KNOWN_FILES_IN_DATA_SOURCES_TREE
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)
void addIngestModuleEventListener(final PropertyChangeListener listener)
synchronized static Logger getLogger(String name)
Definition: Logger.java:161
static void addChangeListener(PreferenceChangeListener listener)
static synchronized DirectoryTreeTopComponent findInstance()
static void addEventSubscriber(Set< String > eventNames, PropertyChangeListener subscriber)
Definition: Case.java:330

Copyright © 2012-2016 Basis Technology. Generated on: Tue Oct 25 2016
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.