Autopsy  4.4
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.Map;
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.apache.commons.lang3.StringUtils;
40 import org.openide.explorer.ExplorerManager;
41 import org.openide.explorer.ExplorerUtils;
42 import org.openide.explorer.view.BeanTreeView;
43 import org.openide.explorer.view.TreeView;
44 import org.openide.nodes.AbstractNode;
45 import org.openide.nodes.Children;
46 import org.openide.nodes.Node;
47 import org.openide.nodes.NodeNotFoundException;
48 import org.openide.nodes.NodeOp;
49 import org.openide.util.NbBundle;
50 import org.openide.util.NbBundle.Messages;
51 import org.openide.windows.TopComponent;
52 import org.openide.windows.WindowManager;
85 import org.sleuthkit.datamodel.Account;
86 import org.sleuthkit.datamodel.BlackboardArtifact;
87 import org.sleuthkit.datamodel.BlackboardAttribute;
88 import org.sleuthkit.datamodel.Content;
89 import org.sleuthkit.datamodel.SleuthkitCase;
90 import org.sleuthkit.datamodel.TskCoreException;
91 
95 // Registered as a service provider for DataExplorer in layer.xml
96 @Messages({
97  "DirectoryTreeTopComponent.resultsView.title=Listing"
98 })
99 public final class DirectoryTreeTopComponent extends TopComponent implements DataExplorer, ExplorerManager.Provider, BlackboardResultViewer {
100 
101  private final transient ExplorerManager em = new ExplorerManager();
103  private final DataResultTopComponent dataResult = new DataResultTopComponent(true, Bundle.DirectoryTreeTopComponent_resultsView_title());
104  private final LinkedList<String[]> backList;
105  private final LinkedList<String[]> forwardList;
106  private static final String PREFERRED_ID = "DirectoryTreeTopComponent"; //NON-NLS
107  private static final Logger LOGGER = Logger.getLogger(DirectoryTreeTopComponent.class.getName());
109 
114  initComponents();
115 
116  // only allow one item to be selected at a time
117  ((BeanTreeView) jScrollPane1).setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
118  // remove the close button
119  putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.TRUE);
120  setName(NbBundle.getMessage(DirectoryTreeTopComponent.class, "CTL_DirectoryTreeTopComponent"));
121  setToolTipText(NbBundle.getMessage(DirectoryTreeTopComponent.class, "HINT_DirectoryTreeTopComponent"));
122 
123  subscribeToChangeEvents();
124  associateLookup(ExplorerUtils.createLookup(em, getActionMap()));
125 
126  // set the back & forward list and also disable the back & forward button
127  this.backList = new LinkedList<>();
128  this.forwardList = new LinkedList<>();
129  backButton.setEnabled(false);
130  forwardButton.setEnabled(false);
131  }
132 
136  private void subscribeToChangeEvents() {
137  UserPreferences.addChangeListener(new PreferenceChangeListener() {
138  @Override
139  public void preferenceChange(PreferenceChangeEvent evt) {
140  switch (evt.getKey()) {
143  refreshContentTreeSafe();
144  break;
147  // TODO: Need a way to refresh the Views subtree
148  break;
149  }
150  }
151  });
152  Case.addEventSubscriber(new HashSet<>(Arrays.asList(Case.Events.CURRENT_CASE.toString(), Case.Events.DATA_SOURCE_ADDED.toString())), this);
153  this.em.addPropertyChangeListener(this);
156  }
157 
159  this.dataResult.requestActive();
160  }
161 
162  public void openDirectoryListing() {
163  this.dataResult.open();
164  }
165 
167  return this.dataResult;
168  }
169 
175  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
176  private void initComponents() {
177 
178  jScrollPane1 = new BeanTreeView();
179  backButton = new javax.swing.JButton();
180  forwardButton = new javax.swing.JButton();
181  showRejectedCheckBox = new javax.swing.JCheckBox();
182 
183  jScrollPane1.setBorder(null);
184 
185  backButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back.png"))); // NOI18N
186  org.openide.awt.Mnemonics.setLocalizedText(backButton, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.backButton.text")); // NOI18N
187  backButton.setBorderPainted(false);
188  backButton.setContentAreaFilled(false);
189  backButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_disabled.png"))); // NOI18N
190  backButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
191  backButton.setMaximumSize(new java.awt.Dimension(55, 100));
192  backButton.setMinimumSize(new java.awt.Dimension(5, 5));
193  backButton.setPreferredSize(new java.awt.Dimension(23, 23));
194  backButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_hover.png"))); // NOI18N
195  backButton.addActionListener(new java.awt.event.ActionListener() {
196  public void actionPerformed(java.awt.event.ActionEvent evt) {
197  backButtonActionPerformed(evt);
198  }
199  });
200 
201  forwardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward.png"))); // NOI18N
202  org.openide.awt.Mnemonics.setLocalizedText(forwardButton, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.forwardButton.text")); // NOI18N
203  forwardButton.setBorderPainted(false);
204  forwardButton.setContentAreaFilled(false);
205  forwardButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_disabled.png"))); // NOI18N
206  forwardButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
207  forwardButton.setMaximumSize(new java.awt.Dimension(55, 100));
208  forwardButton.setMinimumSize(new java.awt.Dimension(5, 5));
209  forwardButton.setPreferredSize(new java.awt.Dimension(23, 23));
210  forwardButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_hover.png"))); // NOI18N
211  forwardButton.addActionListener(new java.awt.event.ActionListener() {
212  public void actionPerformed(java.awt.event.ActionEvent evt) {
213  forwardButtonActionPerformed(evt);
214  }
215  });
216 
217  org.openide.awt.Mnemonics.setLocalizedText(showRejectedCheckBox, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.showRejectedCheckBox.text")); // NOI18N
218 
219  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
220  this.setLayout(layout);
221  layout.setHorizontalGroup(
222  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
223  .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 262, Short.MAX_VALUE)
224  .addGroup(layout.createSequentialGroup()
225  .addGap(5, 5, 5)
226  .addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
227  .addGap(0, 0, 0)
228  .addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
229  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 46, Short.MAX_VALUE)
230  .addComponent(showRejectedCheckBox)
231  .addContainerGap())
232  );
233  layout.setVerticalGroup(
234  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
235  .addGroup(layout.createSequentialGroup()
236  .addGap(5, 5, 5)
237  .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
238  .addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
239  .addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
240  .addComponent(showRejectedCheckBox))
241  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
242  .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 854, Short.MAX_VALUE)
243  .addGap(0, 0, 0))
244  );
245  }// </editor-fold>//GEN-END:initComponents
246 
247  private void backButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_backButtonActionPerformed
248  // change the cursor to "waiting cursor" for this operation
249  this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
250 
251  // the end is the current place,
252  String[] currentNodePath = backList.pollLast();
253  forwardList.addLast(currentNodePath);
254  forwardButton.setEnabled(true);
255 
256  /*
257  * We peek instead of poll because we use its existence in the list
258  * later on so that we do not reset the forward list after the selection
259  * occurs.
260  */
261  String[] newCurrentNodePath = backList.peekLast();
262 
263  // enable / disable the back and forward button
264  if (backList.size() > 1) {
265  backButton.setEnabled(true);
266  } else {
267  backButton.setEnabled(false);
268  }
269 
270  // update the selection on directory tree
271  setSelectedNode(newCurrentNodePath, null);
272 
273  this.setCursor(null);
274  }//GEN-LAST:event_backButtonActionPerformed
275 
276  private void forwardButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_forwardButtonActionPerformed
277  // change the cursor to "waiting cursor" for this operation
278  this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
279 
280  String[] newCurrentNodePath = forwardList.pollLast();
281  if (!forwardList.isEmpty()) {
282  forwardButton.setEnabled(true);
283  } else {
284  forwardButton.setEnabled(false);
285  }
286 
287  backList.addLast(newCurrentNodePath);
288  backButton.setEnabled(true);
289 
290  // update the selection on directory tree
291  setSelectedNode(newCurrentNodePath, null);
292 
293  this.setCursor(null);
294  }//GEN-LAST:event_forwardButtonActionPerformed
295 
296  // Variables declaration - do not modify//GEN-BEGIN:variables
297  private javax.swing.JButton backButton;
298  private javax.swing.JButton forwardButton;
299  private javax.swing.JScrollPane jScrollPane1;
300  private javax.swing.JCheckBox showRejectedCheckBox;
301  // End of variables declaration//GEN-END:variables
302 
311  public static synchronized DirectoryTreeTopComponent getDefault() {
312  if (instance == null) {
313  instance = new DirectoryTreeTopComponent();
314  }
315  return instance;
316  }
317 
324  public static synchronized DirectoryTreeTopComponent findInstance() {
325  WindowManager winManager = WindowManager.getDefault();
326  TopComponent win = winManager.findTopComponent(PREFERRED_ID);
327  if (win == null) {
328  LOGGER.warning(
329  "Cannot find " + PREFERRED_ID + " component. It will not be located properly in the window system."); //NON-NLS
330  return getDefault();
331  }
332  if (win instanceof DirectoryTreeTopComponent) {
333  return (DirectoryTreeTopComponent) win;
334  }
335  LOGGER.warning(
336  "There seem to be multiple components with the '" + PREFERRED_ID //NON-NLS
337  + "' ID. That is a potential source of errors and unexpected behavior."); //NON-NLS
338  return getDefault();
339  }
340 
347  @Override
348  public int getPersistenceType() {
349  return TopComponent.PERSISTENCE_NEVER;
350  }
351 
359  @Override
360  public void componentOpened() {
361  // change the cursor to "waiting cursor" for this operation
362  this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
363  try {
364  Case currentCase = null;
365  try {
366  currentCase = Case.getCurrentCase();
367  } catch (IllegalStateException ex) {
368  /*
369  * No open case.
370  */
371  }
372 
373  // close the top component if there's no image in this case
374  if (null == currentCase || currentCase.hasData() == false) {
375  ((TreeView) this.jScrollPane1).setRootVisible(false); // hide the root
376  } else {
377  // if there's at least one image, load the image and open the top component
378  List<Object> items = new ArrayList<>();
379  final SleuthkitCase tskCase = currentCase.getSleuthkitCase();
380  items.add(new DataSources());
381  items.add(new Views(tskCase));
382  items.add(new Results(tskCase));
383  items.add(new Tags());
384  items.add(new Reports());
385  contentChildren = new RootContentChildren(items);
386 
387  Node root = new AbstractNode(contentChildren) {
392  @Override
393  public Action[] getActions(boolean popup) {
394  return new Action[]{};
395  }
396 
397  // Overide the AbstractNode use of DefaultHandle to return
398  // a handle which can be serialized without a parent
399  @Override
400  public Node.Handle getHandle() {
401  return new Node.Handle() {
402  @Override
403  public Node getNode() throws IOException {
404  return em.getRootContext();
405  }
406  };
407  }
408  };
409 
410  root = new DirectoryTreeFilterNode(root, true);
411 
412  em.setRootContext(root);
413  em.getRootContext().setName(currentCase.getName());
414  em.getRootContext().setDisplayName(currentCase.getName());
415  ((TreeView) this.jScrollPane1).setRootVisible(false); // hide the root
416 
417  // Reset the forward and back lists because we're resetting the root context
418  resetHistory();
419 
420  Children childNodes = em.getRootContext().getChildren();
421  TreeView tree = getTree();
422 
423  Node results = childNodes.findChild(ResultsNode.NAME);
424  tree.expandNode(results);
425 
426  Children resultsChilds = results.getChildren();
427  for (Node n : resultsChilds.getNodes()) {
428  tree.expandNode(n);
429  }
430 
431  Accounts accounts = resultsChilds.findChild(Accounts.NAME).getLookup().lookup(Accounts.class);
432  showRejectedCheckBox.setAction(accounts.newToggleShowRejectedAction());
433  showRejectedCheckBox.setSelected(false);
434 
435  Node views = childNodes.findChild(ViewsNode.NAME);
436  Children viewsChilds = views.getChildren();
437  for (Node n : viewsChilds.getNodes()) {
438  tree.expandNode(n);
439  }
440 
441  tree.collapseNode(views);
442 
443  // if the dataResult is not opened
444  if (!dataResult.isOpened()) {
445  dataResult.open(); // open the data result top component as well when the directory tree is opened
446  }
447 
448  // select the first image node, if there is one
449  // (this has to happen after dataResult is opened, because the event
450  // of changing the selected node fires a handler that tries to make
451  // dataResult active)
452  if (childNodes.getNodesCount() > 0) {
453  try {
454  em.setSelectedNodes(new Node[]{childNodes.getNodeAt(0)});
455  } catch (PropertyVetoException ex) {
456  LOGGER.log(Level.SEVERE, "Error setting default selected node.", ex); //NON-NLS
457  }
458  }
459 
460  }
461  } finally {
462  this.setCursor(null);
463  }
464  }
465 
472  @Override
473  public void componentClosed() {
474  //@@@ push the selection node to null?
475  contentChildren = null;
476  }
477 
478  void writeProperties(java.util.Properties p) {
479  // better to version settings since initial version as advocated at
480  // http://wiki.apidesign.org/wiki/PropertyFiles
481  p.setProperty("version", "1.0");
482  // TODO store your settings
483  }
484 
485  Object readProperties(java.util.Properties p) {
486  if (instance == null) {
487  instance = this;
488  }
489  instance.readPropertiesImpl(p);
490  return instance;
491  }
492 
493  private void readPropertiesImpl(java.util.Properties p) {
494  String version = p.getProperty("version");
495  // TODO read your settings according to their version
496  }
497 
503  @Override
504  protected String preferredID() {
505  return PREFERRED_ID;
506  }
507 
508  @Override
509  public boolean canClose() {
510  /*
511  * Only allow the main tree view in the left side of the main window to
512  * be closed if there is no opne case or the open case has no data
513  * sources.
514  */
515  return !Case.isCaseOpen() || Case.getCurrentCase().hasData() == false;
516  }
517 
523  @Override
524  public ExplorerManager getExplorerManager() {
525  return this.em;
526  }
527 
533  @Override
534  public Action[] getActions() {
535  return new Action[]{};
536  }
537 
543  public Node getSelectedNode() {
544  Node result = null;
545 
546  Node[] selectedNodes = this.getExplorerManager().getSelectedNodes();
547  if (selectedNodes.length > 0) {
548  result = selectedNodes[0];
549  }
550  return result;
551  }
552 
559  @Override
560  public void propertyChange(PropertyChangeEvent evt) {
562  String changed = evt.getPropertyName();
563  if (changed.equals(Case.Events.CURRENT_CASE.toString())) { // changed current case
564  // When a case is closed, the old value of this property is the
565  // closed Case object and the new value is null. When a case is
566  // opened, the old value is null and the new value is the new Case
567  // object.
568  // @@@ This needs to be revisited. Perhaps case closed and case
569  // opened events instead of property change events would be a better
570  // solution. Either way, more probably needs to be done to clean up
571  // data model objects when a case is closed.
572  if (evt.getOldValue() != null && evt.getNewValue() == null) {
573  // The current case has been closed. Reset the ExplorerManager.
574  SwingUtilities.invokeLater(() -> {
575  Node emptyNode = new AbstractNode(Children.LEAF);
576  em.setRootContext(emptyNode);
577  });
578  } else if (evt.getNewValue() != null) {
579  // A new case has been opened. Reset the ExplorerManager.
580  Case newCase = (Case) evt.getNewValue();
581  final String newCaseName = newCase.getName();
582  SwingUtilities.invokeLater(() -> {
583  em.getRootContext().setName(newCaseName);
584  em.getRootContext().setDisplayName(newCaseName);
585 
586  // Reset the forward and back
587  // buttons. Note that a call to CoreComponentControl.openCoreWindows()
588  // by the new Case object will lead to a componentOpened() call
589  // that will repopulate the tree.
590  // @@@ The repopulation of the tree in this fashion also merits
591  // reconsideration.
592  resetHistory();
593  });
594  }
595  } // if the image is added to the case
596  else if (changed.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
603  try {
604  Case currentCase = Case.getCurrentCase();
605  // We only need to trigger openCoreWindows() when the
606  // first data source is added.
607  if (currentCase.getDataSources().size() == 1) {
608  SwingUtilities.invokeLater(() -> {
610  });
611  }
612  } catch (IllegalStateException | TskCoreException notUsed) {
616  }
617  } // change in node selection
618  else if (changed.equals(ExplorerManager.PROP_SELECTED_NODES)) {
619  respondSelection((Node[]) evt.getOldValue(), (Node[]) evt.getNewValue());
620  } else if (changed.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
621  // nothing to do here.
622  // all nodes should be listening for these events and update accordingly.
623  }
624  }
625  }
626 
635  @NbBundle.Messages("DirectoryTreeTopComponent.emptyMimeNode.text=Data not available. Run file type identification module.")
636  private void respondSelection(final Node[] oldNodes, final Node[] newNodes) {
637  if (!Case.isCaseOpen()) {
638  return;
639  }
640 
641  // Some lock that prevents certain Node operations is set during the
642  // ExplorerManager selection-change, so we must handle changes after the
643  // selection-change event is processed.
644  //TODO find a different way to refresh data result viewer, scheduling this
645  //to EDT breaks loading of nodes in the background
646  EventQueue.invokeLater(() -> {
647  // change the cursor to "waiting cursor" for this operation
648  DirectoryTreeTopComponent.this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
649  try {
650  Node treeNode = DirectoryTreeTopComponent.this.getSelectedNode();
651  if (treeNode != null) {
652  Node originNode = ((DirectoryTreeFilterNode) treeNode).getOriginal();
653  //set node, wrap in filter node first to filter out children
654  Node drfn = new DataResultFilterNode(originNode, DirectoryTreeTopComponent.this.em);
655  // Create a TableFilterNode with knowledge of the node's type to allow for column order settings
656  if (FileTypesByMimeType.isEmptyMimeTypeNode(originNode)) {
657  //Special case for when File Type Identification has not yet been run and
658  //there are no mime types to populate Files by Mime Type Tree
659  EmptyNode emptyNode = new EmptyNode(Bundle.DirectoryTreeTopComponent_emptyMimeNode_text());
660  dataResult.setNode(new TableFilterNode(emptyNode, true, "This Node Is Empty")); //NON-NLS
661  } else if (originNode instanceof DisplayableItemNode) {
662  dataResult.setNode(new TableFilterNode(drfn, true, ((DisplayableItemNode) originNode).getItemType()));
663  } else {
664  dataResult.setNode(new TableFilterNode(drfn, true));
665  }
666  String displayName = "";
667  Content content = originNode.getLookup().lookup(Content.class);
668  if (content != null) {
669  try {
670  displayName = content.getUniquePath();
671  } catch (TskCoreException ex) {
672  LOGGER.log(Level.SEVERE, "Exception while calling Content.getUniquePath() for node: {0}", originNode); //NON-NLS
673  }
674  } else if (originNode.getLookup().lookup(String.class) != null) {
675  displayName = originNode.getLookup().lookup(String.class);
676  }
677  dataResult.setPath(displayName);
678  }
679  // set the directory listing to be active
680  if (oldNodes != null && newNodes != null
681  && (oldNodes.length == newNodes.length)) {
682  boolean sameNodes = true;
683  for (int i = 0; i < oldNodes.length; i++) {
684  sameNodes = sameNodes && oldNodes[i].getName().equals(newNodes[i].getName());
685  }
686  if (!sameNodes) {
687  dataResult.requestActive();
688  }
689  }
690  } finally {
691  setCursor(null);
692  }
693  });
694 
695  // update the back and forward list
696  updateHistory(em.getSelectedNodes());
697  }
698 
699  private void updateHistory(Node[] selectedNodes) {
700  if (selectedNodes.length == 0) {
701  return;
702  }
703 
704  Node selectedNode = selectedNodes[0];
705  String selectedNodeName = selectedNode.getName();
706 
707  /*
708  * get the previous entry to make sure we don't duplicate it. Motivation
709  * for this is also that if we used the back button, then we already
710  * added the 'current' node to 'back' and we will detect that and not
711  * reset the forward list.
712  */
713  String[] currentLast = backList.peekLast();
714  String lastNodeName = null;
715  if (currentLast != null) {
716  lastNodeName = currentLast[currentLast.length - 1];
717  }
718 
719  if (currentLast == null || !selectedNodeName.equals(lastNodeName)) {
720  //add to the list if the last if not the same as current
721  final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
722  backList.addLast(selectedPath); // add the node to the "backList"
723  if (backList.size() > 1) {
724  backButton.setEnabled(true);
725  } else {
726  backButton.setEnabled(false);
727  }
728 
729  forwardList.clear(); // clear the "forwardList"
730  forwardButton.setEnabled(false); // disable the forward Button
731  }
732  }
733 
738  private void resetHistory() {
739  // clear the back and forward list
740  backList.clear();
741  forwardList.clear();
742  backButton.setEnabled(false);
743  forwardButton.setEnabled(false);
744  }
745 
751  public BeanTreeView getTree() {
752  return (BeanTreeView) this.jScrollPane1;
753  }
754 
758  public void refreshContentTreeSafe() {
759  SwingUtilities.invokeLater(new Runnable() {
760  @Override
761  public void run() {
762  refreshDataSourceTree();
763  }
764  });
765  }
766 
770  private void refreshDataSourceTree() {
771  Node selectedNode = getSelectedNode();
772  final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
773  Children rootChildren = em.getRootContext().getChildren();
774  Node dataSourcesFilterNode = rootChildren.findChild(DataSourcesNode.NAME);
775  if (dataSourcesFilterNode == null) {
776  LOGGER.log(Level.SEVERE, "Cannot find data sources filter node, won't refresh the content tree"); //NON-NLS
777  return;
778  }
779  Node dataSourcesNode = ((DirectoryTreeFilterNode) dataSourcesFilterNode).getOriginal();
780  DataSourcesNode.DataSourcesNodeChildren contentRootChildren = (DataSourcesNode.DataSourcesNodeChildren) dataSourcesNode.getChildren();
781  contentRootChildren.refreshContentKeys();
782  setSelectedNode(selectedPath, DataSourcesNode.NAME);
783  }
784 
792  private void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName) {
793  if (previouslySelectedNodePath == null) {
794  return;
795  }
796  SwingUtilities.invokeLater(new Runnable() {
797  @Override
798  public void run() {
799  if (previouslySelectedNodePath.length > 0 && (rootNodeName == null || previouslySelectedNodePath[0].equals(rootNodeName))) {
800  Node selectedNode = null;
801  ArrayList<String> selectedNodePath = new ArrayList<>(Arrays.asList(previouslySelectedNodePath));
802  while (null == selectedNode && !selectedNodePath.isEmpty()) {
803  try {
804  selectedNode = NodeOp.findPath(em.getRootContext(), selectedNodePath.toArray(new String[0]));
805  } catch (NodeNotFoundException ex) {
806  // The selected node may have been deleted (e.g., a deleted tag), so truncate the path and try again.
807  if (selectedNodePath.size() > 1) {
808  selectedNodePath.remove(selectedNodePath.size() - 1);
809  } else {
810  StringBuilder nodePath = new StringBuilder();
811  for (int i = 0; i < previouslySelectedNodePath.length; ++i) {
812  nodePath.append(previouslySelectedNodePath[i]).append("/");
813  }
814  LOGGER.log(Level.WARNING, "Failed to find any nodes to select on path " + nodePath.toString(), ex); //NON-NLS
815  break;
816  }
817  }
818  }
819 
820  if (null != selectedNode) {
821  if (rootNodeName != null) {
822  //called from tree auto refresh context
823  //remove last from backlist, because auto select will result in duplication
824  backList.pollLast();
825  }
826  try {
827  em.setExploredContextAndSelection(selectedNode, new Node[]{selectedNode});
828  } catch (PropertyVetoException ex) {
829  LOGGER.log(Level.WARNING, "Property veto from ExplorerManager setting selection to " + selectedNode.getName(), ex); //NON-NLS
830  }
831  }
832  }
833  }
834  });
835  }
836 
837  @Override
838  public TopComponent getTopComponent() {
839  return this;
840  }
841 
842  @Override
843  public boolean hasMenuOpenAction() {
844  return false;
845  }
846 
847  @Override
848  public void viewArtifact(final BlackboardArtifact art) {
849  int typeID = art.getArtifactTypeID();
850  String typeName = art.getArtifactTypeName();
851  Children rootChilds = em.getRootContext().getChildren();
852  Node treeNode = null;
853  Node resultsNode = rootChilds.findChild(ResultsNode.NAME);
854  Children resultsChilds = resultsNode.getChildren();
855  if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) {
856  Node hashsetRootNode = resultsChilds.findChild(typeName);
857  Children hashsetRootChilds = hashsetRootNode.getChildren();
858  try {
859  String setName = null;
860  List<BlackboardAttribute> attributes = art.getAttributes();
861  for (BlackboardAttribute att : attributes) {
862  int typeId = att.getAttributeType().getTypeID();
863  if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
864  setName = att.getValueString();
865  }
866  }
867  treeNode = hashsetRootChilds.findChild(setName);
868  } catch (TskCoreException ex) {
869  LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
870  }
871  } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
872  Node keywordRootNode = resultsChilds.findChild(typeName);
873  Children keywordRootChilds = keywordRootNode.getChildren();
874  try {
875  String listName = null;
876  String keywordName = null;
877  String regex = 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  } else if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()) {
886  regex = att.getValueString();
887  }
888  }
889  if (listName == null) {
890  if (regex == null) { //using same labels used for creation
891  listName = NbBundle.getMessage(KeywordHits.class, "KeywordHits.simpleLiteralSearch.text");
892  } else {
893  listName = NbBundle.getMessage(KeywordHits.class, "KeywordHits.singleRegexSearch.text");
894  }
895  }
896  Node listNode = keywordRootChilds.findChild(listName);
897  if (listNode == null) {
898  return;
899  }
900  Children listChildren = listNode.getChildren();
901  if (listChildren == null) {
902  return;
903  }
904  if (regex != null) { //For support of regex nodes such as URLs, IPs, Phone Numbers, and Email Addrs as they are down another level
905  Node regexNode = listChildren.findChild(regex);
906  if (regexNode == null) {
907  return;
908  }
909  listChildren = regexNode.getChildren();
910  if (listChildren == null) {
911  return;
912  }
913  }
914 
915  treeNode = listChildren.findChild(keywordName);
916 
917  } catch (TskCoreException ex) {
918  LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
919  }
920  } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()
921  || typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
922  Node interestingItemsRootNode = resultsChilds.findChild(NbBundle
923  .getMessage(InterestingHits.class, "InterestingHits.interestingItems.text"));
924  Children interestingItemsRootChildren = interestingItemsRootNode.getChildren();
925  try {
926  String setName = null;
927  List<BlackboardAttribute> attributes = art.getAttributes();
928  for (BlackboardAttribute att : attributes) {
929  int typeId = att.getAttributeType().getTypeID();
930  if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
931  setName = att.getValueString();
932  }
933  }
934  Node setNode = interestingItemsRootChildren.findChild(setName);
935  if (setNode == null) {
936  return;
937  }
938  Children interestingChildren = setNode.getChildren();
939  if (interestingChildren == null) {
940  return;
941  }
942  treeNode = interestingChildren.findChild(art.getDisplayName());
943  } catch (TskCoreException ex) {
944  LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
945  }
946  } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) {
947  Node emailMsgRootNode = resultsChilds.findChild(typeName);
948  Children emailMsgRootChilds = emailMsgRootNode.getChildren();
949  Map<String, String> parsedPath = null;
950  try {
951  List<BlackboardAttribute> attributes = art.getAttributes();
952  for (BlackboardAttribute att : attributes) {
953  int typeId = att.getAttributeType().getTypeID();
954  if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID()) {
955  parsedPath = EmailExtracted.parsePath(att.getValueString());
956  break;
957  }
958  }
959  if (parsedPath == null) {
960  return;
961  }
962  Node defaultNode = emailMsgRootChilds.findChild(parsedPath.get(NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultAcct.text")));
963  Children defaultChildren = defaultNode.getChildren();
964  treeNode = defaultChildren.findChild(parsedPath.get(NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultFolder.text")));
965  } catch (TskCoreException ex) {
966  LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
967  }
968 
969  } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
970  Node accountRootNode = resultsChilds.findChild(art.getDisplayName());
971  Children accountRootChilds = accountRootNode.getChildren();
972  List<BlackboardAttribute> attributes;
973  String accountType = null;
974  String ccNumberName = null;
975  try {
976  attributes = art.getAttributes();
977  for (BlackboardAttribute att : attributes) {
978  int typeId = att.getAttributeType().getTypeID();
979  if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()) {
980  accountType = att.getValueString();
981  }
982  if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID()) {
983  ccNumberName = att.getValueString();
984  }
985  }
986  if (accountType == null) {
987  return;
988  }
989 
990  if (accountType.equals(Account.Type.CREDIT_CARD.name())) {
991  Node accountNode = accountRootChilds.findChild(Account.Type.CREDIT_CARD.getDisplayName());
992  if (accountNode == null) {
993  return;
994  }
995  Children accountChildren = accountNode.getChildren();
996  if (accountChildren == null) {
997  return;
998  }
999  Node binNode = accountChildren.findChild(NbBundle.getMessage(Accounts.class, "Accounts.ByBINNode.name"));
1000  if (binNode == null) {
1001  return;
1002  }
1003  Children binChildren = binNode.getChildren();
1004  if (ccNumberName == null) {
1005  return;
1006  }
1007  //right padded with 0s to 8 digits when single number
1008  //when a range of numbers, the first 6 digits are rightpadded with 0s to 8 digits then a dash then 3 digits, the 6,7,8, digits of the end number right padded with 9s
1009  String binName = StringUtils.rightPad(ccNumberName, 8, "0");
1010  binName = binName.substring(0, 8);
1011  int bin;
1012  try {
1013  bin = Integer.parseInt(binName);
1014  } catch (NumberFormatException ex) {
1015  LOGGER.log(Level.WARNING, "Unable to parseInt a BIN for node selection from string binName=" + binName, ex); //NON-NLS
1016  return;
1017  }
1019  if (binInfo != null) {
1020  int startBin = ((BINRange) binInfo).getBINstart();
1021  int endBin = ((BINRange) binInfo).getBINend();
1022  if (startBin != endBin) {
1023  binName = Integer.toString(startBin) + "-" + Integer.toString(endBin).substring(5); //if there is a range re-construct the name it appears as
1024  }
1025  }
1026  if (binName == null) {
1027  return;
1028  }
1029  treeNode = binChildren.findChild(binName);
1030  } else { //default account type
1031  treeNode = accountRootChilds.findChild(accountType);;
1032  }
1033  } catch (TskCoreException ex) {
1034  LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
1035  }
1036  } else {
1037  Node extractedContent = resultsChilds.findChild(ExtractedContent.NAME);
1038  Children extractedChilds = extractedContent.getChildren();
1039  if (extractedChilds == null) {
1040  return;
1041  }
1042  treeNode = extractedChilds.findChild(typeName);
1043  }
1044 
1045  if (treeNode == null) {
1046  return;
1047  }
1048 
1049  DisplayableItemNode undecoratedParentNode = (DisplayableItemNode) ((DirectoryTreeFilterNode) treeNode).getOriginal();
1050  undecoratedParentNode.setChildNodeSelectionInfo(new ArtifactNodeSelectionInfo(art));
1051  getTree().expandNode(treeNode);
1052  try {
1053  em.setExploredContextAndSelection(treeNode, new Node[]{treeNode});
1054  } catch (PropertyVetoException ex) {
1055  LOGGER.log(Level.WARNING, "Property Veto: ", ex); //NON-NLS
1056  }
1057  // Another thread is needed because we have to wait for dataResult to populate
1058  }
1059 
1060  @Override
1061  public void viewArtifactContent(BlackboardArtifact art) {
1062  new ViewContextAction(
1063  NbBundle.getMessage(this.getClass(), "DirectoryTreeTopComponent.action.viewArtContent.text"),
1064  new BlackboardArtifactNode(art)).actionPerformed(null);
1065  }
1066 
1067  @Override
1068  public void addOnFinishedListener(PropertyChangeListener l) {
1069  DirectoryTreeTopComponent.this.addPropertyChangeListener(l);
1070  }
1071 
1072  void fireViewerComplete() {
1073 
1074  try {
1075  firePropertyChange(BlackboardResultViewer.FINISHED_DISPLAY_EVT, 0, 1);
1076  } catch (Exception e) {
1077  LOGGER.log(Level.SEVERE, "DirectoryTreeTopComponent listener threw exception", e); //NON-NLS
1078  MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "DirectoryTreeTopComponent.moduleErr"),
1079  NbBundle.getMessage(this.getClass(),
1080  "DirectoryTreeTopComponent.moduleErr.msg"),
1081  MessageNotifyUtil.MessageType.ERROR);
1082  }
1083  }
1084 }
List< Content > getDataSources()
Definition: Case.java:1266
static final Map< String, String > parsePath(String path)
static synchronized IngestManager getInstance()
void respondSelection(final Node[] oldNodes, final Node[] newNodes)
void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName)
static synchronized BankIdentificationNumber getBINInfo(int bin)
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)
void setChildNodeSelectionInfo(NodeSelectionInfo selectedChildNodeInfo)
static synchronized DirectoryTreeTopComponent findInstance()
static void addEventSubscriber(Set< String > eventNames, PropertyChangeListener subscriber)
Definition: Case.java:381

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