From cacd5b5c2ba0212cd990c112a2e956cd4d6bbc8e Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 6 Jul 2017 09:36:49 -0400 Subject: [PATCH] Merge pull request #2920 from millmanorama/2791-open-tree-off-EDT 2791 open tree off edt --- .../sleuthkit/autopsy/casemodule/Case.java | 33 +-- .../datamodel/RootContentChildren.java | 9 +- .../DirectoryTreeTopComponent.form | 6 +- .../DirectoryTreeTopComponent.java | 216 +++++++++--------- 4 files changed, 128 insertions(+), 136 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index ce69e7a017..340d847343 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -63,6 +63,8 @@ import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.actions.OpenOutputFolderAction; +import org.sleuthkit.autopsy.appservices.AutopsyService; +import org.sleuthkit.autopsy.appservices.AutopsyService.CaseContext; import org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException; import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceEvent; import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceFailedEvent; @@ -92,15 +94,13 @@ import org.sleuthkit.autopsy.coreutils.Version; import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.autopsy.events.AutopsyEventException; import org.sleuthkit.autopsy.events.AutopsyEventPublisher; -import org.sleuthkit.autopsy.appservices.AutopsyService; -import org.sleuthkit.autopsy.appservices.AutopsyService.CaseContext; -import org.sleuthkit.autopsy.progress.LoggingProgressIndicator; -import org.sleuthkit.autopsy.progress.ModalDialogProgressIndicator; -import org.sleuthkit.autopsy.progress.ProgressIndicator; import org.sleuthkit.autopsy.ingest.IngestJob; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService; import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchServiceException; +import org.sleuthkit.autopsy.progress.LoggingProgressIndicator; +import org.sleuthkit.autopsy.progress.ModalDialogProgressIndicator; +import org.sleuthkit.autopsy.progress.ProgressIndicator; import org.sleuthkit.autopsy.timeline.OpenTimelineAction; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.CaseDbConnectionInfo; @@ -964,23 +964,12 @@ public class Case { /* * Enable the case-specific actions. */ - CallableSystemAction.get(AddImageAction.class - ).setEnabled(true); - CallableSystemAction - .get(CaseCloseAction.class - ).setEnabled(true); - CallableSystemAction - .get(CasePropertiesAction.class - ).setEnabled(true); - CallableSystemAction - .get(CaseDeleteAction.class - ).setEnabled(true); - CallableSystemAction - .get(OpenTimelineAction.class - ).setEnabled(true); - CallableSystemAction - .get(OpenOutputFolderAction.class - ).setEnabled(false); + CallableSystemAction.get(AddImageAction.class).setEnabled(true); + CallableSystemAction.get(CaseCloseAction.class).setEnabled(true); + CallableSystemAction.get(CasePropertiesAction.class).setEnabled(true); + CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true); + CallableSystemAction.get(OpenTimelineAction.class).setEnabled(true); + CallableSystemAction.get(OpenOutputFolderAction.class).setEnabled(false); /* * Add the case to the recent cases tracker that supplies a list diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java index 7221aab9a6..f04495a706 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.datamodel; import java.util.Collection; import java.util.Collections; -import org.sleuthkit.datamodel.BlackboardArtifact; /** * Children implementation for the root node of a ContentNode tree. Accepts a @@ -28,7 +27,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact; */ public class RootContentChildren extends AbstractContentChildren { - private Collection contentKeys; + private final Collection contentKeys; /** * @param contentKeys root Content objects for the Node tree @@ -55,8 +54,6 @@ public class RootContentChildren extends AbstractContentChildren { * but we are not ready for this. */ public void refreshContentKeys() { - for (Object key : contentKeys) { - refreshKey(key); - } + contentKeys.forEach(this::refreshKey); } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.form b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.form index d77daea41e..90c6ac00a6 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.form +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.form @@ -16,7 +16,7 @@ - + @@ -38,14 +38,14 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 8b7c3e1a46..bfb98e5220 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -30,11 +30,13 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.prefs.PreferenceChangeEvent; import java.util.prefs.PreferenceChangeListener; import javax.swing.Action; import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; import javax.swing.tree.TreeSelectionModel; import org.apache.commons.lang3.StringUtils; import org.openide.explorer.ExplorerManager; @@ -114,7 +116,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat initComponents(); // only allow one item to be selected at a time - ((BeanTreeView) jScrollPane1).setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); + getTree().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); // remove the close button putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.TRUE); setName(NbBundle.getMessage(DirectoryTreeTopComponent.class, "CTL_DirectoryTreeTopComponent")); @@ -175,12 +177,12 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat // //GEN-BEGIN:initComponents private void initComponents() { - jScrollPane1 = new BeanTreeView(); + treeView = new BeanTreeView(); backButton = new javax.swing.JButton(); forwardButton = new javax.swing.JButton(); showRejectedCheckBox = new javax.swing.JCheckBox(); - jScrollPane1.setBorder(null); + treeView.setBorder(null); backButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(backButton, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.backButton.text")); // NOI18N @@ -220,7 +222,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 262, Short.MAX_VALUE) + .addComponent(treeView, javax.swing.GroupLayout.DEFAULT_SIZE, 262, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addGap(5, 5, 5) .addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) @@ -239,7 +241,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat .addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(showRejectedCheckBox)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 854, Short.MAX_VALUE) + .addComponent(treeView, javax.swing.GroupLayout.DEFAULT_SIZE, 854, Short.MAX_VALUE) .addGap(0, 0, 0)) ); }// //GEN-END:initComponents @@ -296,8 +298,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton backButton; private javax.swing.JButton forwardButton; - private javax.swing.JScrollPane jScrollPane1; private javax.swing.JCheckBox showRejectedCheckBox; + private javax.swing.JScrollPane treeView; // End of variables declaration//GEN-END:variables /** @@ -360,106 +362,117 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat public void componentOpened() { // change the cursor to "waiting cursor" for this operation this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + Case currentCase = null; try { - Case currentCase = null; - try { - currentCase = Case.getCurrentCase(); - } catch (IllegalStateException ex) { - /* - * No open case. + currentCase = Case.getCurrentCase(); + } catch (IllegalStateException ex) { + // No open case. + } + + // close the top component if there's no image in this case + if (null == currentCase || currentCase.hasData() == false) { + getTree().setRootVisible(false); // hide the root + } else { + // if there's at least one image, load the image and open the top component + final SleuthkitCase tskCase = currentCase.getSleuthkitCase(); + contentChildren = new RootContentChildren(Arrays.asList( + new DataSources(), + new Views(tskCase), + new Results(tskCase), + new Tags(), + new Reports())); + Node root = new AbstractNode(contentChildren) { + //JIRA-2807: What is the point of these overrides? + /** + * to override the right click action in the white blank space + * area on the directory tree window */ - } + @Override + public Action[] getActions(boolean popup) { + return new Action[]{}; + } - // close the top component if there's no image in this case - if (null == currentCase || currentCase.hasData() == false) { - ((TreeView) this.jScrollPane1).setRootVisible(false); // hide the root - } else { - // if there's at least one image, load the image and open the top component - List items = new ArrayList<>(); - final SleuthkitCase tskCase = currentCase.getSleuthkitCase(); - items.add(new DataSources()); - items.add(new Views(tskCase)); - items.add(new Results(tskCase)); - items.add(new Tags()); - items.add(new Reports()); - contentChildren = new RootContentChildren(items); + // Overide the AbstractNode use of DefaultHandle to return + // a handle which can be serialized without a parent + @Override + public Node.Handle getHandle() { + return new Node.Handle() { + @Override + public Node getNode() throws IOException { + return em.getRootContext(); + } + }; + } + }; - Node root = new AbstractNode(contentChildren) { - /** - * to override the right click action in the white blank - * space area on the directory tree window + root = new DirectoryTreeFilterNode(root, true); + + em.setRootContext(root); + em.getRootContext().setName(currentCase.getName()); + em.getRootContext().setDisplayName(currentCase.getName()); + getTree().setRootVisible(false); // hide the root + + // Reset the forward and back lists because we're resetting the root context + resetHistory(); + new SwingWorker() { + @Override + protected Node[] doInBackground() throws Exception { + Children rootChildren = em.getRootContext().getChildren(); + TreeView tree = getTree(); + + Node results = rootChildren.findChild(ResultsNode.NAME); + tree.expandNode(results); + Children resultsChildren = results.getChildren(); + Arrays.stream(resultsChildren.getNodes()).forEach(tree::expandNode); + + Accounts accounts = resultsChildren.findChild(Accounts.NAME).getLookup().lookup(Accounts.class); + showRejectedCheckBox.setAction(accounts.newToggleShowRejectedAction()); + showRejectedCheckBox.setSelected(false); + + Node views = rootChildren.findChild(ViewsNode.NAME); + Arrays.stream(views.getChildren().getNodes()).forEach(tree::expandNode); + tree.collapseNode(views); + /* + * JIRA-2806: What is this supposed to do? Right now it selects + * the data sources node, but the comment seems to indicate + * it is supposed to select the first datasource. */ - @Override - public Action[] getActions(boolean popup) { - return new Action[]{}; + // select the first image node, if there is one + // (this has to happen after dataResult is opened, because the event + // of changing the selected node fires a handler that tries to make + // dataResult active) + if (rootChildren.getNodesCount() > 0) { + return new Node[]{rootChildren.getNodeAt(0)}; } + return new Node[]{}; + } - // Overide the AbstractNode use of DefaultHandle to return - // a handle which can be serialized without a parent - @Override - public Node.Handle getHandle() { - return new Node.Handle() { - @Override - public Node getNode() throws IOException { - return em.getRootContext(); - } - }; + @Override + protected void done() { + super.done(); + + // if the dataResult is not opened + if (!dataResult.isOpened()) { + dataResult.open(); // open the data result top component as well when the directory tree is opened } - }; - - root = new DirectoryTreeFilterNode(root, true); - - em.setRootContext(root); - em.getRootContext().setName(currentCase.getName()); - em.getRootContext().setDisplayName(currentCase.getName()); - ((TreeView) this.jScrollPane1).setRootVisible(false); // hide the root - - // Reset the forward and back lists because we're resetting the root context - resetHistory(); - - Children childNodes = em.getRootContext().getChildren(); - TreeView tree = getTree(); - - Node results = childNodes.findChild(ResultsNode.NAME); - tree.expandNode(results); - - Children resultsChilds = results.getChildren(); - for (Node n : resultsChilds.getNodes()) { - tree.expandNode(n); - } - - Accounts accounts = resultsChilds.findChild(Accounts.NAME).getLookup().lookup(Accounts.class); - showRejectedCheckBox.setAction(accounts.newToggleShowRejectedAction()); - showRejectedCheckBox.setSelected(false); - - Node views = childNodes.findChild(ViewsNode.NAME); - Children viewsChilds = views.getChildren(); - for (Node n : viewsChilds.getNodes()) { - tree.expandNode(n); - } - - tree.collapseNode(views); - - // if the dataResult is not opened - if (!dataResult.isOpened()) { - dataResult.open(); // open the data result top component as well when the directory tree is opened - } - - // select the first image node, if there is one - // (this has to happen after dataResult is opened, because the event - // of changing the selected node fires a handler that tries to make - // dataResult active) - if (childNodes.getNodesCount() > 0) { + /* + * JIRA-2806: What is this supposed to do? + */ + // select the first image node, if there is one + // (this has to happen after dataResult is opened, because the event + // of changing the selected node fires a handler that tries to make + // dataResult active) try { - em.setSelectedNodes(new Node[]{childNodes.getNodeAt(0)}); + em.setSelectedNodes(get()); } catch (PropertyVetoException ex) { LOGGER.log(Level.SEVERE, "Error setting default selected node.", ex); //NON-NLS + } catch (InterruptedException | ExecutionException ex) { + LOGGER.log(Level.SEVERE, "Error expanding tree to initial state.", ex); //NON-NLS + } finally { + setCursor(null); } } - - } - } finally { - this.setCursor(null); + }.execute(); } } @@ -605,9 +618,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat // We only need to trigger openCoreWindows() when the // first data source is added. if (currentCase.getDataSources().size() == 1) { - SwingUtilities.invokeLater(() -> { - CoreComponentControl.openCoreWindows(); - }); + SwingUtilities.invokeLater(CoreComponentControl::openCoreWindows); } } catch (IllegalStateException | TskCoreException notUsed) { /** @@ -749,19 +760,14 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat * @return tree the BeanTreeView */ public BeanTreeView getTree() { - return (BeanTreeView) this.jScrollPane1; + return (BeanTreeView) this.treeView; } /** * Refresh the content node part of the dir tree safely in the EDT thread */ public void refreshContentTreeSafe() { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - refreshDataSourceTree(); - } - }); + SwingUtilities.invokeLater(this::refreshDataSourceTree); } /** @@ -801,7 +807,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat ArrayList selectedNodePath = new ArrayList<>(Arrays.asList(previouslySelectedNodePath)); while (null == selectedNode && !selectedNodePath.isEmpty()) { try { - selectedNode = NodeOp.findPath(em.getRootContext(), selectedNodePath.toArray(new String[0])); + selectedNode = NodeOp.findPath(em.getRootContext(), selectedNodePath.toArray(new String[selectedNodePath.size()])); } catch (NodeNotFoundException ex) { // The selected node may have been deleted (e.g., a deleted tag), so truncate the path and try again. if (selectedNodePath.size() > 1) { @@ -1028,7 +1034,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat } treeNode = binChildren.findChild(binName); } else { //default account type - treeNode = accountRootChilds.findChild(accountType);; + treeNode = accountRootChilds.findChild(accountType); } } catch (TskCoreException ex) { LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS