From 4f07cc398810ad821ea6419e2098b507212261b6 Mon Sep 17 00:00:00 2001 From: Jeff Wallace Date: Thu, 21 Nov 2013 15:56:48 -0500 Subject: [PATCH 1/9] Fixed 'view in directory' action. --- .../corecomponents/DataResultPanel.java | 90 +++++------ .../corecomponents/DataResultViewerTable.java | 150 +++++++++--------- .../directorytree/ViewContextAction.java | 54 +++++-- 3 files changed, 161 insertions(+), 133 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java index 6835a1e435..969966604c 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java @@ -362,6 +362,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C this.rootNode.addNodeListener(dummyNodeListener); } + resetTabs(selectedNode); setupTabs(selectedNode); if (selectedNode != null) { @@ -369,58 +370,42 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C this.numberMatchLabel.setText(Integer.toString(childrenCount)); } this.numberMatchLabel.setVisible(true); - - - resetTabs(selectedNode); - - // set the display on the current active tab - int currentActiveTab = this.dataResultTabbedPanel.getSelectedIndex(); - if (currentActiveTab != -1) { - UpdateWrapper drv = viewers.get(currentActiveTab); - drv.setNode(selectedNode); - } } - private void setupTabs(final Node selectedNode) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - //update/disable tabs based on if supported for this node - int drvC = 0; - for (UpdateWrapper drv : viewers) { + private void setupTabs(Node selectedNode) { + //update/disable tabs based on if supported for this node + int drvC = 0; + for (UpdateWrapper drv : viewers) { - if (drv.isSupported(selectedNode)) { - dataResultTabbedPanel.setEnabledAt(drvC, true); - } else { - dataResultTabbedPanel.setEnabledAt(drvC, false); - } - ++drvC; - } + if (drv.isSupported(selectedNode)) { + dataResultTabbedPanel.setEnabledAt(drvC, true); + } else { + dataResultTabbedPanel.setEnabledAt(drvC, false); + } + ++drvC; + } - // if the current tab is no longer enabled, then find one that is - boolean hasViewerEnabled = true; - int currentActiveTab = dataResultTabbedPanel.getSelectedIndex(); - if ((currentActiveTab == -1) || (dataResultTabbedPanel.isEnabledAt(currentActiveTab) == false)) { - hasViewerEnabled = false; - for (int i = 0; i < dataResultTabbedPanel.getTabCount(); i++) { - if (dataResultTabbedPanel.isEnabledAt(i)) { - currentActiveTab = i; - hasViewerEnabled = true; - break; - } - } - - if (hasViewerEnabled) { - dataResultTabbedPanel.setSelectedIndex(currentActiveTab); - } - } - - if (hasViewerEnabled) { - viewers.get(currentActiveTab).setNode(selectedNode); + // if the current tab is no longer enabled, then find one that is + boolean hasViewerEnabled = true; + int currentActiveTab = dataResultTabbedPanel.getSelectedIndex(); + if ((currentActiveTab == -1) || (dataResultTabbedPanel.isEnabledAt(currentActiveTab) == false)) { + hasViewerEnabled = false; + for (int i = 0; i < dataResultTabbedPanel.getTabCount(); i++) { + if (dataResultTabbedPanel.isEnabledAt(i)) { + currentActiveTab = i; + hasViewerEnabled = true; + break; } } - }); - + + if (hasViewerEnabled) { + dataResultTabbedPanel.setSelectedIndex(currentActiveTab); + } + } + + if (hasViewerEnabled) { + viewers.get(currentActiveTab).setNode(selectedNode); + } } @Override @@ -620,11 +605,20 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C } @Override - public void childrenAdded(NodeMemberEvent nme) { + public void childrenAdded(final NodeMemberEvent nme) { Node[] delta = nme.getDelta(); if (load && containsReal(delta)) { load = false; - setupTabs(nme.getNode()); + if (SwingUtilities.isEventDispatchThread()) { + setupTabs(nme.getNode()); + } else { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + setupTabs(nme.getNode()); + } + }); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java index ab8d52fed8..b8106f9b0b 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java @@ -278,101 +278,96 @@ public class DataResultViewerTable extends AbstractDataResultViewer { * @param root The parent Node of the ContentNodes */ private void setupTable(final Node root) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - //wrap to filter out children - //note: this breaks the tree view mode in this generic viewer, - //so wrap nodes earlier if want 1 level view - //if (!(root instanceof TableFilterNode)) { - /// root = new TableFilterNode(root, true); - //} + //wrap to filter out children + //note: this breaks the tree view mode in this generic viewer, + //so wrap nodes earlier if want 1 level view + //if (!(root instanceof TableFilterNode)) { + /// root = new TableFilterNode(root, true); + //} - em.setRootContext(root); + em.setRootContext(root); - final OutlineView ov = ((OutlineView) DataResultViewerTable.this.tableScrollPanel); + final OutlineView ov = ((OutlineView) DataResultViewerTable.this.tableScrollPanel); - propertiesAcc.clear(); + propertiesAcc.clear(); - DataResultViewerTable.this.getAllChildPropertyHeadersRec(root, 100); - List props = new ArrayList(propertiesAcc); - if (props.size() > 0) { - Node.Property prop = props.remove(0); - ((DefaultOutlineModel) ov.getOutline().getOutlineModel()).setNodesColumnLabel(prop.getDisplayName()); - } + DataResultViewerTable.this.getAllChildPropertyHeadersRec(root, 100); + List props = new ArrayList(propertiesAcc); + if (props.size() > 0) { + Node.Property prop = props.remove(0); + ((DefaultOutlineModel) ov.getOutline().getOutlineModel()).setNodesColumnLabel(prop.getDisplayName()); + } - // *********** Make the TreeTableView to be sortable *************** + // *********** Make the TreeTableView to be sortable *************** - //First property column is sortable, but also sorted initially, so - //initially this one will have the arrow icon: - if (props.size() > 0) { - props.get(0).setValue("TreeColumnTTV", Boolean.TRUE); // Identifies special property representing first (tree) column. - props.get(0).setValue("SortingColumnTTV", Boolean.TRUE); // TreeTableView should be initially sorted by this property column. - } + //First property column is sortable, but also sorted initially, so + //initially this one will have the arrow icon: + if (props.size() > 0) { + props.get(0).setValue("TreeColumnTTV", Boolean.TRUE); // Identifies special property representing first (tree) column. + props.get(0).setValue("SortingColumnTTV", Boolean.TRUE); // TreeTableView should be initially sorted by this property column. + } - // The rest of the columns are sortable, but not initially sorted, - // so initially will have no arrow icon: - String[] propStrings = new String[props.size() * 2]; - for (int i = 0; i < props.size(); i++) { - props.get(i).setValue("ComparableColumnTTV", Boolean.TRUE); - propStrings[2 * i] = props.get(i).getName(); - propStrings[2 * i + 1] = props.get(i).getDisplayName(); - } + // The rest of the columns are sortable, but not initially sorted, + // so initially will have no arrow icon: + String[] propStrings = new String[props.size() * 2]; + for (int i = 0; i < props.size(); i++) { + props.get(i).setValue("ComparableColumnTTV", Boolean.TRUE); + propStrings[2 * i] = props.get(i).getName(); + propStrings[2 * i + 1] = props.get(i).getDisplayName(); + } - ov.setPropertyColumns(propStrings); - // ***************************************************************** + ov.setPropertyColumns(propStrings); + // ***************************************************************** - // // set the first entry - // Children test = root.getChildren(); - // Node firstEntryNode = test.getNodeAt(0); - // try { - // this.getExplorerManager().setSelectedNodes(new Node[]{firstEntryNode}); - // } catch (PropertyVetoException ex) {} + // // set the first entry + // Children test = root.getChildren(); + // Node firstEntryNode = test.getNodeAt(0); + // try { + // this.getExplorerManager().setSelectedNodes(new Node[]{firstEntryNode}); + // } catch (PropertyVetoException ex) {} - // show the horizontal scroll panel and show all the content & header + // show the horizontal scroll panel and show all the content & header - int totalColumns = props.size(); + int totalColumns = props.size(); - //int scrollWidth = ttv.getWidth(); - int margin = 4; - int startColumn = 1; - ov.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + //int scrollWidth = ttv.getWidth(); + int margin = 4; + int startColumn = 1; + ov.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_OFF); - // get first 100 rows values for the table - Object[][] content = null; - content = getRowValues(root, 100); + // get first 100 rows values for the table + Object[][] content = null; + content = getRowValues(root, 100); - if (content != null) { - // get the fontmetrics - final Graphics graphics = ov.getGraphics(); - if (graphics != null) { - final FontMetrics metrics = graphics.getFontMetrics(); + if (content != null) { + // get the fontmetrics + final Graphics graphics = ov.getGraphics(); + if (graphics != null) { + final FontMetrics metrics = graphics.getFontMetrics(); - // for the "Name" column - int nodeColWidth = Math.min(getMaxColumnWidth(0, metrics, margin, 40, firstColumnLabel, content), 250); // Note: 40 is the width of the icon + node lines. Change this value if those values change! - ov.getOutline().getColumnModel().getColumn(0).setPreferredWidth(nodeColWidth); + // for the "Name" column + int nodeColWidth = Math.min(getMaxColumnWidth(0, metrics, margin, 40, firstColumnLabel, content), 250); // Note: 40 is the width of the icon + node lines. Change this value if those values change! + ov.getOutline().getColumnModel().getColumn(0).setPreferredWidth(nodeColWidth); - // get the max for each other column - for (int colIndex = startColumn; colIndex <= totalColumns; colIndex++) { - int colWidth = Math.min(getMaxColumnWidth(colIndex, metrics, margin, 8, props, content), 350); - ov.getOutline().getColumnModel().getColumn(colIndex).setPreferredWidth(colWidth); - } - } - } - - // if there's no content just auto resize all columns - if (!(content.length > 0)) { - // turn on the auto resize - ov.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); + // get the max for each other column + for (int colIndex = startColumn; colIndex <= totalColumns; colIndex++) { + int colWidth = Math.min(getMaxColumnWidth(colIndex, metrics, margin, 8, props, content), 350); + ov.getOutline().getColumnModel().getColumn(colIndex).setPreferredWidth(colWidth); } } - }); + } + + // if there's no content just auto resize all columns + if (!(content.length > 0)) { + // turn on the auto resize + ov.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); + } } private static Object[][] getRowValues(Node node, int rows) { @@ -485,11 +480,20 @@ public class DataResultViewerTable extends AbstractDataResultViewer { } @Override - public void childrenAdded(NodeMemberEvent nme) { + public void childrenAdded(final NodeMemberEvent nme) { Node[] delta = nme.getDelta(); if (load && containsReal(delta)) { load = false; - setupTable(nme.getNode()); + if (SwingUtilities.isEventDispatchThread()) { + setupTable(nme.getNode()); + } else { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + setupTable(nme.getNode()); + } + }); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java index e03e869a97..84a2dccadd 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java @@ -25,11 +25,12 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.logging.Level; +import javafx.scene.control.TreeView; import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.AbstractAction; -import org.openide.explorer.ExplorerManager; -import org.openide.explorer.view.TreeView; +import javax.swing.SwingWorker; import org.openide.nodes.AbstractNode; +import org.openide.explorer.ExplorerManager; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; @@ -120,22 +121,51 @@ public class ViewContextAction extends AbstractAction { public void run() { DataResultTopComponent dataResult = directoryTree.getDirectoryListing(); Node resultRoot = dataResult.getRootNode(); - Children resultChilds = resultRoot.getChildren(); Node generated = content.accept(new RootContentChildren.CreateSleuthkitNodeVisitor()); - for (int i = 0; i < resultChilds.getNodesCount(); i++) { - Node current = resultChilds.getNodeAt(i); - if (generated.getName().equals(current.getName())) { - dataResult.requestActive(); - dataResult.setSelectedNodes(new Node[]{current}); - DirectoryTreeTopComponent.getDefault().fireViewerComplete(); - break; - } - } + new SelectionWorker(dataResult, generated.getName(), resultRoot).execute(); + } }); } }); } + + class SelectionWorker extends SwingWorker { + + DataResultTopComponent dataResult; + String nameToSelect; + Node originalRoot; + + SelectionWorker(DataResultTopComponent dataResult, String nameToSelect, Node originalRoot) { + this.dataResult = dataResult; + this.nameToSelect = nameToSelect; + this.originalRoot = originalRoot; + } + + @Override + protected Node[] doInBackground() throws Exception { + return originalRoot.getChildren().getNodes(true); + } + + @Override + protected void done() { + Node[] nodes = get(); + + if (dataResult.getRootNode().equals(originalRoot) == false) { + return; + } + + for (Node current : nodes) { + if (nameToSelect.equals(current.getName())) { + dataResult.requestActive(); + dataResult.setSelectedNodes(new Node[]{current}); + DirectoryTreeTopComponent.getDefault().fireViewerComplete(); + break; + } + } + } + + } /** * The ReverseHierarchyVisitor class is designed to return a list of Content From f15301ed5e5b0c6e33958510835d9808f37a094d Mon Sep 17 00:00:00 2001 From: Jeff Wallace Date: Thu, 21 Nov 2013 16:02:43 -0500 Subject: [PATCH 2/9] Fixed error. --- .../autopsy/directorytree/ViewContextAction.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java index 84a2dccadd..2f840d29e5 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java @@ -24,15 +24,17 @@ import java.beans.PropertyVetoException; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.concurrent.ExecutionException; import java.util.logging.Level; -import javafx.scene.control.TreeView; import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.AbstractAction; import javax.swing.SwingWorker; import org.openide.nodes.AbstractNode; import org.openide.explorer.ExplorerManager; +import org.openide.explorer.view.TreeView; import org.openide.nodes.Children; import org.openide.nodes.Node; +import org.openide.util.Exceptions; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; @@ -149,7 +151,13 @@ public class ViewContextAction extends AbstractAction { @Override protected void done() { - Node[] nodes = get(); + Node[] nodes; + try { + nodes = get(); + } catch (InterruptedException | ExecutionException ex) { + logger.log(Level.WARNING, "Failed to get nodes in selection worker."); + return; + } if (dataResult.getRootNode().equals(originalRoot) == false) { return; From fc961cd210d1a72501fcae6488a7472502240fbb Mon Sep 17 00:00:00 2001 From: Jeff Wallace Date: Thu, 21 Nov 2013 16:05:58 -0500 Subject: [PATCH 3/9] Added documentation. --- .../directorytree/ViewContextAction.java | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java index 2f840d29e5..79bba79802 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java @@ -132,21 +132,26 @@ public class ViewContextAction extends AbstractAction { }); } - class SelectionWorker extends SwingWorker { + /** + * Thread that waits for a Node's children to completely be generated (they + * may be lazily loaded), then sets the correct selection in a + * DataResultTopComponent. + */ + private class SelectionWorker extends SwingWorker { DataResultTopComponent dataResult; - String nameToSelect; - Node originalRoot; + String nameOfNodeToSelect; + Node originalRootNode; SelectionWorker(DataResultTopComponent dataResult, String nameToSelect, Node originalRoot) { this.dataResult = dataResult; - this.nameToSelect = nameToSelect; - this.originalRoot = originalRoot; + this.nameOfNodeToSelect = nameToSelect; + this.originalRootNode = originalRoot; } @Override protected Node[] doInBackground() throws Exception { - return originalRoot.getChildren().getNodes(true); + return originalRootNode.getChildren().getNodes(true); } @Override @@ -159,12 +164,14 @@ public class ViewContextAction extends AbstractAction { return; } - if (dataResult.getRootNode().equals(originalRoot) == false) { + // If the root node of the data result viewer has changed, don't + // set the selection. + if (dataResult.getRootNode().equals(originalRootNode) == false) { return; } for (Node current : nodes) { - if (nameToSelect.equals(current.getName())) { + if (nameOfNodeToSelect.equals(current.getName())) { dataResult.requestActive(); dataResult.setSelectedNodes(new Node[]{current}); DirectoryTreeTopComponent.getDefault().fireViewerComplete(); From ed4fcbc65578fb1ce28887f6706c589b3c7c2727 Mon Sep 17 00:00:00 2001 From: Jeff Wallace Date: Thu, 21 Nov 2013 16:24:34 -0500 Subject: [PATCH 4/9] Fixed tabs. --- .../sleuthkit/autopsy/corecomponents/DataResultPanel.java | 4 ++-- .../autopsy/corecomponents/DataResultViewerTable.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java index 988f2582d4..d243bab86b 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java @@ -613,14 +613,14 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C load = false; if (SwingUtilities.isEventDispatchThread()) { setupTabs(nme.getNode()); - updateMatches(); + updateMatches(); } else { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { setupTabs(nme.getNode()); updateMatches(); - } + } }); } } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java index 68487c350f..475b6bc395 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java @@ -290,9 +290,9 @@ public class DataResultViewerTable extends AbstractDataResultViewer { final OutlineView ov = ((OutlineView) DataResultViewerTable.this.tableScrollPanel); - if (ov == null) { - return; - } + if (ov == null) { + return; + } propertiesAcc.clear(); From 499bd6163968c8252c26c0550c4509a4561807d1 Mon Sep 17 00:00:00 2001 From: Jeff Wallace Date: Tue, 26 Nov 2013 12:12:53 -0500 Subject: [PATCH 5/9] Cleaned up ViewContextAction and added more specific documentation. --- .../directorytree/ViewContextAction.java | 97 +++++++++++-------- 1 file changed, 58 insertions(+), 39 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java index 79bba79802..e959e7e3ed 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java @@ -34,7 +34,6 @@ import org.openide.explorer.ExplorerManager; import org.openide.explorer.view.TreeView; import org.openide.nodes.Children; import org.openide.nodes.Node; -import org.openide.util.Exceptions; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; @@ -47,7 +46,14 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.VolumeSystem; /** - * View the directory content associated with the given Artifact + * View the directory content associated with the given Artifact in the DataResultViewer. + * + * 1. Expands the Directory Tree to the location of the parent Node of the + * associated Content. + * 2. Selects the parent Node of the associated Content in the Directory Tree, + * which causes the parent Node's Children to be visible in the DataResultViewer. + * 3. Waits for all the Children to be contentNode in the DataResultViewer and + * selects the Node that represents the Content. */ public class ViewContextAction extends AbstractAction { @@ -84,48 +90,48 @@ public class ViewContextAction extends AbstractAction { Node generated = new DirectoryTreeFilterNode(new AbstractNode(new RootContentChildren(hierarchy)), true); Children genChilds = generated.getChildren(); - final DirectoryTreeTopComponent directoryTree = DirectoryTreeTopComponent.findInstance(); - TreeView tree = directoryTree.getTree(); - ExplorerManager man = directoryTree.getExplorerManager(); - Node dirRoot = man.getRootContext(); - Children dirChilds = dirRoot.getChildren(); - Node imagesRoot = dirChilds.findChild(DataSourcesNode.NAME); - dirChilds = imagesRoot.getChildren(); + final DirectoryTreeTopComponent dirTree = DirectoryTreeTopComponent.findInstance(); + TreeView dirTreeView = dirTree.getTree(); + ExplorerManager dirTreeExplorerManager = dirTree.getExplorerManager(); + Node dirTreeRootNode = dirTreeExplorerManager.getRootContext(); + Children dirChilds = dirTreeRootNode.getChildren(); + Children currentChildren = dirChilds.findChild(DataSourcesNode.NAME).getChildren(); Node dirExplored = null; + // Find the parent node of the content in the directory tree for (int i = 0; i < genChilds.getNodesCount() - 1; i++) { Node currentGeneratedNode = genChilds.getNodeAt(i); - for (int j = 0; j < dirChilds.getNodesCount(); j++) { - Node currentDirectoryTreeNode = dirChilds.getNodeAt(j); + for (int j = 0; j < currentChildren.getNodesCount(); j++) { + Node currentDirectoryTreeNode = currentChildren.getNodeAt(j); if (currentGeneratedNode.getDisplayName().equals(currentDirectoryTreeNode.getDisplayName())) { dirExplored = currentDirectoryTreeNode; - tree.expandNode(dirExplored); - dirChilds = currentDirectoryTreeNode.getChildren(); + dirTreeView.expandNode(dirExplored); + currentChildren = currentDirectoryTreeNode.getChildren(); break; } } } + // Set the parent node of the content as the selection in the + // directory tree try { if (dirExplored != null) { - tree.expandNode(dirExplored); - man.setExploredContextAndSelection(dirExplored, new Node[]{dirExplored}); + dirTreeView.expandNode(dirExplored); + dirTreeExplorerManager.setExploredContextAndSelection(dirExplored, new Node[]{dirExplored}); } - } catch (PropertyVetoException ex) { logger.log(Level.WARNING, "Couldn't set selected node", ex); } - // Another thread is needed because we have to wait for dataResult to populate + EventQueue.invokeLater(new Runnable() { @Override public void run() { - DataResultTopComponent dataResult = directoryTree.getDirectoryListing(); - Node resultRoot = dataResult.getRootNode(); - Node generated = content.accept(new RootContentChildren.CreateSleuthkitNodeVisitor()); - new SelectionWorker(dataResult, generated.getName(), resultRoot).execute(); - + DataResultTopComponent dataResultTC = dirTree.getDirectoryListing(); + Node currentRootNodeOfDataResultTC = dataResultTC.getRootNode(); + Node contentNode = content.accept(new RootContentChildren.CreateSleuthkitNodeVisitor()); + new SelectionWorker(dataResultTC, contentNode.getName(), currentRootNodeOfDataResultTC).execute(); } }); } @@ -133,47 +139,60 @@ public class ViewContextAction extends AbstractAction { } /** - * Thread that waits for a Node's children to completely be generated (they - * may be lazily loaded), then sets the correct selection in a + * Waits for a Node's children to be generated, regardless of whether they + * are lazily loaded, then sets the correct selection in a specified * DataResultTopComponent. */ private class SelectionWorker extends SwingWorker { - DataResultTopComponent dataResult; + DataResultTopComponent dataResultTC; String nameOfNodeToSelect; - Node originalRootNode; + Node originalRootNodeOfDataResultTC; SelectionWorker(DataResultTopComponent dataResult, String nameToSelect, Node originalRoot) { - this.dataResult = dataResult; + this.dataResultTC = dataResult; this.nameOfNodeToSelect = nameToSelect; - this.originalRootNode = originalRoot; + this.originalRootNodeOfDataResultTC = originalRoot; } @Override protected Node[] doInBackground() throws Exception { - return originalRootNode.getChildren().getNodes(true); + // Calls to Children::getNodes(true) block until all child Nodes have + // been created, regardless of whether they are created lazily. + // This means that this call will return the actual child Nodes + // and will *NEVER* return a proxy wait Node. This is done on the + // background thread to ensure we are not hanging the ui as it could + // be a lengthy operation. + return originalRootNodeOfDataResultTC.getChildren().getNodes(true); } @Override protected void done() { - Node[] nodes; + Node[] nodesDisplayedInDataResultViewer; try { - nodes = get(); + nodesDisplayedInDataResultViewer = get(); } catch (InterruptedException | ExecutionException ex) { - logger.log(Level.WARNING, "Failed to get nodes in selection worker."); + logger.log(Level.WARNING, "Failed to get nodes in selection worker.", ex); return; } - // If the root node of the data result viewer has changed, don't - // set the selection. - if (dataResult.getRootNode().equals(originalRootNode) == false) { + // It is possible the user selected a different Node to be displayed + // in the DataResultViewer while the child Nodes were being generated. + // In that case, we don't want to set the selection because it the + // nodes returned from get() won't be in the DataResultTopComponent's + // ExplorerManager. If we did call setSelectedNodes, it would clear + // the current selection, which is not good. + if (dataResultTC.getRootNode().equals(originalRootNodeOfDataResultTC) == false) { return; } - for (Node current : nodes) { - if (nameOfNodeToSelect.equals(current.getName())) { - dataResult.requestActive(); - dataResult.setSelectedNodes(new Node[]{current}); + // Find the correct node to select from the nodes that are displayed + // in the data result viewer and set it as the selection of the + // DataResultTopComponent. + for (Node node : nodesDisplayedInDataResultViewer) { + if (nameOfNodeToSelect.equals(node.getName())) { + dataResultTC.requestActive(); + dataResultTC.setSelectedNodes(new Node[]{node}); DirectoryTreeTopComponent.getDefault().fireViewerComplete(); break; } From b4cc51ce0dd63b7e01ead184a0f320f704837055 Mon Sep 17 00:00:00 2001 From: Jeff Wallace Date: Tue, 26 Nov 2013 09:56:37 -0500 Subject: [PATCH 6/9] Removed regex type drop down from advanced keyword search config. --- .../autopsy/keywordsearch/Bundle.properties | 1 - .../KeywordSearchEditListPanel.form | 28 ++--------- .../KeywordSearchEditListPanel.java | 48 ++----------------- 3 files changed, 8 insertions(+), 69 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties index 1bfc26e95b..7b728c5005 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties @@ -38,7 +38,6 @@ KeywordSearchPanel.settingsLabel.text= KeywordSearchListsViewerPanel.searchAddButton.text=Search KeywordSearchListsViewerPanel.manageListsButton.text=Manage Lists KeywordSearchListsViewerPanel.ingestIndexLabel.text=Files Indexed: -KeywordSearchEditListPanel.selectorsCombo.toolTipText=Regular Expression selector type (optional) KeywordSearchPanel.searchButton.text= KeywordSearchPanel.cutMenuItem.text=Cut KeywordSearchPanel.copyMenuItem.text=Copy diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchEditListPanel.form b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchEditListPanel.form index 326354f950..8e9ae1651c 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchEditListPanel.form +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchEditListPanel.form @@ -206,20 +206,16 @@ - + - + - - - - - + @@ -234,10 +230,7 @@ - - - - + @@ -276,19 +269,6 @@ - - - - - - - - - - - - - diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchEditListPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchEditListPanel.java index a720dde3ba..ce91aefd16 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchEditListPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchEditListPanel.java @@ -126,18 +126,6 @@ class KeywordSearchEditListPanel extends javax.swing.JPanel implements ListSelec break; } } - if (selected > -1 && selected < keywords.size()) { - Keyword k = keywords.get(selected); - BlackboardAttribute.ATTRIBUTE_TYPE selType = k.getType(); - if (selType != null) { - selectorsCombo.setSelectedIndex(selType.ordinal()); - } else { - //set to none (last item) - selectorsCombo.setSelectedIndex(selectorsCombo.getItemCount() - 1); - } - } - - } } }); @@ -195,15 +183,6 @@ class KeywordSearchEditListPanel extends javax.swing.JPanel implements ListSelec } } }); - - //selectors - selectorsCombo.setEnabled(false); - for (BlackboardAttribute.ATTRIBUTE_TYPE type : BlackboardAttribute.ATTRIBUTE_TYPE.values()) { - selectorsCombo.addItem(type.getDisplayName()); - } - selectorsCombo.addItem(""); - selectorsCombo.setSelectedIndex(selectorsCombo.getItemCount() - 1); - } /** @@ -251,7 +230,6 @@ class KeywordSearchEditListPanel extends javax.swing.JPanel implements ListSelec chRegex.setEnabled(listSet && (!ingestOngoing || !inIngest) && !isLocked); keywordOptionsLabel.setEnabled(addWordButton.isEnabled() || chRegex.isEnabled()); keywordOptionsSeparator.setEnabled(addWordButton.isEnabled() || chRegex.isEnabled()); - selectorsCombo.setEnabled(listSet && (!ingestOngoing || !inIngest) && !isLocked && chRegex.isSelected()); useForIngestCheckbox.setEnabled(listSet && (!ingestOngoing || !inIngest)); useForIngestCheckbox.setSelected(useForIngest); ingestMessagesCheckbox.setEnabled(useForIngestCheckbox.isEnabled() && useForIngestCheckbox.isSelected()); @@ -295,7 +273,6 @@ class KeywordSearchEditListPanel extends javax.swing.JPanel implements ListSelec addWordButton = new javax.swing.JButton(); addWordField = new javax.swing.JTextField(); chRegex = new javax.swing.JCheckBox(); - selectorsCombo = new javax.swing.JComboBox(); deleteWordButton = new javax.swing.JButton(); ingestMessagesCheckbox = new javax.swing.JCheckBox(); keywordsLabel = new javax.swing.JLabel(); @@ -359,8 +336,6 @@ class KeywordSearchEditListPanel extends javax.swing.JPanel implements ListSelec } }); - selectorsCombo.setToolTipText(org.openide.util.NbBundle.getMessage(KeywordSearchEditListPanel.class, "KeywordSearchEditListPanel.selectorsCombo.toolTipText")); // NOI18N - deleteWordButton.setText(org.openide.util.NbBundle.getMessage(KeywordSearchEditListPanel.class, "KeywordSearchEditListPanel.deleteWordButton.text")); // NOI18N deleteWordButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -373,17 +348,14 @@ class KeywordSearchEditListPanel extends javax.swing.JPanel implements ListSelec addKeywordPanelLayout.setHorizontalGroup( addKeywordPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(addKeywordPanelLayout.createSequentialGroup() - .addGroup(addKeywordPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addGroup(addKeywordPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addGroup(addKeywordPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(addKeywordPanelLayout.createSequentialGroup() - .addComponent(addWordField) + .addComponent(addWordField, javax.swing.GroupLayout.PREFERRED_SIZE, 216, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(addWordButton)) .addComponent(deleteWordButton)) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, addKeywordPanelLayout.createSequentialGroup() - .addComponent(chRegex) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(selectorsCombo, javax.swing.GroupLayout.PREFERRED_SIZE, 154, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(chRegex, javax.swing.GroupLayout.Alignment.LEADING)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); addKeywordPanelLayout.setVerticalGroup( @@ -394,9 +366,7 @@ class KeywordSearchEditListPanel extends javax.swing.JPanel implements ListSelec .addComponent(addWordField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(addWordButton)) .addGap(7, 7, 7) - .addGroup(addKeywordPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(selectorsCombo, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(chRegex)) + .addComponent(chRegex) .addGap(7, 7, 7) .addComponent(deleteWordButton) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) @@ -515,14 +485,6 @@ class KeywordSearchEditListPanel extends javax.swing.JPanel implements ListSelec String newWord = addWordField.getText().trim(); boolean isLiteral = !chRegex.isSelected(); final Keyword keyword = new Keyword(newWord, isLiteral); - if (!isLiteral) { - //get selector - int selI = this.selectorsCombo.getSelectedIndex(); - if (selI < this.selectorsCombo.getItemCount() - 1) { - BlackboardAttribute.ATTRIBUTE_TYPE selector = BlackboardAttribute.ATTRIBUTE_TYPE.values()[selI]; - keyword.setType(selector); - } - } if (newWord.equals("")) { return; @@ -620,7 +582,6 @@ class KeywordSearchEditListPanel extends javax.swing.JPanel implements ListSelec }//GEN-LAST:event_exportButtonActionPerformed private void chRegexActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chRegexActionPerformed - selectorsCombo.setEnabled(chRegex.isEnabled() && chRegex.isSelected()); }//GEN-LAST:event_chRegexActionPerformed private void useForIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useForIngestCheckboxActionPerformed @@ -659,7 +620,6 @@ private void useForIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) private javax.swing.JPopupMenu rightClickMenu; private javax.swing.JButton saveListButton; private javax.swing.JMenuItem selectAllMenuItem; - private javax.swing.JComboBox selectorsCombo; private javax.swing.JCheckBox useForIngestCheckbox; // End of variables declaration//GEN-END:variables From 70ed69dd1f90215d793f8d81b2f20c09d0444007 Mon Sep 17 00:00:00 2001 From: Jeff Wallace Date: Mon, 2 Dec 2013 12:33:36 -0500 Subject: [PATCH 7/9] Format extracted html content appropriately --- .../keywordsearch/JerichoParserWrapper.java | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/JerichoParserWrapper.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/JerichoParserWrapper.java index aea91e3f5a..28c1c7ede9 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/JerichoParserWrapper.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/JerichoParserWrapper.java @@ -26,10 +26,10 @@ import java.util.List; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; import net.htmlparser.jericho.Attributes; +import net.htmlparser.jericho.Renderer; import net.htmlparser.jericho.Source; import net.htmlparser.jericho.StartTag; import net.htmlparser.jericho.StartTagType; -import net.htmlparser.jericho.TextExtractor; /** * Uses Jericho HTML Parser to create a Reader for output, consisting of @@ -57,7 +57,7 @@ public class JerichoParserWrapper { Source source = new Source(in); source.fullSequentialParse(); - StringBuilder text = new StringBuilder(); + String text; StringBuilder scripts = new StringBuilder(); StringBuilder links = new StringBuilder(); StringBuilder images = new StringBuilder(); @@ -68,14 +68,8 @@ public class JerichoParserWrapper { int numImages = 1; int numComments = 1; int numOthers = 1; - - // Extract text from the source - TextExtractor extractor = new TextExtractor(source); - // Split it at every ". " but keep the . - String[] lines = extractor.toString().split("(?<=\\. )"); - for(String s : lines) { - text.append(s).append("\n"); - } + + text = renderHTMLAsPlainText(source); // Get all the tags in the source List tags = source.getAllStartTags(); @@ -113,7 +107,7 @@ public class JerichoParserWrapper { } } - out.append(text.toString()).append("\n"); + out.append(text).append("\n"); out.append("----------NONVISIBLE TEXT----------\n\n"); if(numScripts>1) { @@ -147,5 +141,15 @@ public class JerichoParserWrapper { public Reader getReader() { return reader; } - + + // Extract text from the source, nicely formatted with whitespace and + // newlines where appropriate. + private String renderHTMLAsPlainText(Source source) { + Renderer renderer = source.getRenderer(); + renderer.setNewLine("\n"); + renderer.setIncludeHyperlinkURLs(false); + renderer.setDecorateFontStyles(false); + renderer.setIncludeAlternateText(false); + return renderer.toString(); + } } From 3abaa97e7a4de4d5059f0337ef830585bb9c0171 Mon Sep 17 00:00:00 2001 From: Jeff Wallace Date: Mon, 2 Dec 2013 12:36:19 -0500 Subject: [PATCH 8/9] Minor clean up of jericho parser wrapper --- .../keywordsearch/JerichoParserWrapper.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/JerichoParserWrapper.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/JerichoParserWrapper.java index 28c1c7ede9..50b7f0fc89 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/JerichoParserWrapper.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/JerichoParserWrapper.java @@ -46,6 +46,15 @@ public class JerichoParserWrapper { this.in = in; } + /** + * Returns the reader, initialized in parse(), which will be + * null if parse() is not called or if parse() throws an error. + * @return Reader + */ + public Reader getReader() { + return reader; + } + /** * Initialize the reader by parsing the InputStream, adding it to StringBuilder, * and creating a StringReader from it. @@ -133,15 +142,6 @@ public class JerichoParserWrapper { } } - /** - * Returns the reader, initialized in parse(), which will be - * null if parse() is not called or if parse() throws an error. - * @return Reader - */ - public Reader getReader() { - return reader; - } - // Extract text from the source, nicely formatted with whitespace and // newlines where appropriate. private String renderHTMLAsPlainText(Source source) { From 4808d8785560f629df6d603c57fc09338afc253a Mon Sep 17 00:00:00 2001 From: Jeff Wallace Date: Mon, 2 Dec 2013 12:40:31 -0500 Subject: [PATCH 9/9] Fixed spacing. --- .../sleuthkit/autopsy/keywordsearch/JerichoParserWrapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/JerichoParserWrapper.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/JerichoParserWrapper.java index 50b7f0fc89..ba723ddff4 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/JerichoParserWrapper.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/JerichoParserWrapper.java @@ -116,7 +116,7 @@ public class JerichoParserWrapper { } } - out.append(text).append("\n"); + out.append(text).append("\n\n"); out.append("----------NONVISIBLE TEXT----------\n\n"); if(numScripts>1) {