Autopsy  3.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-2014 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.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.JPanel;
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;
79 
83 // Registered as a service provider for DataExplorer in layer.xml
84 public final class DirectoryTreeTopComponent extends TopComponent implements DataExplorer, ExplorerManager.Provider, BlackboardResultViewer {
85 
86  private transient ExplorerManager em = new ExplorerManager();
88  private DataResultTopComponent dataResult = new DataResultTopComponent(true, NbBundle.getMessage(this.getClass(),
89  "DirectoryTreeTopComponent.title.text"));
90  private LinkedList<String[]> backList;
91  private LinkedList<String[]> forwardList;
95 // static final String ICON_PATH = "SET/PATH/TO/ICON/HERE";
96  private static final String PREFERRED_ID = "DirectoryTreeTopComponent"; //NON-NLS
97  private PropertyChangeSupport pcs;
98  // for error handling
99  private JPanel caller;
100  private String className = this.getClass().toString();
101  private static final Logger logger = Logger.getLogger(DirectoryTreeTopComponent.class.getName());
103 
108  initComponents();
109 
110  // only allow one item to be selected at a time
111  ((BeanTreeView) jScrollPane1).setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
112  // remove the close button
113  putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.TRUE);
114  setName(NbBundle.getMessage(DirectoryTreeTopComponent.class, "CTL_DirectoryTreeTopComponent"));
115  setToolTipText(NbBundle.getMessage(DirectoryTreeTopComponent.class, "HINT_DirectoryTreeTopComponent"));
116 
118  associateLookup(ExplorerUtils.createLookup(em, getActionMap()));
119 
120 
121  this.pcs = new PropertyChangeSupport(this);
122 
123  // set the back & forward list and also disable the back & forward button
124  this.backList = new LinkedList<>();
125  this.forwardList = new LinkedList<>();
126  backButton.setEnabled(false);
127  forwardButton.setEnabled(false);
128  }
129 
133  private void subscribeToChangeEvents() {
134  UserPreferences.addChangeListener(new PreferenceChangeListener() {
135  @Override
136  public void preferenceChange(PreferenceChangeEvent evt) {
137  switch (evt.getKey()) {
140  break;
142  // TODO: Need a way to refresh the Views subtree
143  break;
144  }
145  }
146  });
148  this.em.addPropertyChangeListener(this);
151  }
152 
154  this.dataResult.requestActive();
155  }
156 
157  public void openDirectoryListing() {
158  this.dataResult.open();
159  }
160 
162  return this.dataResult;
163  }
164 
170  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
171  private void initComponents() {
172 
173  jScrollPane1 = new BeanTreeView();
174  backButton = new javax.swing.JButton();
175  forwardButton = new javax.swing.JButton();
176  jSeparator1 = new javax.swing.JSeparator();
177 
178  jScrollPane1.setBorder(null);
179 
180  backButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back.png"))); // NOI18N NON-NLS
181  org.openide.awt.Mnemonics.setLocalizedText(backButton, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.backButton.text")); // NOI18N
182  backButton.setBorderPainted(false);
183  backButton.setContentAreaFilled(false);
184  backButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_disabled.png"))); // NOI18N NON-NLS
185  backButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
186  backButton.setMaximumSize(new java.awt.Dimension(55, 100));
187  backButton.setMinimumSize(new java.awt.Dimension(5, 5));
188  backButton.setPreferredSize(new java.awt.Dimension(23, 23));
189  backButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_hover.png"))); // NOI18N NON-NLS
190  backButton.addActionListener(new java.awt.event.ActionListener() {
191  public void actionPerformed(java.awt.event.ActionEvent evt) {
193  }
194  });
195 
196  forwardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward.png"))); // NOI18N NON-NLS
197  org.openide.awt.Mnemonics.setLocalizedText(forwardButton, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.forwardButton.text")); // NOI18N
198  forwardButton.setBorderPainted(false);
199  forwardButton.setContentAreaFilled(false);
200  forwardButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_disabled.png"))); // NOI18N NON-NLS
201  forwardButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
202  forwardButton.setMaximumSize(new java.awt.Dimension(55, 100));
203  forwardButton.setMinimumSize(new java.awt.Dimension(5, 5));
204  forwardButton.setPreferredSize(new java.awt.Dimension(23, 23));
205  forwardButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_hover.png"))); // NOI18N NON-NLS
206  forwardButton.addActionListener(new java.awt.event.ActionListener() {
207  public void actionPerformed(java.awt.event.ActionEvent evt) {
209  }
210  });
211 
212  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
213  this.setLayout(layout);
214  layout.setHorizontalGroup(
215  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
216  .addGroup(layout.createSequentialGroup()
217  .addContainerGap()
218  .addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
219  .addGap(0, 0, 0)
220  .addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
221  .addContainerGap(206, Short.MAX_VALUE))
222  .addComponent(jSeparator1, javax.swing.GroupLayout.DEFAULT_SIZE, 262, Short.MAX_VALUE)
223  .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 262, Short.MAX_VALUE)
224  );
225  layout.setVerticalGroup(
226  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
227  .addGroup(layout.createSequentialGroup()
228  .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
229  .addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
230  .addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE))
231  .addGap(0, 0, 0)
232  .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 1, javax.swing.GroupLayout.PREFERRED_SIZE)
233  .addGap(0, 0, 0)
234  .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 860, Short.MAX_VALUE)
235  .addContainerGap())
236  );
237  }// </editor-fold>//GEN-END:initComponents
238 
239  private void backButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_backButtonActionPerformed
240  // change the cursor to "waiting cursor" for this operation
241  this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
242 
243  // the end is the current place,
244  String[] currentNodePath = backList.pollLast();
245  forwardList.addLast(currentNodePath);
246  forwardButton.setEnabled(true);
247 
248  /* We peek instead of poll because we use its existence
249  * in the list later on so that we do not reset the forward list
250  * after the selection occurs. */
251  String[] newCurrentNodePath = backList.peekLast();
252 
253  // enable / disable the back and forward button
254  if (backList.size() > 1) {
255  backButton.setEnabled(true);
256  } else {
257  backButton.setEnabled(false);
258  }
259 
260  // update the selection on directory tree
261  setSelectedNode(newCurrentNodePath, null);
262 
263  this.setCursor(null);
264  }//GEN-LAST:event_backButtonActionPerformed
265 
266  private void forwardButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_forwardButtonActionPerformed
267  // change the cursor to "waiting cursor" for this operation
268  this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
269 
270  String[] newCurrentNodePath = forwardList.pollLast();
271  if (!forwardList.isEmpty()) {
272  forwardButton.setEnabled(true);
273  } else {
274  forwardButton.setEnabled(false);
275  }
276 
277  backList.addLast(newCurrentNodePath);
278  backButton.setEnabled(true);
279 
280  // update the selection on directory tree
281  setSelectedNode(newCurrentNodePath, null);
282 
283  this.setCursor(null);
284  }//GEN-LAST:event_forwardButtonActionPerformed
285  // Variables declaration - do not modify//GEN-BEGIN:variables
286  private javax.swing.JButton backButton;
287  private javax.swing.JButton forwardButton;
288  private javax.swing.JScrollPane jScrollPane1;
289  private javax.swing.JSeparator jSeparator1;
290  // End of variables declaration//GEN-END:variables
291 
298  public static synchronized DirectoryTreeTopComponent getDefault() {
299  if (instance == null) {
300  instance = new DirectoryTreeTopComponent();
301  }
302  return instance;
303  }
304 
309  public static synchronized DirectoryTreeTopComponent findInstance() {
310  WindowManager winManager = WindowManager.getDefault();
311  TopComponent win = winManager.findTopComponent(PREFERRED_ID);
312  if (win == null) {
313  logger.warning(
314  "Cannot find " + PREFERRED_ID + " component. It will not be located properly in the window system."); //NON-NLS
315  return getDefault();
316  }
317  if (win instanceof DirectoryTreeTopComponent) {
318  return (DirectoryTreeTopComponent) win;
319  }
320  logger.warning(
321  "There seem to be multiple components with the '" + PREFERRED_ID //NON-NLS
322  + "' ID. That is a potential source of errors and unexpected behavior."); //NON-NLS
323  return getDefault();
324  }
325 
332  @Override
333  public int getPersistenceType() {
334  return TopComponent.PERSISTENCE_NEVER;
335  }
336 
344  @Override
345  public void componentOpened() {
346  // change the cursor to "waiting cursor" for this operation
347  this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
348  try {
349  if (Case.existsCurrentCase()) {
350  Case currentCase = Case.getCurrentCase();
351 
352  // close the top component if there's no image in this case
353  if (currentCase.hasData() == false) {
354  //this.close();
355  ((BeanTreeView) this.jScrollPane1).setRootVisible(false); // hide the root
356  } else {
357  // if there's at least one image, load the image and open the top component
358  List<Object> items = new ArrayList<>();
359  final SleuthkitCase tskCase = currentCase.getSleuthkitCase();
360  items.add(new DataSources());
361  items.add(new Views(tskCase));
362  items.add(new Results(tskCase));
363  items.add(new Tags());
364  items.add(new Reports());
365  contentChildren = new RootContentChildren(items);
366  Node root = new AbstractNode(contentChildren) {
371  @Override
372  public Action[] getActions(boolean popup) {
373  return new Action[]{};
374  }
375 
376  // Overide the AbstractNode use of DefaultHandle to return
377  // a handle which can be serialized without a parent
378  @Override
379  public Node.Handle getHandle() {
380  return new Node.Handle() {
381  @Override
382  public Node getNode() throws IOException {
383  return em.getRootContext();
384  }
385  };
386  }
387  };
388 
389  root = new DirectoryTreeFilterNode(root, true);
390 
391 
392  em.setRootContext(root);
393  em.getRootContext().setName(currentCase.getName());
394  em.getRootContext().setDisplayName(currentCase.getName());
395  ((BeanTreeView) this.jScrollPane1).setRootVisible(false); // hide the root
396 
397  // Reset the forward and back lists because we're resetting the root context
398  resetHistory();
399 
400  Children childNodes = em.getRootContext().getChildren();
401  TreeView tree = getTree();
402 
403  Node results = childNodes.findChild(ResultsNode.NAME);
404  tree.expandNode(results);
405 
406  Children resultsChilds = results.getChildren();
407  tree.expandNode(resultsChilds.findChild(KeywordHits.NAME));
408  tree.expandNode(resultsChilds.findChild(ExtractedContent.NAME));
409 
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 
425  // select the first image node, if there is one
426  // (this has to happen after dataResult is opened, because the event
427  // of changing the selected node fires a handler that tries to make
428  // dataResult active)
429  if (childNodes.getNodesCount() > 0) {
430  try {
431  em.setSelectedNodes(new Node[]{childNodes.getNodeAt(0)});
432  } catch (Exception ex) {
433  logger.log(Level.SEVERE, "Error setting default selected node.", ex); //NON-NLS
434  }
435  }
436 
437  }
438  }
439  } finally {
440  this.setCursor(null);
441  }
442  }
443 
450  @Override
451  public void componentClosed() {
452  //@@@ push the selection node to null?
453  contentChildren = null;
454  }
455 
456  void writeProperties(java.util.Properties p) {
457  // better to version settings since initial version as advocated at
458  // http://wiki.apidesign.org/wiki/PropertyFiles
459  p.setProperty("version", "1.0");
460  // TODO store your settings
461  }
462 
463  Object readProperties(java.util.Properties p) {
464  if (instance == null) {
465  instance = this;
466  }
467  instance.readPropertiesImpl(p);
468  return instance;
469  }
470 
471  private void readPropertiesImpl(java.util.Properties p) {
472  String version = p.getProperty("version");
473  // TODO read your settings according to their version
474  }
475 
481  @Override
482  protected String preferredID() {
483  return PREFERRED_ID;
484  }
485 
486  @Override
487  public boolean canClose() {
488  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
489  }
490 
496  @Override
497  public ExplorerManager getExplorerManager() {
498  return this.em;
499  }
500 
506  @Override
507  public Action[] getActions() {
508  return new Action[]{};
509  }
510 
516  public Node getSelectedNode() {
517  Node result = null;
518 
519  Node[] selectedNodes = this.getExplorerManager().getSelectedNodes();
520  if (selectedNodes.length > 0) {
521  result = selectedNodes[0];
522  }
523  return result;
524  }
525 
532  @Override
533  public void propertyChange(PropertyChangeEvent evt) {
534  String changed = evt.getPropertyName();
535  Object oldValue = evt.getOldValue();
536  Object newValue = evt.getNewValue();
537 
538  // change in the case name
539  if (changed.equals(Case.Events.NAME.toString())) {
540  // set the main title of the window
541  String oldCaseName = oldValue.toString();
542  String newCaseName = newValue.toString();
543 
544 
545  // update the case name
546  if ((!oldCaseName.equals("")) && (!newCaseName.equals(""))) {
547  // change the root name and display name
548  em.getRootContext().setName(newCaseName);
549  em.getRootContext().setDisplayName(newCaseName);
550  }
551  } // changed current case
552  else if (changed.equals(Case.Events.CURRENT_CASE.toString())) {
553  // When a case is closed, the old value of this property is the
554  // closed Case object and the new value is null. When a case is
555  // opened, the old value is null and the new value is the new Case
556  // object.
557  // @@@ This needs to be revisited. Perhaps case closed and case
558  // opened events instead of property change events would be a better
559  // solution. Either way, more probably needs to be done to clean up
560  // data model objects when a case is closed.
561  if (oldValue != null && newValue == null) {
562  // The current case has been closed. Reset the ExplorerManager.
563  Node emptyNode = new AbstractNode(Children.LEAF);
564  em.setRootContext(emptyNode);
565  } else if (newValue != null) {
566  // A new case has been opened. Reset the forward and back
567  // buttons. Note that a call to CoreComponentControl.openCoreWindows()
568  // by the new Case object will lead to a componentOpened() call
569  // that will repopulate the tree.
570  // @@@ The repopulation of the tree in this fashion also merits
571  // reconsideration.
572  resetHistory();
573  }
574  } // if the image is added to the case
575  else if (changed.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
576  componentOpened();
577  }
578  // change in node selection
579  else if (changed.equals(ExplorerManager.PROP_SELECTED_NODES)) {
580  respondSelection((Node[]) oldValue, (Node[]) newValue);
581  }
582  else if (changed.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
583  // nothing to do here.
584  // all nodes should be listening for these events and update accordingly.
585  } else if (changed.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
586  || changed.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
587  SwingUtilities.invokeLater(new Runnable() {
588  @Override
589  public void run() {
591  }
592  });
593  } else if (changed.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
594  SwingUtilities.invokeLater(new Runnable() {
595  @Override
596  public void run() {
598  }
599  });
600  }
601  }
602 
611  private void respondSelection(final Node[] oldNodes, final Node[] newNodes) {
612  if (!Case.isCaseOpen()) {
613  //handle in-between condition when case is being closed
614  //and legacy selection events are pumped
615  return;
616  }
617 
618 
619  // Some lock that prevents certain Node operations is set during the
620  // ExplorerManager selection-change, so we must handle changes after the
621  // selection-change event is processed.
622  //TODO find a different way to refresh data result viewer, scheduling this
623  //to EDT breaks loading of nodes in the background
624  EventQueue.invokeLater(new Runnable() {
625  @Override
626  public void run() {
627  // change the cursor to "waiting cursor" for this operation
628  DirectoryTreeTopComponent.this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
629  try {
630 
631  // make sure dataResult is open, redundant?
632  //dataResult.open();
633 
634  Node treeNode = DirectoryTreeTopComponent.this.getSelectedNode();
635  if (treeNode != null) {
636  DirectoryTreeFilterNode.OriginalNode origin = treeNode.getLookup().lookup(DirectoryTreeFilterNode.OriginalNode.class);
637  if (origin == null) {
638  return;
639  }
640  Node originNode = origin.getNode();
641 
642  //set node, wrap in filter node first to filter out children
643  Node drfn = new DataResultFilterNode(originNode, DirectoryTreeTopComponent.this.em);
644  Node kffn = new KnownFileFilterNode(drfn, KnownFileFilterNode.getSelectionContext(originNode));
645  dataResult.setNode(new TableFilterNode(kffn, true));
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  /* get the previous entry to make sure we don't duplicate it.
691  * Motivation for this is also that if we used the back button,
692  * then we already added the 'current' node to 'back' and we will
693  * detect that and not reset the forward list.
694  */
695  String[] currentLast = backList.peekLast();
696  String lastNodeName = null;
697  if (currentLast != null) {
698  lastNodeName = currentLast[currentLast.length - 1];
699  }
700 
701  if (currentLast == null || !selectedNodeName.equals(lastNodeName)) {
702  //add to the list if the last if not the same as current
703  final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
704  backList.addLast(selectedPath); // add the node to the "backList"
705  if (backList.size() > 1) {
706  backButton.setEnabled(true);
707  } else {
708  backButton.setEnabled(false);
709  }
710 
711  forwardList.clear(); // clear the "forwardList"
712  forwardButton.setEnabled(false); // disable the forward Button
713  }
714  }
715 
720  private void resetHistory() {
721  // clear the back and forward list
722  backList.clear();
723  forwardList.clear();
724  backButton.setEnabled(false);
725  forwardButton.setEnabled(false);
726  }
727 
728  @Override
729  public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
730  pcs.addPropertyChangeListener(listener);
731  }
732 
733  @Override
734  public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
735  pcs.removePropertyChangeListener(listener);
736  }
737 
743  public BeanTreeView getTree() {
744  return (BeanTreeView) this.jScrollPane1;
745  }
746 
750  public void refreshContentTreeSafe() {
751  SwingUtilities.invokeLater(new Runnable() {
752  @Override
753  public void run() {
755  }
756  });
757  }
758 
762  private void refreshDataSourceTree() {
763  Node selectedNode = getSelectedNode();
764  final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
765 
766  Children rootChildren = em.getRootContext().getChildren();
767  Node dataSourcesFilterNode = rootChildren.findChild(DataSourcesNode.NAME);
768  if (dataSourcesFilterNode == null) {
769  logger.log(Level.SEVERE, "Cannot find data sources filter node, won't refresh the content tree"); //NON-NLS
770  return;
771  }
772  DirectoryTreeFilterNode.OriginalNode imagesNodeOrig = dataSourcesFilterNode.getLookup().lookup(DirectoryTreeFilterNode.OriginalNode.class);
773 
774  if (imagesNodeOrig == null) {
775  logger.log(Level.SEVERE, "Cannot find data sources node, won't refresh the content tree"); //NON-NLS
776  return;
777  }
778 
779  Node imagesNode = imagesNodeOrig.getNode();
780 
781  RootContentChildren contentRootChildren = (RootContentChildren) imagesNode.getChildren();
782  contentRootChildren.refreshContentKeys();
783 
784  //final TreeView tree = getTree();
785  //tree.expandNode(imagesNode);
786 
787  setSelectedNode(selectedPath, DataSourcesNode.NAME);
788 
789  }
790 
795 // public void refreshResultsTree(final BlackboardArtifact.ARTIFACT_TYPE... types) {
796 // //save current selection
797 // Node selectedNode = getSelectedNode();
798 // final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
799 //
800 // //TODO: instead, we should choose a specific key to refresh? Maybe?
801 // //contentChildren.refreshKeys();
802 //
803 // Children dirChilds = em.getRootContext().getChildren();
804 //
805 // Node results = dirChilds.findChild(ResultsNode.NAME);
806 // if (results == null) {
807 // logger.log(Level.SEVERE, "Cannot find Results filter node, won't refresh the bb tree"); //NON-NLS
808 // return;
809 // }
810 //
811 // OriginalNode original = results.getLookup().lookup(OriginalNode.class);
812 // ResultsNode resultsNode = (ResultsNode) original.getNode();
813 // RootContentChildren resultsNodeChilds = (RootContentChildren) resultsNode.getChildren();
814 // resultsNodeChilds.refreshKeys(types);
815 //
816 //
817 // final TreeView tree = getTree();
818 // // @@@ tree.expandNode(results);
819 //
820 // Children resultsChilds = results.getChildren();
821 // if (resultsChilds == null) {
822 // return;
823 // }
824 //
825 // Node childNode = resultsChilds.findChild(KeywordHits.NAME);
826 // if (childNode == null) {
827 // return;
828 // }
829 // // @@@tree.expandNode(childNode);
830 //
831 // childNode = resultsChilds.findChild(ExtractedContent.NAME);
832 // if (childNode == null) {
833 // return;
834 // }
835 // tree.expandNode(childNode);
836 //
837 // //restores selection if it was under the Results node
838 // //@@@ setSelectedNode(selectedPath, ResultsNode.NAME);
839 //
840 // }
841 
848  private void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName) {
849  if (previouslySelectedNodePath == null) {
850  return;
851  }
852  SwingUtilities.invokeLater(new Runnable() {
853  @Override
854  public void run() {
855  if (previouslySelectedNodePath.length > 0 && (rootNodeName == null || previouslySelectedNodePath[0].equals(rootNodeName))) {
856  Node selectedNode = null;
857  ArrayList<String> selectedNodePath = new ArrayList<>(Arrays.asList(previouslySelectedNodePath));
858  while (null == selectedNode && !selectedNodePath.isEmpty()) {
859  try {
860  selectedNode = NodeOp.findPath(em.getRootContext(), selectedNodePath.toArray(new String[0]));
861  } catch (NodeNotFoundException ex) {
862  // The selected node may have been deleted (e.g., a deleted tag), so truncate the path and try again.
863  if (selectedNodePath.size() > 1) {
864  selectedNodePath.remove(selectedNodePath.size() - 1);
865  } else {
866  StringBuilder nodePath = new StringBuilder();
867  for (int i = 0; i < previouslySelectedNodePath.length; ++i) {
868  nodePath.append(previouslySelectedNodePath[i]).append("/");
869  }
870  logger.log(Level.WARNING, "Failed to find any nodes to select on path " + nodePath.toString(), ex); //NON-NLS
871  break;
872  }
873  }
874  }
875 
876  if (null != selectedNode) {
877  if (rootNodeName != null) {
878  //called from tree auto refresh context
879  //remove last from backlist, because auto select will result in duplication
880  backList.pollLast();
881  }
882  try {
883  em.setExploredContextAndSelection(selectedNode, new Node[]{selectedNode});
884  } catch (PropertyVetoException ex) {
885  logger.log(Level.WARNING, "Property veto from ExplorerManager setting selection to " + selectedNode.getName(), ex); //NON-NLS
886  }
887  }
888  }
889  }
890  });
891  }
892 
893  @Override
894  public TopComponent getTopComponent() {
895  return this;
896  }
897 
898  @Override
899  public boolean hasMenuOpenAction() {
900  return false;
901  }
902 
903  @Override
904  public void viewArtifact(final BlackboardArtifact art) {
906  Children rootChilds = em.getRootContext().getChildren();
907  Node treeNode = null;
908  Node resultsNode = rootChilds.findChild(ResultsNode.NAME);
909  Children resultsChilds = resultsNode.getChildren();
911  Node hashsetRootNode = resultsChilds.findChild(type.getLabel());
912  Children hashsetRootChilds = hashsetRootNode.getChildren();
913  try {
914  String setName = null;
915  List<BlackboardAttribute> attributes = art.getAttributes();
916  for (BlackboardAttribute att : attributes) {
917  int typeId = att.getAttributeTypeID();
918  if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
919  setName = att.getValueString();
920  }
921  }
922  treeNode = hashsetRootChilds.findChild(setName);
923  } catch (TskException ex) {
924  logger.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
925  }
926  } else if (type.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT)) {
927  Node keywordRootNode = resultsChilds.findChild(type.getLabel());
928  Children keywordRootChilds = keywordRootNode.getChildren();
929  try {
930  String listName = null;
931  String keywordName = null;
932  List<BlackboardAttribute> attributes = art.getAttributes();
933  for (BlackboardAttribute att : attributes) {
934  int typeId = att.getAttributeTypeID();
935  if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
936  listName = att.getValueString();
937  } else if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) {
938  keywordName = att.getValueString();
939  }
940  }
941  Node listNode = keywordRootChilds.findChild(listName);
942  if (listNode == null) {
943  return;
944  }
945  Children listChildren = listNode.getChildren();
946  if (listChildren == null) {
947  return;
948  }
949  treeNode = listChildren.findChild(keywordName);
950  } catch (TskException ex) {
951  logger.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
952  }
955  Node interestingItemsRootNode = resultsChilds.findChild(type.getLabel());
956  Children interestingItemsRootChildren = interestingItemsRootNode.getChildren();
957  try {
958  String setName = null;
959  List<BlackboardAttribute> attributes = art.getAttributes();
960  for (BlackboardAttribute att : attributes) {
961  int typeId = att.getAttributeTypeID();
962  if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
963  setName = att.getValueString();
964  }
965  }
966  treeNode = interestingItemsRootChildren.findChild(setName);
967  } catch (TskException ex) {
968  logger.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
969  }
970  } else {
971  Node extractedContent = resultsChilds.findChild(ExtractedContent.NAME);
972  Children extractedChilds = extractedContent.getChildren();
973  if (extractedChilds == null) {
974  return;
975  }
976  treeNode = extractedChilds.findChild(type.getLabel());
977  }
978 
979  if (treeNode == null) {
980  return;
981  }
982 
983  try {
984  em.setExploredContextAndSelection(treeNode, new Node[]{treeNode});
985  } catch (PropertyVetoException ex) {
986  logger.log(Level.WARNING, "Property Veto: ", ex); //NON-NLS
987  }
988 
989  // Another thread is needed because we have to wait for dataResult to populate
990  EventQueue.invokeLater(new Runnable() {
991  @Override
992  public void run() {
993  Children resultChilds = dataResult.getRootNode().getChildren();
994  Node select = resultChilds.findChild(Long.toString(art.getArtifactID()));
995  if (select != null) {
996  dataResult.requestActive();
997  dataResult.setSelectedNodes(new Node[]{select});
998  fireViewerComplete();
999  }
1000  }
1001  });
1002  }
1003 
1004  @Override
1006  new ViewContextAction(
1007  NbBundle.getMessage(this.getClass(), "DirectoryTreeTopComponent.action.viewArtContent.text"),
1008  new BlackboardArtifactNode(art)).actionPerformed(null);
1009  }
1010 
1011 // private class HistoryManager<T> {
1012 // private Stack<T> past, future;
1013 //
1014 // }
1015  @Override
1016  public void addOnFinishedListener(PropertyChangeListener l) {
1018  }
1019 
1020  void fireViewerComplete() {
1021 
1022  try {
1023  firePropertyChange(BlackboardResultViewer.FINISHED_DISPLAY_EVT, 0, 1);
1024  } catch (Exception e) {
1025  logger.log(Level.SEVERE, "DirectoryTreeTopComponent listener threw exception", e); //NON-NLS
1026  MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "DirectoryTreeTopComponent.moduleErr"),
1027  NbBundle.getMessage(this.getClass(),
1028  "DirectoryTreeTopComponent.moduleErr.msg"),
1029  MessageNotifyUtil.MessageType.ERROR);
1030  }
1031  }
1032 }
static synchronized IngestManager getInstance()
static boolean existsCurrentCase()
Definition: Case.java:622
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)
List< BlackboardAttribute > getAttributes()
synchronized void removePropertyChangeListener(PropertyChangeListener listener)
void addIngestModuleEventListener(final PropertyChangeListener listener)
static synchronized void addPropertyChangeListener(PropertyChangeListener listener)
Definition: Case.java:833
static void addChangeListener(PreferenceChangeListener listener)
static Logger getLogger(String name)
Definition: Logger.java:131

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