diff --git a/Core/src/org/sleuthkit/autopsy/communications/MessageBrowser.java b/Core/src/org/sleuthkit/autopsy/communications/MessageBrowser.java
index 7b90357993e4766a615d994cb3126bf3d90a1445..dca177046394898f9409f0b0d30b70c548a9ab44 100644
--- a/Core/src/org/sleuthkit/autopsy/communications/MessageBrowser.java
+++ b/Core/src/org/sleuthkit/autopsy/communications/MessageBrowser.java
@@ -128,7 +128,7 @@ public void propertyChange(final PropertyChangeEvent focusEvent) {
             public void propertyChange(PropertyChangeEvent pce) {
                 if (pce.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
                     final Node[] selectedNodes = MessageBrowser.this.tableEM.getSelectedNodes();
-                    messagesResultPanel.setNumMatches(0);
+                    messagesResultPanel.setNumberOfChildNodes(0);
                     messagesResultPanel.setNode(null);
                     messagesResultPanel.setPath("");
                     if (selectedNodes.length > 0) {
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java
index 960f90f39ea4bbd35d7912a42528a7020a496e34..8726cfedb64592383546ba89d4a9584f5644292c 100644
--- a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java
+++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java
@@ -98,7 +98,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
     @NbBundle.Messages("MessageContentViewer.AtrachmentsPanel.title=Attachments")
     public MessageContentViewer() {
         initComponents();
-        drp = DataResultPanel.createInstanceUninitialized(Bundle.MessageContentViewer_AtrachmentsPanel_title(), "", Node.EMPTY, 0, null);
+        drp = DataResultPanel.createInstanceUninitialized(Bundle.MessageContentViewer_AtrachmentsPanel_title(), "", new TableFilterNode(Node.EMPTY, false), 0, null);
         attachmentsScrollPane.setViewportView(drp);
         msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, true);
 
diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResult.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResult.java
index 191a851b9a2556563ba6b231ffa5c001e2314f4b..6af30b8729c1b716dc2f7deb4cd5a003a46ca38d 100644
--- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResult.java
+++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResult.java
@@ -1,7 +1,7 @@
 /*
  * Autopsy Forensic Browser
  *
- * Copyright 2011 Basis Technology Corp.
+ * Copyright 2012-2018 Basis Technology Corp.
  * Contact: carrier <at> sleuthkit <dot> org
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,41 +22,58 @@
 import org.openide.nodes.Node;
 
 /**
- * The interface for the "top right component" window.
+ * An interface for result view components. A result view component provides
+ * multiple views of the application data represented by a given NetBeans Node.
+ * The differing views of the node are supplied by a collection of result
+ * viewers (implementations of the DataResultViewer interface).
  *
+ * A typical implementation of this interface are the NetBeans TopComponents
+ * (DataResultTopComponents) that use a child result view component
+ * (DataResultPanel) for displaying their result viewers, and are docked into
+ * the upper right hand side (editor mode) of the main application window.
  */
 public interface DataResult {
 
     /**
-     * Sets the "selected" node in this class.
+     * Sets the node for which this result view component should provide
+     * multiple views of the underlying application data.
+     *
+     * @param node The node, may be null. If null, the call to this method is
+     *             equivalent to a call to resetComponent on this result view
+     *             component's result viewers.
      */
-    public void setNode(Node selectedNode);
+    public void setNode(Node node);
 
     /**
-     * Gets the unique TopComponent ID of this class.
+     * Gets the preferred identifier for this result view panel in the window
+     * system.
      *
-     * @return preferredID the unique ID
+     * @return The preferred identifier.
      */
     public String getPreferredID();
 
     /**
-     * Sets the title of this TopComponent
+     * Sets the title of this result view component.
      *
-     * @param title the given title (String)
+     * @param title The title.
      */
     public void setTitle(String title);
 
     /**
-     * Sets the descriptive context text at the top of the pane.
+     * Sets the descriptive text about the source of the nodes displayed in this
+     * result view component.
      *
-     * @param pathText Descriptive text giving context for the current results
+     * @param description The text to display.
      */
     public void setPath(String pathText);
 
     /**
-     * Checks if this is the main (uncloseable) instance of DataResult
+     * Gets whether or not this result view panel is the "main" result view
+     * panel used to view the child nodes of a node selected in the application
+     * tree view (DirectoryTreeTopComponent) that is normally docked into the
+     * left hand side of the main window.
      *
-     * @return true if it is the main instance, otherwise false
+     * @return True or false.
      */
     public boolean isMain();
 
diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResultViewer.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResultViewer.java
index d88c9798445facea3d5b483db1d09cfa5c349af3..c9d305f53ec92978a435f9ba26246b204472e5bf 100644
--- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResultViewer.java
+++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResultViewer.java
@@ -1,7 +1,7 @@
 /*
  * Autopsy Forensic Browser
  *
- * Copyright 2011-17 Basis Technology Corp.
+ * Copyright 2012-2018 Basis Technology Corp.
  * Contact: carrier <at> sleuthkit <dot> org
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,76 +22,120 @@
 import org.openide.nodes.Node;
 
 /**
- * Interface for the different viewers that show a set of nodes in the
- * DataResult area. AbstractDataResultViewer has default implementations for the
- * action handlers.
+ * An interface for result viewers. A result viewer uses a Swing Component to
+ * provide a view of the application data represented by a NetBeans Node passed
+ * to it via its setNode method.
  *
+ * Result viewers are most commonly presented as a tab in a result view panel
+ * (DataResultPanel) inside a result view top component (DataResultTopComponent)
+ * that is docked into the upper right hand side (editor mode) of the main
+ * application window.
+ *
+ * A result viewer is typically a JPanel that displays the child nodes of the
+ * given node using a NetBeans explorer view child component. Such a result
+ * viewer should use the explorer manager of the ancestor top component to
+ * connect the lookups of the nodes displayed in the NetBeans explorer view to
+ * the actions global context. It is strongly recommended that this type of
+ * result viewer is implemented by extending the abstract base class
+ * AbstractDataResultViewer, which will handle some key aspects of working with
+ * the ancestor top component's explorer manager.
+ *
+ * This interface is an extension point, so classes that implement it should
+ * provide an appropriate ServiceProvider annotation.
  */
 public interface DataResultViewer {
 
     /**
-     * Set the root node to display in this viewer. When called with null, must
-     * clear all references to previous nodes.
+     * Creates a new instance of this result viewer, which allows the
+     * application to use the capability provided by this result viewer in more
+     * than one result view. This is done by using the default instance of this
+     * result viewer as a "factory" for creating other instances.
      */
-    public void setNode(Node selectedNode);
+    public DataResultViewer createInstance();
 
     /**
-     * Gets the title of this viewer
+     * Indicates whether this result viewer is able to provide a meaningful view
+     * of the application data represented by a given node. Typically, indicates
+     * whether or not this result viewer can use the given node as the root node
+     * of its child explorer view component.
+     *
+     * @param node The node.
+     *
+     * @return True or false.
      */
-    public String getTitle();
+    public boolean isSupported(Node node);
 
     /**
-     * Get a new instance of DataResultViewer
+     * Sets the node for which this result viewer should provide a view of the
+     * underlying application data. Typically, this means using the given node
+     * as the root node of this result viewer's child explorer view component.
+     *
+     * @param node The node, may be null. If null, the call to this method is
+     *             equivalent to a call to resetComponent.
      */
-    public DataResultViewer createInstance();
+    public void setNode(Node node);
 
     /**
-     * Get the Swing component (i.e. JPanel) for this viewer
+     * Requests selection of the given child nodes of the node passed to
+     * setNode. This method should be implemented as a no-op for result viewers
+     * that do not display the child nodes of a given root node using a NetBeans
+     * explorer view set up to use a given explorer manager.
+     *
+     * @param selectedNodes The child nodes to select.
      */
-    public Component getComponent();
+    default public void setSelectedNodes(Node[] selectedNodes) {
+    }
 
     /**
-     * Resets the viewer.
+     * Gets the title of this result viewer.
+     *
+     * @return The title.
      */
-    public void resetComponent();
+    public String getTitle();
 
     /**
-     * Frees the objects that have been allocated by this viewer, in preparation
-     * for permanently disposing of it.
+     * Gets the Swing component for this viewer.
+     *
+     * @return The component.
      */
-    public void clearComponent();
+    public Component getComponent();
 
     /**
-     * Expand node, if supported by the viewed
-     *
-     * @param n Node to expand
+     * Resets the state of the Swing component for this viewer to its default
+     * state.
      */
-    public void expandNode(Node n);
+    default public void resetComponent() {
+    }
 
     /**
-     * Select the given node array
+     * Frees any resources tha have been allocated by this result viewer, in
+     * preparation for permanently disposing of it.
      */
-    public void setSelectedNodes(Node[] selected);
+    default public void clearComponent() {
+    }
 
     /**
-     * Checks whether the currently selected root node is supported by this
-     * viewer
+     * Sets the node for which this result viewer should provide a view of the
+     * underlying application data model object, and expands the node.
      *
-     * @param selectedNode the selected node
+     * @param node The node.
      *
-     * @return True if supported, else false
+     * @deprecated This API is not used by the application.
      */
-    public boolean isSupported(Node selectedNode);
+    @Deprecated
+    default public void expandNode(Node node) {
+    }
 
     /**
-     * Set a custom content viewer to respond to selection events from this
-     * result viewer. If not set, the default content viewer is used
+     * Sets a custom content viewer to which nodes selected in this result
+     * viewer should be pushed via DataContent.setNode.
      *
-     * @param contentViewer content viewer to respond to selection events from
-     *                      this viewer
+     * @param contentViewer The content viewer.
      *
-     * @deprecated All implementations of this in the standard DataResultViewers are now no-ops.
+     * @deprecated This API is not used by the application.
      */
     @Deprecated
-    public void setContentViewer(DataContent contentViewer);
+    default public void setContentViewer(DataContent contentViewer) {
+    }
+
 }
diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AbstractDataResultViewer.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AbstractDataResultViewer.java
index 26d58d6efff09707dcbaafc816ec099b0cb0f733..fdabf16ac08db9300c6c6a1737e32cb176f51da6 100644
--- a/Core/src/org/sleuthkit/autopsy/corecomponents/AbstractDataResultViewer.java
+++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AbstractDataResultViewer.java
@@ -1,7 +1,7 @@
 /*
  * Autopsy Forensic Browser
  *
- * Copyright 2011-17 Basis Technology Corp.
+ * Copyright 2012-2018 Basis Technology Corp.
  * Contact: carrier <at> sleuthkit <dot> org
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,88 +23,69 @@
 import java.util.logging.Level;
 import javax.swing.JPanel;
 import org.openide.explorer.ExplorerManager;
-import org.openide.explorer.ExplorerManager.Provider;
 import org.openide.nodes.Node;
-import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent;
 import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
 import org.sleuthkit.autopsy.coreutils.Logger;
 
 /**
- * This class provides a default implementation of selected methods of the
- * DataResultViewer interface. Derived classes will be Swing JPanel objects.
- * Additionally, the ExplorerManager.Provider interface is implemented to supply
- * an ExplorerManager to derived classes and their child components.
+ * An abstract base class for an implementation of the result viewer interface
+ * that is a JPanel that displays the child nodes of a given node using a
+ * NetBeans explorer view as a child component. Such a result viewer should use
+ * the explorer manager of an ancestor top component to connect the lookups of
+ * the nodes displayed in the NetBeans explorer view to the actions global
+ * context. This class handles some key aspects of working with the ancestor top
+ * component's explorer manager.
+ *
+ * Instances of this class can be supplied with the top component's explorer
+ * manager during construction, but the typical use case is for the result
+ * viewer to find the ancestor top component's explorer manager at runtime.
+ *
+ * IMPORTANT: If the result viewer is going to find the ancestor top component's
+ * explorer manager at runtime, the first call to the getExplorerManager method
+ * of this class must be made AFTER the component hierarchy is fully
+ * constructed.
+ *
  */
-abstract class AbstractDataResultViewer extends JPanel implements DataResultViewer, Provider {
+public abstract class AbstractDataResultViewer extends JPanel implements DataResultViewer, ExplorerManager.Provider {
 
     private static final Logger logger = Logger.getLogger(AbstractDataResultViewer.class.getName());
-    protected transient ExplorerManager em;
+    private transient ExplorerManager explorerManager;
 
     /**
-     * This constructor is intended to allow an AbstractDataResultViewer to use
-     * an ExplorerManager provided by a TopComponent, allowing Node selections
-     * to be available to Actions via the action global context lookup when the
-     * TopComponent has focus. The ExplorerManager must be present when the
-     * object is constructed so that its child components can discover it using
-     * the ExplorerManager.find() method.
+     * Constructs an abstract base class for an implementation of the result
+     * viewer interface that is a JPanel that displays the child nodes of the
+     * given node using a NetBeans explorer view as a child component.
      *
-     * @param explorerManager
-     */
-    AbstractDataResultViewer(ExplorerManager explorerManager) {
-        this.em = explorerManager;
-    }
-
-    /**
-     * This constructor can be used by AbstractDataResultViewers that do not
-     * need to make Node selections available to Actions via the action global
-     * context lookup.
+     * @param explorerManager The explorer manager to use in the NetBeans
+     *                        explorer view child component of this result
+     *                        viewer, may be null. If null, the explorer manager
+     *                        will be discovered the first time
+     *                        getExplorerManager is called.
      */
-    public AbstractDataResultViewer() {
-        this(new ExplorerManager());
-    }
-
-    @Override
-    public void clearComponent() {
-    }
-
-    public Node getSelectedNode() {
-        Node result = null;
-        Node[] selectedNodes = this.getExplorerManager().getSelectedNodes();
-        if (selectedNodes.length > 0) {
-            result = selectedNodes[0];
-        }
-        return result;
-    }
-
-    @Override
-    public void expandNode(Node n) {
-    }
-
-    @Override
-    public void resetComponent() {
-    }
-
-    @Override
-    public Component getComponent() {
-        return this;
+    public AbstractDataResultViewer(ExplorerManager explorerManager) {
+        this.explorerManager = explorerManager;
     }
 
     @Override
     public ExplorerManager getExplorerManager() {
-        return this.em;
+        if (this.explorerManager == null) {
+            this.explorerManager = ExplorerManager.find(this);
+        }
+        return this.explorerManager;
     }
 
     @Override
     public void setSelectedNodes(Node[] selected) {
         try {
-            this.em.setSelectedNodes(selected);
+            this.getExplorerManager().setSelectedNodes(selected);
         } catch (PropertyVetoException ex) {
-            logger.log(Level.WARNING, "Couldn't set selected nodes.", ex); //NON-NLS
+            logger.log(Level.SEVERE, "Couldn't set selected nodes", ex); //NON-NLS
         }
     }
 
-    @Deprecated
     @Override
-    public void setContentViewer(DataContent contentViewer) {
+    public Component getComponent() {
+        return this;
     }
+
 }
diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties
index 245fe1744df0085b26961346953347f1470a51bb..c2a9d9845fc59fceec4e527bebbb88210f815df3 100644
--- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties
+++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties
@@ -62,9 +62,6 @@ DataResultViewerThumbnail.filePathLabel.text=\ \ \
 DataResultViewerThumbnail.goToPageLabel.text=Go to Page:
 DataResultViewerThumbnail.goToPageField.text=
 AdvancedConfigurationDialog.cancelButton.text=Cancel
-DataResultPanel.directoryTablePath.text=directoryPath
-DataResultPanel.numberMatchLabel.text=0
-DataResultPanel.matchLabel.text=Results
 DataContentViewerArtifact.waitText=Retrieving and preparing data, please wait...
 DataContentViewerArtifact.errorText=Error retrieving result
 DataContentViewerArtifact.title=Results
@@ -181,3 +178,6 @@ AutopsyOptionsPanel.agencyLogoPreview.text=<html><div style='text-align: center;
 AutopsyOptionsPanel.logoPanel.border.title=Logo
 AutopsyOptionsPanel.runtimePanel.border.title=Runtime
 AutopsyOptionsPanel.viewPanel.border.title=View
+DataResultPanel.matchLabel.text=Results
+DataResultPanel.numberOfChildNodesLabel.text=0
+DataResultPanel.descriptionLabel.text=directoryPath
diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle_ja.properties
index 6505a09862f36f8457bd6f6a8a030421bfc182d7..cbdabb3747031a9a1a20bef1901e0e6d3bd44afe 100644
--- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle_ja.properties
+++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle_ja.properties
@@ -37,9 +37,6 @@ DataResultViewerThumbnail.imagesRangeLabel.text=-
 DataResultViewerThumbnail.pageNumLabel.text=-
 DataResultViewerThumbnail.goToPageLabel.text=\u6b21\u306e\u30da\u30fc\u30b8\u306b\u79fb\u52d5\uff1a
 AdvancedConfigurationDialog.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb
-DataResultPanel.directoryTablePath.text=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30d1\u30b9
-DataResultPanel.numberMatchLabel.text=0
-DataResultPanel.matchLabel.text=\u7d50\u679c
 DataContentViewerArtifact.waitText=\u30c7\u30fc\u30bf\u3092\u53d6\u8fbc\u307f\u304a\u3088\u3073\u6e96\u5099\u4e2d\u3002\u3057\u3070\u3089\u304f\u304a\u5f85\u3061\u4e0b\u3055\u3044...
 DataContentViewerArtifact.errorText=\u7d50\u679c\u3092\u53d6\u8fbc\u307f\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
 DataContentViewerArtifact.title=\u7d50\u679c
@@ -131,3 +128,6 @@ DataResultViewerThumbnail.thumbnailSizeComboBox.small=\u30b5\u30e0\u30cd\u30a4\u
 MediaViewImagePanel.errorLabel.OOMText=\u30d5\u30a1\u30a4\u30eb\u3092\u30e1\u30c7\u30a3\u30a2\u30d3\u30e5\u30fc\u306b\u8aad\u307f\u8fbc\u3081\u307e\u305b\u3093\u3067\u3057\u305f\uff1a\u30e1\u30e2\u30ea\u4e0d\u8db3\u3002
 MediaViewImagePanel.errorLabel.text=\u30d5\u30a1\u30a4\u30eb\u3092\u30e1\u30c7\u30a3\u30a2\u30d3\u30e5\u30fc\u306b\u8aad\u307f\u8fbc\u3081\u307e\u305b\u3093\u3067\u3057\u305f\u3002
 MediaViewImagePanel.externalViewerButton.text=\u5916\u90e8\u30d3\u30e5\u30fc\u30a2\u30fc\u3067\u958b\u304f
+DataResultPanel.matchLabel.text=\u7d50\u679c
+DataResultPanel.numberOfChildNodesLabel.text=0
+DataResultPanel.descriptionLabel.text=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30d1\u30b9
diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.form
index 0a6ea4b4a6622b8ad55bcacc74a09c16c8b1be2f..3c24e28182ac20e79536bbf35fae7de775180dcd 100644
--- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.form
+++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.form
@@ -25,13 +25,13 @@
     <DimensionLayout dim="0">
       <Group type="103" groupAlignment="0" attributes="0">
           <Group type="102" attributes="0">
-              <Component id="directoryTablePath" min="-2" max="-2" attributes="0"/>
+              <Component id="descriptionLabel" min="-2" max="-2" attributes="0"/>
               <EmptySpace max="32767" attributes="0"/>
-              <Component id="numberMatchLabel" min="-2" max="-2" attributes="0"/>
+              <Component id="numberOfChildNodesLabel" min="-2" max="-2" attributes="0"/>
               <EmptySpace max="-2" attributes="0"/>
               <Component id="matchLabel" min="-2" max="-2" attributes="0"/>
           </Group>
-          <Component id="dataResultTabbedPanel" max="32767" attributes="0"/>
+          <Component id="resultViewerTabs" max="32767" attributes="0"/>
       </Group>
     </DimensionLayout>
     <DimensionLayout dim="1">
@@ -39,32 +39,32 @@
           <Group type="102" attributes="0">
               <Group type="103" groupAlignment="0" attributes="0">
                   <Group type="103" alignment="0" groupAlignment="3" attributes="0">
-                      <Component id="numberMatchLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="numberOfChildNodesLabel" alignment="3" min="-2" max="-2" attributes="0"/>
                       <Component id="matchLabel" alignment="3" min="-2" max="-2" attributes="0"/>
                   </Group>
-                  <Component id="directoryTablePath" alignment="0" min="-2" max="-2" attributes="0"/>
+                  <Component id="descriptionLabel" alignment="0" min="-2" max="-2" attributes="0"/>
               </Group>
               <EmptySpace min="0" pref="0" max="-2" attributes="0"/>
-              <Component id="dataResultTabbedPanel" max="32767" attributes="0"/>
+              <Component id="resultViewerTabs" max="32767" attributes="0"/>
           </Group>
       </Group>
     </DimensionLayout>
   </Layout>
   <SubComponents>
-    <Component class="javax.swing.JLabel" name="directoryTablePath">
+    <Component class="javax.swing.JLabel" name="descriptionLabel">
       <Properties>
         <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-          <ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultPanel.directoryTablePath.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+          <ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultPanel.descriptionLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
         </Property>
         <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
           <Dimension value="[5, 14]"/>
         </Property>
       </Properties>
     </Component>
-    <Component class="javax.swing.JLabel" name="numberMatchLabel">
+    <Component class="javax.swing.JLabel" name="numberOfChildNodesLabel">
       <Properties>
         <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-          <ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultPanel.numberMatchLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+          <ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultPanel.numberOfChildNodesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
         </Property>
       </Properties>
     </Component>
@@ -75,7 +75,7 @@
         </Property>
       </Properties>
     </Component>
-    <Container class="javax.swing.JTabbedPane" name="dataResultTabbedPanel">
+    <Container class="javax.swing.JTabbedPane" name="resultViewerTabs">
       <Properties>
         <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
           <Dimension value="[0, 5]"/>
diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java
index 9751bb024ae28b2e31c3c1151e4eb40120f4c693..c9bae6afb936f344b7584c3c4530a60f73aad3a8 100644
--- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java
@@ -1,7 +1,7 @@
 /*
  * Autopsy Forensic Browser
  *
- * Copyright 2011-2018 Basis Technology Corp.
+ * Copyright 2013-2018 Basis Technology Corp.
  * Contact: carrier <at> sleuthkit <dot> org
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,6 +22,7 @@
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import javax.swing.JTabbedPane;
@@ -44,153 +45,204 @@
 import org.sleuthkit.autopsy.datamodel.NodeSelectionInfo;
 
 /**
- * A Swing JPanel with a JTabbedPane child component. The tabbed pane contains
- * result viewers.
+ * A result view panel is a JPanel with a JTabbedPane child component that
+ * contains a collection of result viewers and implements the DataResult
+ * interface. The result viewers in a result view panel are either supplied
+ * during construction of the panel or are obtained from the result viewer
+ * extension point (DataResultViewer service providers).
  *
- * The "main" DataResultPanel for the desktop application has a table viewer
- * (DataResultViewerTable) and a thumbnail viewer (DataResultViewerThumbnail),
- * plus zero to many additional DataResultViewers, since the DataResultViewer
- * interface is an extension point.
+ * A result view panel provides an implementation of the setNode API of the the
+ * DataResult interface that pushes a given NetBeans Node into its child result
+ * viewers via the DataResultViewer.setNode API. The result viewers are
+ * responsible for providing a view of the application data represented by the
+ * node. A typical result viewer is a JPanel that displays the child nodes of
+ * the given node using a NetBeans explorer view child component.
  *
- * The "main" DataResultPanel resides in the "main" results view
- * (DataResultTopComponent) that is normally docked into the upper right hand
- * side of the main window of the desktop application.
+ * A result panel should be child components of top components that are explorer
+ * manager providers. The parent top component is expected to expose a lookup
+ * maintained by its explorer manager to the actions global context. The child
+ * result view panel will then find the parent top component's explorer manager
+ * at runtime, so that it can act as an explorer manager provider for its child
+ * result viewers. This connects the nodes displayed in the result viewers to
+ * the actions global context.
  *
- * The result viewers in the "main panel" are used to view the child nodes of a
- * node selected in the tree view (DirectoryTreeTopComponent) that is normally
- * docked into the left hand side of the main window of the desktop application.
- *
- * Nodes selected in the child results viewers of a DataResultPanel are
- * displayed in a content view (implementation of the DataContent interface)
- * supplied the panel. The default content view is (DataContentTopComponent) is
- * normally docked into the lower right hand side of the main window, underneath
- * the results view. A custom content view may be specified instead.
+ * All result view panels push single node selections in the child result
+ * viewers to either the "main" content view (DataContentTopComponent) that is
+ * normally docked into the lower right hand side of the main application
+ * window, or to a supplied custom content view (implements DataContent).
  */
 public class DataResultPanel extends javax.swing.JPanel implements DataResult, ChangeListener, ExplorerManager.Provider {
 
     private static final long serialVersionUID = 1L;
     private static final int NO_TAB_SELECTED = -1;
     private static final String PLEASE_WAIT_NODE_DISPLAY_NAME = NbBundle.getMessage(DataResultPanel.class, "DataResultPanel.pleasewaitNodeDisplayName");
-    private final List<DataResultViewer> resultViewers = new ArrayList<>();
-    private boolean isMain;
+    private final boolean isMain;
+    private final List<DataResultViewer> resultViewers;
+    private final ExplorerManagerListener explorerManagerListener;
+    private final RootNodeListener rootNodeListener;
+    private DataContent contentView;
     private ExplorerManager explorerManager;
-    private ExplorerManagerNodeSelectionListener emNodeSelectionListener;
-    private Node rootNode;
-    private final RootNodeListener rootNodeListener = new RootNodeListener();
+    private Node currentRootNode;
     private boolean listeningToTabbedPane;
-    private DataContent contentView;
 
     /**
-     * Constructs and opens a DataResultPanel with the given initial data, and
-     * the default DataContent.
+     * Creates and opens a Swing JPanel with a JTabbedPane child component that
+     * contains instances of the result viewers (DataResultViewer) provided by
+     * the result viewer extension point (service providers that implement
+     * DataResultViewer). The result view panel will push single node selections
+     * from its child result viewers to the "main" content view that is normally
+     * docked into the lower right hand side of the main application window.
      *
-     * @param title        The title for the panel.
-     * @param pathText     Descriptive text about the source of the nodes
-     *                     displayed.
-     * @param rootNode     The new root node.
-     * @param totalMatches Cardinality of root node's children
+     * @param title           The title for the result view panel.
+     * @param description     Descriptive text about the source of the nodes
+     *                        displayed.
+     * @param currentRootNode The current root (parent) node for the nodes
+     *                        displayed. May be changed by calling setNode.
+     * @param childNodeCount  The cardinality of the root node's children.
+     *
+     * @return A result view panel.
+     */
+    public static DataResultPanel createInstance(String title, String description, Node currentRootNode, int childNodeCount) {
+        DataResultPanel resultPanel = new DataResultPanel(title, false, Collections.emptyList(), null);
+        createInstanceCommon(title, description, currentRootNode, childNodeCount, resultPanel);
+        resultPanel.open();
+        return resultPanel;
+    }
+
+    /**
+     * Creates and opens a Swing JPanel with a JTabbedPane child component that
+     * contains a given collection of result viewers (DataResultViewer) instead
+     * of the result viewers provided by the results viewer extension point. The
+     * result view panel will push single node selections from its child result
+     * viewers to the "main" content view that is normally docked into the lower
+     * right hand side of the main application window..
+     *
+     * @param title           The title for the result view panel.
+     * @param description     Descriptive text about the source of the nodes
+     *                        displayed.
+     * @param currentRootNode The current root (parent) node for the nodes
+     *                        displayed. May be changed by calling setNode.
+     * @param childNodeCount  The cardinality of the root node's children.
+     * @param viewers         A collection of result viewers to use instead of
+     *                        the result viewers provided by the results viewer
+     *                        extension point.
      *
-     * @return A DataResultPanel instance.
+     * @return A result view panel.
      */
-    public static DataResultPanel createInstance(String title, String pathText, Node rootNode, int totalMatches) {
-        DataResultPanel resultPanel = new DataResultPanel(title, false);
-        createInstanceCommon(title, pathText, rootNode, totalMatches, resultPanel);
+    public static DataResultPanel createInstance(String title, String description, Node currentRootNode, int childNodeCount, Collection<DataResultViewer> viewers) {
+        DataResultPanel resultPanel = new DataResultPanel(title, false, viewers, null);
+        createInstanceCommon(title, description, currentRootNode, childNodeCount, resultPanel);
         resultPanel.open();
         return resultPanel;
     }
 
     /**
-     * Constructs and opens a DataResultPanel with the given initial data, and a
-     * custom DataContent.
+     * Creates and opens a Swing JPanel with a JTabbedPane child component that
+     * contains instances of the result viewers (DataResultViewer) provided by
+     * the result viewer extension point (service providers that implement
+     * DataResultViewer). The result view panel will push single node selections
+     * from its child result viewers to the supplied custom content view.
      *
-     * @param title             The title for the panel.
-     * @param pathText          Descriptive text about the source of the nodes
+     * @param title             The title for the result view panel.
+     * @param description       Descriptive text about the source of the nodes
      *                          displayed.
-     * @param rootNode          The new root node.
-     * @param totalMatches      Cardinality of root node's children
-     * @param customContentView A content view to use in place of the default
-     *                          content view.
+     * @param currentRootNode   The current root (parent) node for the nodes
+     *                          displayed. May be changed by calling setNode.
+     * @param childNodeCount    The cardinality of the root node's children.
+     * @param customContentView A custom content view to use instead of the
+     *                          "main" content view that is normally docked into
+     *                          the lower right hand side of the main
+     *                          application window.
      *
-     * @return A DataResultPanel instance.
+     * @return A result view panel.
      */
-    public static DataResultPanel createInstance(String title, String pathText, Node rootNode, int totalMatches, DataContent customContentView) {
-        DataResultPanel resultPanel = new DataResultPanel(title, customContentView);
-        createInstanceCommon(title, pathText, rootNode, totalMatches, resultPanel);
+    public static DataResultPanel createInstance(String title, String description, Node currentRootNode, int childNodeCount, DataContent customContentView) {
+        DataResultPanel resultPanel = new DataResultPanel(title, false, Collections.emptyList(), customContentView);
+        createInstanceCommon(title, description, currentRootNode, childNodeCount, resultPanel);
         resultPanel.open();
         return resultPanel;
     }
 
     /**
-     * Constructs a DataResultPanel with the given initial data, and a custom
-     * DataContent. The panel is NOT opened; the client of this method must call
-     * open on the panel that is returned.
+     * Creates, but does not open, a Swing JPanel with a JTabbedPane child
+     * component that contains instances of the result viewers
+     * (DataResultViewer) provided by the result viewer extension point (service
+     * providers that implement DataResultViewer). The result view panel will
+     * push single node selections from its child result viewers to the supplied
+     * custom content view.
      *
-     * @param title             The title for the panel.
-     * @param pathText          Descriptive text about the source of the nodes
+     * @param title             The title for the result view panel.
+     * @param description       Descriptive text about the source of the nodes
      *                          displayed.
-     * @param rootNode          The new root node.
-     * @param totalMatches      Cardinality of root node's children
+     * @param currentRootNode   The current root (parent) node for the nodes
+     *                          displayed. May be changed by calling setNode.
+     * @param childNodeCount    The cardinality of the root node's children.
      * @param customContentView A content view to use in place of the default
      *                          content view.
      *
-     * @return A DataResultPanel instance.
+     * @return A result view panel.
      */
-    public static DataResultPanel createInstanceUninitialized(String title, String pathText, Node rootNode, int totalMatches, DataContent customContentView) {
-        DataResultPanel resultPanel = new DataResultPanel(title, customContentView);
-        createInstanceCommon(title, pathText, rootNode, totalMatches, resultPanel);
+    public static DataResultPanel createInstanceUninitialized(String title, String description, Node currentRootNode, int childNodeCount, DataContent customContentView) {
+        DataResultPanel resultPanel = new DataResultPanel(title, false, Collections.emptyList(), customContentView);
+        createInstanceCommon(title, description, currentRootNode, childNodeCount, resultPanel);
         return resultPanel;
     }
 
     /**
-     * Executes code common to all of the DataSreultPanel factory methods.
+     * Executes code common to all of the result view panel factory methods.
      *
-     * @param title           The title for the panel.
-     * @param pathText        Descriptive text about the source of the nodes
+     * @param title           The title for the result view panel.
+     * @param description     Descriptive text about the source of the nodes
      *                        displayed.
-     * @param rootNode        The new root node.
-     * @param totalMatches    Cardinality of root node's children
-     * @param resultViewPanel A content view to use in place of the default
-     *                        content view.
+     * @param currentRootNode The current root (parent) node for the nodes
+     *                        displayed. May be changed by calling setNode.
+     * @param childNodeCount  The cardinality of the root node's children.
+     * @param resultViewPanel A new results view panel.
      */
-    private static void createInstanceCommon(String title, String pathText, Node rootNode, int totalMatches, DataResultPanel resultViewPanel) {
+    private static void createInstanceCommon(String title, String description, Node currentRootNode, int childNodeCount, DataResultPanel resultViewPanel) {
         resultViewPanel.setTitle(title);
         resultViewPanel.setName(title);
-        resultViewPanel.setNumMatches(totalMatches);
-        resultViewPanel.setNode(rootNode);
-        resultViewPanel.setPath(pathText);
+        resultViewPanel.setNumberOfChildNodes(childNodeCount);
+        resultViewPanel.setNode(currentRootNode);
+        resultViewPanel.setPath(description);
     }
 
     /**
-     * Constructs a DataResultPanel with the default DataContent
+     * Constructs a Swing JPanel with a JTabbedPane child component that
+     * contains a collection of result viewers that is either supplied or
+     * provided by the result viewer extension point.
      *
-     * @param title  The title for the panel.
-     * @param isMain True if the DataResultPanel being constructed is the "main"
-     *               DataResultPanel.
+     * @param title             The title of the result view panel.
+     * @param isMain            Whether or not the result view panel is the
+     *                          "main" instance of the panel that resides in the
+     *                          "main" results view (DataResultTopComponent)
+     *                          that is normally docked into the upper right
+     *                          hand side of the main application window.
+     * @param viewers           A collection of result viewers to use instead of
+     *                          the result viewers provided by the results
+     *                          viewer extension point, may be empty.
+     * @param customContentView A custom content view to use instead of the
+     *                          "main" content view that is normally docked into
+     *                          the lower right hand side of the main
+     *                          application window, may be null.
      */
-    DataResultPanel(String title, boolean isMain) {
-        this(isMain, Lookup.getDefault().lookup(DataContent.class));
-        setTitle(title);
-    }
-
-    private DataResultPanel(boolean isMain, DataContent contentView) {
+    DataResultPanel(String title, boolean isMain, Collection<DataResultViewer> viewers, DataContent customContentView) {
+        this.setTitle(title);
         this.isMain = isMain;
-        this.contentView = contentView;
+        if (customContentView == null) {
+            this.contentView = Lookup.getDefault().lookup(DataContent.class);
+        } else {
+            this.contentView = customContentView;
+        }
+        this.resultViewers = new ArrayList<>(viewers);
+        this.explorerManagerListener = new ExplorerManagerListener();
+        this.rootNodeListener = new RootNodeListener();
         initComponents();
     }
 
     /**
-     * Constructs a DataResultPanel with the a custom DataContent.
-     *
-     * @param title             The title for the panel.
-     * @param customContentView A content view to use in place of the default
-     *                          content view.
-     */
-    DataResultPanel(String title, DataContent customContentView) {
-        this(false, customContentView);
-    }
-
-    /**
-     * Gets the preferred identifier for this panel in the window system.
+     * Gets the preferred identifier for this result view panel in the window
+     * system.
      *
      * @return The preferred identifier.
      */
@@ -200,19 +252,7 @@ public String getPreferredID() {
     }
 
     /**
-     * Gets whether or not this panel is the "main" panel used to view the child
-     * nodes of a node selected in the tree view (DirectoryTreeTopComponent)
-     * that is normally docked into the left hand side of the main window.
-     *
-     * @return True or false.
-     */
-    @Override
-    public boolean isMain() {
-        return this.isMain;
-    }
-
-    /**
-     * Sets the title of this panel.
+     * Sets the title of this result view panel.
      *
      * @param title The title.
      */
@@ -223,27 +263,27 @@ public void setTitle(String title) {
 
     /**
      * Sets the descriptive text about the source of the nodes displayed in this
-     * panel.
+     * result view panel.
      *
-     * @param pathText The text to display.
+     * @param description The text to display.
      */
     @Override
-    public void setPath(String pathText) {
-        this.directoryTablePath.setText(pathText);
+    public void setPath(String description) {
+        this.descriptionLabel.setText(description);
     }
 
     /**
-     * Adds a result viewer to this panel.
+     * Adds a results viewer to this result view panel.
      *
-     * @param resultViewer The result viewer.
+     * @param resultViewer The results viewer.
      */
     public void addResultViewer(DataResultViewer resultViewer) {
         resultViewers.add(resultViewer);
-        dataResultTabbedPanel.addTab(resultViewer.getTitle(), resultViewer.getComponent());
+        resultViewerTabs.addTab(resultViewer.getTitle(), resultViewer.getComponent());
     }
 
     /**
-     * Gets the result viewers for this panel.
+     * Gets the result viewers for this result view panel.
      *
      * @return A list of result viewers.
      */
@@ -253,8 +293,8 @@ public List<DataResultViewer> getViewers() {
     }
 
     /**
-     * Sets the content view for this panel. Needs to be called before the first
-     * call to open.
+     * Sets the content view for this result view panel. Needs to be called
+     * before the first call to open.
      *
      * @param customContentView A content view to use in place of the default
      *                          content view.
@@ -264,67 +304,60 @@ public void setContentViewer(DataContent customContentView) {
     }
 
     /**
-     * Initializes this panel. Intended to be called by a parent top component
+     * Opens this result view panel. Should be called by a parent top component
      * when the top component is opened.
      */
     public void open() {
-        if (null == explorerManager) {
-            /*
-             * Get an explorer manager to pass to the child result viewers. If
-             * the application components are put together as expected, this
-             * will be an explorer manager owned by a parent top component, and
-             * placed by the top component in the look up that is proxied as the
-             * action global context when the top component has focus. The
-             * sharing of this explorer manager enables the same child node
-             * selections to be made in all of the result viewers.
-             */
-            explorerManager = ExplorerManager.find(this);
-            emNodeSelectionListener = new ExplorerManagerNodeSelectionListener();
-            explorerManager.addPropertyChangeListener(emNodeSelectionListener);
+        /*
+         * The parent top component is expected to be an explorer manager
+         * provider that exposes a lookup maintained by its explorer manager to
+         * the actions global context. The child result view panel will then
+         * find the parent top component's explorer manager at runtime, so that
+         * it can act as an explorer manager provider for its child result
+         * viewers. This connects the nodes displayed in the result viewers to
+         * the actions global context.
+         */
+        if (this.explorerManager == null) {
+            this.explorerManager = ExplorerManager.find(this);
+            this.explorerManager.addPropertyChangeListener(this.explorerManagerListener);
         }
 
         /*
-         * Load the child result viewers into the tabbed pane.
+         * Load either the supplied result viewers or the result viewers
+         * provided by the result viewer extension point into the tabbed pane.
+         * If loading from the extension point and distinct result viewer
+         * instances MUST be created if this is not the "main" result view.
          */
-        if (0 == dataResultTabbedPanel.getTabCount()) {
-            /*
-             * TODO (JIRA-2658): Fix the DataResultViewer extension point. When
-             * this is done, restore the implementation of DataResultViewerTable
-             * and DataREsultViewerThumbnail as DataResultViewer service
-             * providers.
-             */
-            addResultViewer(new DataResultViewerTable(this.explorerManager));
-            addResultViewer(new DataResultViewerThumbnail(this.explorerManager));
-            for (DataResultViewer factory : Lookup.getDefault().lookupAll(DataResultViewer.class)) {
-                DataResultViewer resultViewer;
-                if (isMain) {
-                    resultViewer = factory;
-                } else {
-                    resultViewer = factory.createInstance();
+        if (this.resultViewerTabs.getTabCount() == 0) {
+            if (this.resultViewers.isEmpty()) {
+                for (DataResultViewer resultViewer : Lookup.getDefault().lookupAll(DataResultViewer.class)) {
+                    if (this.isMain) {
+                        this.resultViewers.add(resultViewer);
+                    } else {
+                        this.resultViewers.add(resultViewer.createInstance());
+                    }
                 }
-                addResultViewer(resultViewer);
             }
-        }
-
-        if (isMain && null == rootNode) {
-            setNode(rootNode);
+            this.resultViewers.forEach((resultViewer) -> resultViewerTabs.addTab(resultViewer.getTitle(), resultViewer.getComponent()));
         }
 
         this.setVisible(true);
     }
 
     /**
-     * Sets the root node for this panel. The child nodes of the root node will
-     * be displayed in the result viewers. For the "main" panel, the root node
-     * is the currently selected node in the tree view docked into the left side
-     * of the main application window.
+     * Sets the current root node for this result view panel. The child nodes of
+     * the current root node will be displayed in the child result viewers. For
+     * the "main" panel, the root node is the currently selected node in the
+     * application tree view docked into the left side of the main application
+     * window.
      *
-     * @param rootNode The root node for this panel.
+     * @param rootNode The root node for this panel, may be null if the panel is
+     *                 to be reset.
      */
     @Override
     public void setNode(Node rootNode) {
-        if (this.rootNode != null) {
-            this.rootNode.removeNodeListener(rootNodeListener);
+        if (this.currentRootNode != null) {
+            this.currentRootNode.removeNodeListener(rootNodeListener);
         }
 
         /*
@@ -333,53 +366,54 @@ public void setNode(Node rootNode) {
          * construction.
          */
         if (listeningToTabbedPane == false) {
-            dataResultTabbedPanel.addChangeListener(this);
+            resultViewerTabs.addChangeListener(this);
             listeningToTabbedPane = true;
         }
 
-        this.rootNode = rootNode;
-        if (this.rootNode != null) {
+        this.currentRootNode = rootNode;
+        if (this.currentRootNode != null) {
             rootNodeListener.reset();
-            this.rootNode.addNodeListener(rootNodeListener);
+            this.currentRootNode.addNodeListener(rootNodeListener);
         }
 
-        resetTabs(this.rootNode);
-        setupTabs(this.rootNode);
+        this.resultViewers.forEach((viewer) -> {
+            viewer.resetComponent();
+        });
+        setupTabs(this.currentRootNode);
 
-        if (null != this.rootNode) {
-            int childrenCount = this.rootNode.getChildren().getNodesCount();
-            this.numberMatchLabel.setText(Integer.toString(childrenCount));
+        if (this.currentRootNode != null) {
+            int childrenCount = this.currentRootNode.getChildren().getNodesCount();
+            this.numberOfChildNodesLabel.setText(Integer.toString(childrenCount));
         }
-        this.numberMatchLabel.setVisible(true);
+        this.numberOfChildNodesLabel.setVisible(true);
     }
 
     /**
-     * Gets the root node of this panel. For the "main" panel, the root node is
-     * the currently selected node in the tree view docked into the left side of
-     * the main application window.
+     * Gets the root node of this result view panel. For the "main" panel, the
+     * root node is the currently selected node in the application tree view
+     * docked into the left side of the main application window.
      *
      * @return The root node.
      */
     public Node getRootNode() {
-        return rootNode;
+        return currentRootNode;
     }
 
     /**
-     * Set number of child nodes displayed for the current root node.
+     * Sets the label text that displays the number of the child nodes displayed
+     * by this result view panel's result viewers.
      *
-     * @param numberOfChildNodes
+     * @param numberOfChildNodes The number of child nodes.
      */
-    public void setNumMatches(Integer numberOfChildNodes) {
-        if (this.numberMatchLabel != null) {
-            this.numberMatchLabel.setText(Integer.toString(numberOfChildNodes));
-        }
+    public void setNumberOfChildNodes(Integer numberOfChildNodes) {
+        this.numberOfChildNodesLabel.setText(Integer.toString(numberOfChildNodes));
     }
 
     /**
-     * Sets the children of the root node that should be currently selected in
-     * this panel's result viewers.
+     * Selects the given child nodes of the root node in this panel's result
+     * viewers.
      *
-     * @param selectedNodes The nodes to be selected.
+     * @param selectedNodes The child nodes to be selected.
      */
     public void setSelectedNodes(Node[] selectedNodes) {
         this.resultViewers.forEach((viewer) -> viewer.setSelectedNodes(selectedNodes));
@@ -396,11 +430,11 @@ private void setupTabs(Node selectedNode) {
          * Enable or disable the result viewer tabs based on whether or not the
          * corresponding results viewer supports display of the selected node.
          */
-        for (int i = 0; i < dataResultTabbedPanel.getTabCount(); i++) {
+        for (int i = 0; i < resultViewerTabs.getTabCount(); i++) {
             if (resultViewers.get(i).isSupported(selectedNode)) {
-                dataResultTabbedPanel.setEnabledAt(i, true);
+                resultViewerTabs.setEnabledAt(i, true);
             } else {
-                dataResultTabbedPanel.setEnabledAt(i, false);
+                resultViewerTabs.setEnabledAt(i, false);
             }
         }
 
@@ -415,17 +449,17 @@ private void setupTabs(Node selectedNode) {
             NodeSelectionInfo selectedChildInfo = ((TableFilterNode) selectedNode).getChildNodeSelectionInfo();
             if (null != selectedChildInfo) {
                 for (int i = 0; i < resultViewers.size(); ++i) {
-                    if (resultViewers.get(i) instanceof DataResultViewerTable && dataResultTabbedPanel.isEnabledAt(i)) {
+                    if (resultViewers.get(i) instanceof DataResultViewerTable && resultViewerTabs.isEnabledAt(i)) {
                         tabToSelect = i;
                     }
                 }
             }
         };
-        if (NO_TAB_SELECTED == tabToSelect) {
-            tabToSelect = dataResultTabbedPanel.getSelectedIndex();
-            if ((NO_TAB_SELECTED == tabToSelect) || (!dataResultTabbedPanel.isEnabledAt(tabToSelect))) {
-                for (int i = 0; i < dataResultTabbedPanel.getTabCount(); ++i) {
-                    if (dataResultTabbedPanel.isEnabledAt(i)) {
+        if (tabToSelect == NO_TAB_SELECTED) {
+            tabToSelect = resultViewerTabs.getSelectedIndex();
+            if ((tabToSelect == NO_TAB_SELECTED) || (!resultViewerTabs.isEnabledAt(tabToSelect))) {
+                for (int i = 0; i < resultViewerTabs.getTabCount(); ++i) {
+                    if (resultViewerTabs.isEnabledAt(i)) {
                         tabToSelect = i;
                         break;
                     }
@@ -434,27 +468,15 @@ private void setupTabs(Node selectedNode) {
         }
 
         /*
-         * If there is a tab to sele3ct, do so, and push the selected node to
-         * the corresponding result viewer.
+         * If there is a tab to select, do so, and push the selected node to the
+         * corresponding result viewer.
          */
-        if (NO_TAB_SELECTED != tabToSelect) {
-            dataResultTabbedPanel.setSelectedIndex(tabToSelect);
+        if (tabToSelect != NO_TAB_SELECTED) {
+            resultViewerTabs.setSelectedIndex(tabToSelect);
             resultViewers.get(tabToSelect).setNode(selectedNode);
         }
     }
 
-    /**
-     * Resets the state of the child result viewers, based on a selected root
-     * node.
-     *
-     * @param unusedSelectedNode The selected node.
-     */
-    public void resetTabs(Node unusedSelectedNode) {
-        this.resultViewers.forEach((viewer) -> {
-            viewer.resetComponent();
-        });
-    }
-
     /**
      * Responds to a tab selection changed event by setting the root node of the
      * corresponding result viewer.
@@ -465,57 +487,34 @@ public void resetTabs(Node unusedSelectedNode) {
     public void stateChanged(ChangeEvent event) {
         JTabbedPane pane = (JTabbedPane) event.getSource();
         int currentTab = pane.getSelectedIndex();
-        if (-1 != currentTab) {
+        if (currentTab != DataResultPanel.NO_TAB_SELECTED) {
             DataResultViewer currentViewer = this.resultViewers.get(currentTab);
             this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
             try {
-                currentViewer.setNode(rootNode);
+                currentViewer.setNode(currentRootNode);
             } finally {
-                this.setCursor(null);
+                this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
             }
         }
     }
 
     /**
-     * Indicates whether or not this panel can be closed at the time of the
-     * call.
-     *
-     * @return True or false.
-     */
-    public boolean canClose() {
-        /*
-         * If this is the "main" panel, only allow it to be closed when no case
-         * is open or no there are no data sources in the current case.
-         */
-        Case openCase;
-        try {
-            openCase = Case.getOpenCase();
-        } catch (NoCurrentCaseException ex) {
-            return true;
-        }
-        return (!this.isMain) || openCase.hasData() == false;
-    }
-
-    /**
-     * Closes down the component. Intended to be called by the parent top
+     * Closes this reult view panel. Intended to be called by the parent top
      * component when it is closed.
      */
     void close() {
-        if (null != explorerManager && null != emNodeSelectionListener) {
-            explorerManager.removePropertyChangeListener(emNodeSelectionListener);
+        if (explorerManager != null && explorerManagerListener != null) {
+            explorerManager.removePropertyChangeListener(explorerManagerListener);
             explorerManager = null;
         }
 
         this.resultViewers.forEach((viewer) -> viewer.setNode(null));
 
-        if (!this.isMain) {
+        if (!this.isMain) { // RJCTODO: What?
             this.resultViewers.forEach(DataResultViewer::clearComponent);
-            this.directoryTablePath.removeAll();
-            this.directoryTablePath = null;
-            this.numberMatchLabel.removeAll();
-            this.numberMatchLabel = null;
+            this.descriptionLabel.removeAll();
+            this.numberOfChildNodesLabel.removeAll();
             this.matchLabel.removeAll();
-            this.matchLabel = null;
             this.setLayout(null);
             this.removeAll();
             this.setVisible(false);
@@ -525,50 +524,37 @@ void close() {
     @Override
     public ExplorerManager getExplorerManager() {
         return explorerManager;
+
     }
 
     /**
-     * Responds to node selection change events from the explorer manager.
+     * Responds to node selection change events from the explorer manager of
+     * this panel's parent top component. The selected nodes are passed to the
+     * content view. This is how the results view and the content view are kept
+     * in sync. It is therefore required that all of the result viewers in this
+     * panel use the explorer manager of the parent top component. This supports
+     * this way of passing the selection to the content view, plus the exposure
+     * of the selection to through the actions global context, which is needed
+     * for multiple selection.
      */
-    private class ExplorerManagerNodeSelectionListener implements PropertyChangeListener {
+    private class ExplorerManagerListener implements PropertyChangeListener {
 
         @Override
         public void propertyChange(PropertyChangeEvent evt) {
-            try {
-                Case.getOpenCase();
-            } catch (NoCurrentCaseException ex) {
-                return;
-            }
-
-            /*
-             * Only interested in node selection events.
-             */
-            if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
-                setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
-                try {
-                    if (contentView != null) {
-                        Node[] selectedNodes = explorerManager.getSelectedNodes();
-
-                        /*
-                         * Pass the selected nodes to all of the result viewers
-                         * sharing this explorer manager.
-                         */
-                        resultViewers.forEach((viewer) -> viewer.setSelectedNodes(selectedNodes));
-
-                        /*
-                         * Passing null signals that either multiple nodes are
-                         * selected, or no nodes are selected. This is important
-                         * to the content view, since content views only work
-                         * for a single node..
-                         */
-                        if (1 == selectedNodes.length) {
-                            contentView.setNode(selectedNodes[0]);
-                        } else {
-                            contentView.setNode(null);
-                        }
-                    }
-                } finally {
-                    setCursor(null);
+            if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES) && contentView != null) {
+                /*
+                 * Pass a single node selection in a result viewer to the
+                 * content view. Note that passing null to the content view
+                 * signals that either multiple nodes are selected, or a
+                 * previous selection has been cleared. This is important to the
+                 * content view, since its child content viewers only work for a
+                 * single node.
+                 */
+                Node[] selectedNodes = explorerManager.getSelectedNodes();
+                if (1 == selectedNodes.length) {
+                    contentView.setNode(selectedNodes[0]);
+                } else {
+                    contentView.setNode(null);
                 }
             }
         }
@@ -578,6 +564,7 @@ public void propertyChange(PropertyChangeEvent evt) {
      * Responds to changes in the root node due to asynchronous child node
      * creation.
      */
+    // RJCTODO: Why do we need this?
     private class RootNodeListener implements NodeListener {
 
         private volatile boolean waitingForData = true;
@@ -623,8 +610,8 @@ private boolean containsReal(Node[] delta) {
          *
          */
         private void updateMatches() {
-            if (rootNode != null && rootNode.getChildren() != null) {
-                setNumMatches(rootNode.getChildren().getNodesCount());
+            if (currentRootNode != null && currentRootNode.getChildren() != null) {
+                setNumMatches(currentRootNode.getChildren().getNodesCount());
             }
         }
 
@@ -655,52 +642,93 @@ public void propertyChange(PropertyChangeEvent evt) {
     // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
     private void initComponents() {
 
-        directoryTablePath = new javax.swing.JLabel();
-        numberMatchLabel = new javax.swing.JLabel();
+        descriptionLabel = new javax.swing.JLabel();
+        numberOfChildNodesLabel = new javax.swing.JLabel();
         matchLabel = new javax.swing.JLabel();
-        dataResultTabbedPanel = new javax.swing.JTabbedPane();
+        resultViewerTabs = new javax.swing.JTabbedPane();
 
         setMinimumSize(new java.awt.Dimension(0, 5));
         setPreferredSize(new java.awt.Dimension(5, 5));
 
-        org.openide.awt.Mnemonics.setLocalizedText(directoryTablePath, org.openide.util.NbBundle.getMessage(DataResultPanel.class, "DataResultPanel.directoryTablePath.text")); // NOI18N
-        directoryTablePath.setMinimumSize(new java.awt.Dimension(5, 14));
+        org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, org.openide.util.NbBundle.getMessage(DataResultPanel.class, "DataResultPanel.descriptionLabel.text")); // NOI18N
+        descriptionLabel.setMinimumSize(new java.awt.Dimension(5, 14));
 
-        org.openide.awt.Mnemonics.setLocalizedText(numberMatchLabel, org.openide.util.NbBundle.getMessage(DataResultPanel.class, "DataResultPanel.numberMatchLabel.text")); // NOI18N
+        org.openide.awt.Mnemonics.setLocalizedText(numberOfChildNodesLabel, org.openide.util.NbBundle.getMessage(DataResultPanel.class, "DataResultPanel.numberOfChildNodesLabel.text")); // NOI18N
 
         org.openide.awt.Mnemonics.setLocalizedText(matchLabel, org.openide.util.NbBundle.getMessage(DataResultPanel.class, "DataResultPanel.matchLabel.text")); // NOI18N
 
-        dataResultTabbedPanel.setMinimumSize(new java.awt.Dimension(0, 5));
+        resultViewerTabs.setMinimumSize(new java.awt.Dimension(0, 5));
 
         javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
         this.setLayout(layout);
         layout.setHorizontalGroup(
             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
             .addGroup(layout.createSequentialGroup()
-                .addComponent(directoryTablePath, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addComponent(descriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                .addComponent(numberMatchLabel)
+                .addComponent(numberOfChildNodesLabel)
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                 .addComponent(matchLabel))
-            .addComponent(dataResultTabbedPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+            .addComponent(resultViewerTabs, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
         );
         layout.setVerticalGroup(
             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
             .addGroup(layout.createSequentialGroup()
                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                     .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
-                        .addComponent(numberMatchLabel)
+                        .addComponent(numberOfChildNodesLabel)
                         .addComponent(matchLabel))
-                    .addComponent(directoryTablePath, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                    .addComponent(descriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                 .addGap(0, 0, 0)
-                .addComponent(dataResultTabbedPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                .addComponent(resultViewerTabs, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
         );
     }// </editor-fold>//GEN-END:initComponents
     // Variables declaration - do not modify//GEN-BEGIN:variables
-    private javax.swing.JTabbedPane dataResultTabbedPanel;
-    private javax.swing.JLabel directoryTablePath;
+    private javax.swing.JLabel descriptionLabel;
     private javax.swing.JLabel matchLabel;
-    private javax.swing.JLabel numberMatchLabel;
+    private javax.swing.JLabel numberOfChildNodesLabel;
+    private javax.swing.JTabbedPane resultViewerTabs;
     // End of variables declaration//GEN-END:variables
 
+    /**
+     * Gets whether or not this result view panel is the "main" result view
+     * panel used to view the child nodes of a node selected in the application
+     * tree view (DirectoryTreeTopComponent) that is normally docked into the
+     * left hand side of the main window.
+     *
+     * @return True or false.
+     *
+     * @Deprecated This method has no valid use case.
+     */
+    @Deprecated
+    @Override
+    public boolean isMain() {
+        return this.isMain;
+    }
+
+    /**
+     * Sets the label text that displays the number of the child nodes displayed
+     * by this result view panel's result viewers.
+     *
+     * @param numberOfChildNodes The number of child nodes.
+     *
+     * @deprecated Use setNumberOfChildNodes instead.
+     */
+    @Deprecated
+    public void setNumMatches(Integer numberOfChildNodes) {
+        this.setNumberOfChildNodes(numberOfChildNodes);
+    }
+
+    /**
+     * Resets the state of this results panel.
+     *
+     * @param unusedSelectedNode Unused.
+     *
+     * @deprecated Use setNode(null) instead.
+     */
+    @Deprecated
+    public void resetTabs(Node unusedSelectedNode) {
+        this.setNode(null);
+    }
+
 }
diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.form
index cb4669a51e93ba4b574830eb716116a84faf9a64..755df0fcf09565c51455bf4840c35c34773d3771 100644
--- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.form
+++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.form
@@ -28,10 +28,10 @@
   <SubComponents>
     <Component class="org.sleuthkit.autopsy.corecomponents.DataResultPanel" name="dataResultPanelLocal">
       <AuxValues>
-        <AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="dataResultPanel;"/>
+        <AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="resultViewersPanel;"/>
         <AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
         <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
       </AuxValues>
     </Component>
   </SubComponents>
-</Form>
+</Form>
\ No newline at end of file
diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java
index 4a5d265a2c5a0ffb6661a9dba5af512a399250d0..797a8d526274247d59c65fd0b5a0f3df2704b45d 100644
--- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java
+++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java
@@ -19,6 +19,7 @@
 package org.sleuthkit.autopsy.corecomponents;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.logging.Level;
@@ -39,161 +40,220 @@
 import org.sleuthkit.autopsy.coreutils.Logger;
 
 /**
- * Top component which displays results (top-right editor mode by default).
+ * A DataResultTopComponent object is a NetBeans top component that provides
+ * multiple views of the application data represented by a NetBeans Node. It is
+ * a result view component (implements DataResult) that contains a result view
+ * panel (DataResultPanel), which is also a result view component. The result
+ * view panel is a JPanel with a JTabbedPane child component that contains a
+ * collection of result viewers. Each result viewer (implements
+ * DataResultViewer) presents a different view of the current node. Result
+ * viewers are usually JPanels that display the child nodes of the current node
+ * using a NetBeans explorer view child component. The result viewers are either
+ * supplied during construction of the result view top component or provided by
+ * the result viewer extension point (service providers that implement
+ * DataResultViewer).
  *
- * There is a main tc instance that responds to directory tree selections.
- * Others can also create an additional result viewer tc using one of the
- * factory methods, that can be:
+ * Result view top components are typically docked into the upper right hand
+ * side of the main application window (editor mode), and are linked to the
+ * content view in the lower right hand side of the main application window
+ * (output mode) by the result view panel. The panel passes single node
+ * selections in the active result viewer to the content view.
  *
- * - added to top-right corner as an additional, closeable viewer - added to a
- * different, custom mode, - linked to a custom content viewer that responds to
- * selections from this top component.
+ * The "main" result view top component receives its current node as a selection
+ * from the case tree view in the top component (DirectoryTreeYopComponent)
+ * docked into the left hand side of the main application window.
  *
- * For embedding custom data result in other top components window, use
- * DataResultPanel component instead, since we cannot nest top components.
- *
- * Encapsulates the internal DataResultPanel and delegates to it.
- *
- * Implements DataResult interface by delegating to the encapsulated
- * DataResultPanel.
+ * Result view top components are explorer manager providers to connect the
+ * lookups of the nodes displayed in the NetBeans explorer views of the result
+ * viewers to the actions global context.
  */
 @RetainLocation("editor")
 public class DataResultTopComponent extends TopComponent implements DataResult, ExplorerManager.Provider {
 
     private static final Logger logger = Logger.getLogger(DataResultTopComponent.class.getName());
-    private final ExplorerManager explorerManager = new ExplorerManager();
-    private final DataResultPanel dataResultPanel; //embedded component with all the logic
-    private boolean isMain;
-    private String customModeName;
-
-    //keep track of tcs opened for menu presenters
     private static final List<String> activeComponentIds = Collections.synchronizedList(new ArrayList<String>());
+    private final boolean isMain;
+    private final String customModeName;
+    private final ExplorerManager explorerManager;
+    private final DataResultPanel dataResultPanel;
 
     /**
-     * Create a new data result top component
+     * Creates a result view top component that provides multiple views of the
+     * application data represented by a NetBeans Node. The result view will be
+     * docked into the upper right hand side of the main application window
+     * (editor mode) and will be linked to the content view in the lower right
+     * hand side of the main application window (output mode). Its result
+     * viewers are provided by the result viewer extension point (service
+     * providers that implement DataResultViewer).
      *
-     * @param isMain whether it is the main, application default result viewer,
-     *               there can be only 1 main result viewer
-     * @param title  title of the data result window
+     * @param title          The title for the top component, appears on the top
+     *                       component's tab.
+     * @param description    Descriptive text about the node displayed, appears
+     *                       on the top component's tab
+     * @param node           The node to display.
+     * @param childNodeCount The cardinality of the node's children.
+     *
+     * @return The result view top component.
      */
-    public DataResultTopComponent(boolean isMain, String title) {
-        associateLookup(ExplorerUtils.createLookup(explorerManager, getActionMap()));
-        this.dataResultPanel = new DataResultPanel(title, isMain);
-        initComponents();
-        customizeComponent(isMain, title);
+    public static DataResultTopComponent createInstance(String title, String description, Node node, int childNodeCount) {
+        DataResultTopComponent resultViewTopComponent = new DataResultTopComponent(false, title, null, Collections.emptyList(), null);
+        initInstance(description, node, childNodeCount, resultViewTopComponent);
+        return resultViewTopComponent;
     }
 
     /**
-     * Create a new, custom data result top component, in addition to the
-     * application main one
+     * Creates a result view top component that provides multiple views of the
+     * application data represented by a NetBeans Node. The result view will be
+     * docked into the upper right hand side of the main application window
+     * (editor mode) and will be linked to the content view in the lower right
+     * hand side of the main application window (output mode).
      *
-     * @param name                unique name of the data result window, also
-     *                            used as title
-     * @param mode                custom mode to dock into
-     * @param customContentViewer custom content viewer to send selection events
-     *                            to
+     * @param title          The title for the top component, appears on the top
+     *                       component's tab.
+     * @param description    Descriptive text about the node displayed, appears
+     *                       on the top component's tab
+     * @param node           The node to display.
+     * @param childNodeCount The cardinality of the node's children.
+     * @param viewers        A collection of result viewers to use instead of
+     *                       the result viewers provided by the results viewer
+     *                       extension point.
+     *
+     * @return The result view top component.
      */
-    DataResultTopComponent(String name, String mode, DataContentTopComponent customContentViewer) {
-        associateLookup(ExplorerUtils.createLookup(explorerManager, getActionMap()));
-        this.customModeName = mode;
-        dataResultPanel = new DataResultPanel(name, customContentViewer);
-        initComponents();
-        customizeComponent(isMain, name);
+    public static DataResultTopComponent createInstance(String title, String description, Node node, int childNodeCount, Collection<DataResultViewer> viewers) {
+        DataResultTopComponent resultViewTopComponent = new DataResultTopComponent(false, title, null, viewers, null);
+        initInstance(description, node, childNodeCount, resultViewTopComponent);
+        return resultViewTopComponent;
     }
 
-    private void customizeComponent(boolean isMain, String title) {
-        this.isMain = isMain;
-        this.customModeName = null;
-
-        setToolTipText(NbBundle.getMessage(DataResultTopComponent.class, "HINT_NodeTableTopComponent"));
-
-        setTitle(title); // set the title
-        setName(title);
-        getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(AddBookmarkTagAction.BOOKMARK_SHORTCUT, "addBookmarkTag"); //NON-NLS
-        getActionMap().put("addBookmarkTag", new AddBookmarkTagAction()); //NON-NLS
-
-        putClientProperty(TopComponent.PROP_CLOSING_DISABLED, isMain); // set option to close compoment in GUI
-        putClientProperty(TopComponent.PROP_MAXIMIZATION_DISABLED, true);
-        putClientProperty(TopComponent.PROP_DRAGGING_DISABLED, true);
-
-        activeComponentIds.add(title);
+    /**
+     * Creates a partially initialized result view top component that provides
+     * multiple views of the application data represented by a NetBeans Node.
+     * The result view will be docked into the upper right hand side of the main
+     * application window (editor mode) and will be linked to the content view
+     * in the lower right hand side of the main application window (output
+     * mode). Its result viewers are provided by the result viewer extension
+     * point (service providers that implement DataResultViewer).
+     *
+     * IMPORTANT: Initialization MUST be completed by calling initInstance.
+     *
+     * @param title The title for the result view top component, appears on the
+     *              top component's tab.
+     *
+     * @return The partially initialized result view top component.
+     */
+    public static DataResultTopComponent createInstance(String title) {
+        DataResultTopComponent resultViewTopComponent = new DataResultTopComponent(false, title, null, Collections.emptyList(), null);
+        return resultViewTopComponent;
     }
 
     /**
-     * Initialize previously created tc instance with additional data
+     * Initializes a partially initialized result view top component.
      *
-     * @param pathText
-     * @param givenNode
-     * @param totalMatches
-     * @param newDataResult previously created with createInstance()
-     *                      uninitialized instance
+     * @param description            Descriptive text about the node displayed,
+     *                               appears on the top component's tab
+     * @param node                   The node to display.
+     * @param childNodeCount         The cardinality of the node's children.
+     * @param resultViewTopComponent The partially initialized result view top
+     *                               component.
      */
-    public static void initInstance(String pathText, Node givenNode, int totalMatches, DataResultTopComponent newDataResult) {
-        newDataResult.setNumMatches(totalMatches);
-
-        newDataResult.open(); // open it first so the component can be initialized
-
-        // set the tree table view
-        newDataResult.setNode(givenNode);
-        newDataResult.setPath(pathText);
-
-        newDataResult.requestActive();
+    public static void initInstance(String description, Node node, int childNodeCount, DataResultTopComponent resultViewTopComponent) {
+        resultViewTopComponent.setNumberOfChildNodes(childNodeCount);
+        resultViewTopComponent.open();
+        resultViewTopComponent.setNode(node);
+        resultViewTopComponent.setPath(description);
+        resultViewTopComponent.requestActive();
     }
 
     /**
-     * Creates a new non-default DataResult component and initializes it
+     * Creates a result view top component that provides multiple views of the
+     * application data represented by a NetBeans Node. The result view will be
+     * docked into a custom mode and linked to the supplied content view. Its
+     * result viewers are provided by the result viewer extension point (service
+     * providers that implement DataResultViewer).
      *
-     * @param title        Title of the component window
-     * @param pathText     Descriptive text about the source of the nodes
-     *                     displayed
-     * @param givenNode    The new root node
-     * @param totalMatches Cardinality of root node's children
+     * @param title                   The title for the top component, appears
+     *                                on the top component's tab.
+     * @param mode                    The NetBeans Window system mode into which
+     *                                this top component should be docked.
+     * @param description             Descriptive text about the node displayed,
+     *                                appears on the top component's tab
+     * @param node                    The node to display.
+     * @param childNodeCount          The cardinality of the node's children.
+     * @param contentViewTopComponent A content view to which this result view
+     *                                will be linked.
      *
-     * @return a new, not default, initialized DataResultTopComponent instance
+     * @return The result view top component.
      */
-    public static DataResultTopComponent createInstance(String title, String pathText, Node givenNode, int totalMatches) {
-        DataResultTopComponent newDataResult = new DataResultTopComponent(false, title);
-
-        initInstance(pathText, givenNode, totalMatches, newDataResult);
-
+    public static DataResultTopComponent createInstance(String title, String mode, String description, Node node, int childNodeCount, DataContentTopComponent contentViewTopComponent) {
+        DataResultTopComponent newDataResult = new DataResultTopComponent(false, title, mode, Collections.emptyList(), contentViewTopComponent);
+        initInstance(description, node, childNodeCount, newDataResult);
         return newDataResult;
     }
 
     /**
-     * Creates a new non-default DataResult component linked with a custom data
-     * content, and initializes it.
+     * Creates a result view top component that provides multiple views of the
+     * application data represented by a NetBeans Node. The result view will be
+     * the "main" result view and will docked into the upper right hand side of
+     * the main application window (editor mode) and will be linked to the
+     * content view in the lower right hand side of the main application window
+     * (output mode). Its result viewers are provided by the result viewer
+     * extension point (service providers that implement DataResultViewer).
      *
+     * IMPORTANT: The "main" result view top component receives its current node
+     * as a selection from the case tree view in the top component
+     * (DirectoryTreeTopComponent) docked into the left hand side of the main
+     * application window. This constructor is RESERVED for the use of the
+     * DirectoryTreeTopComponent singleton only. DO NOT USE OTHERWISE.
      *
-     * @param title             Title of the component window
-     * @param mode              custom mode to dock this custom TopComponent to
-     * @param pathText          Descriptive text about the source of the nodes
-     *                          displayed
-     * @param givenNode         The new root node
-     * @param totalMatches      Cardinality of root node's children
-     * @param dataContentWindow a handle to data content top component window to
-     *
-     * @return a new, not default, initialized DataResultTopComponent instance
+     * @param title The title for the top component, appears on the top
+     *              component's tab.
      */
-    public static DataResultTopComponent createInstance(String title, final String mode, String pathText, Node givenNode, int totalMatches, DataContentTopComponent dataContentWindow) {
-        DataResultTopComponent newDataResult = new DataResultTopComponent(title, mode, dataContentWindow);
-
-        initInstance(pathText, givenNode, totalMatches, newDataResult);
-        return newDataResult;
+    public DataResultTopComponent(String title) {
+        this(true, title, null, Collections.emptyList(), null);
     }
 
     /**
-     * Creates a new non-default DataResult component. You probably want to use
-     * initInstance after it
-     *
-     * @param title
+     * Constructs a result view top component that provides multiple views of
+     * the application data represented by a NetBeans Node.
      *
-     * @return a new, not default, not fully initialized DataResultTopComponent
-     *         instance
+     * @param isMain                  Whether or not this is the "main" result
+     *                                view top component.
+     * @param title                   The title for the top component, appears
+     *                                on the top component's tab.
+     * @param mode                    The NetBeans Window system mode into which
+     *                                this top component should be docked. If
+     *                                null, the editor mode will be used by
+     *                                default.
+     * @param viewers                 A collection of result viewers. If empty,
+     *                                the result viewers provided by the results
+     *                                viewer extension point will be used.
+     * @param contentViewTopComponent A content view to which this result view
+     *                                will be linked. If null, this result view
+     *                                will be linked to the content view docked
+     *                                into the lower right hand side of the main
+     *                                application window,
      */
-    public static DataResultTopComponent createInstance(String title) {
-        final DataResultTopComponent newDataResult = new DataResultTopComponent(false, title);
+    private DataResultTopComponent(boolean isMain, String title, String mode, Collection<DataResultViewer> viewers, DataContentTopComponent contentViewTopComponent) {
+        this.isMain = isMain;
+        this.explorerManager = new ExplorerManager();
+        associateLookup(ExplorerUtils.createLookup(explorerManager, getActionMap()));
+        this.customModeName = mode;
+        this.dataResultPanel = new DataResultPanel(title, isMain, viewers, contentViewTopComponent);
+        initComponents();
+        customizeComponent(title);
+    }
 
-        return newDataResult;
+    private void customizeComponent(String title) {
+        setToolTipText(NbBundle.getMessage(DataResultTopComponent.class, "HINT_NodeTableTopComponent"));  //NON-NLS
+        setTitle(title);
+        setName(title);
+        getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(AddBookmarkTagAction.BOOKMARK_SHORTCUT, "addBookmarkTag"); //NON-NLS
+        getActionMap().put("addBookmarkTag", new AddBookmarkTagAction()); //NON-NLS
+        putClientProperty(TopComponent.PROP_CLOSING_DISABLED, isMain);
+        putClientProperty(TopComponent.PROP_MAXIMIZATION_DISABLED, true);
+        putClientProperty(TopComponent.PROP_DRAGGING_DISABLED, true);
+        activeComponentIds.add(title);
     }
 
     @Override
@@ -202,38 +262,15 @@ public ExplorerManager getExplorerManager() {
     }
 
     /**
-     * Get a list with names of active windows ids, e.g. for the menus
+     * Get a listing of the preferred identifiers of all the result view top
+     * components that have been created.
      *
-     * @return
+     * @return The listing.
      */
     public static List<String> getActiveComponentIds() {
         return new ArrayList<>(activeComponentIds);
     }
 
-    /**
-     * This method is called from within the constructor to initialize the form.
-     * WARNING: Do NOT modify this code. The content of this method is always
-     * regenerated by the Form Editor.
-     */
-    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
-    private void initComponents() {
-
-        org.sleuthkit.autopsy.corecomponents.DataResultPanel dataResultPanelLocal = dataResultPanel;
-
-        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
-        this.setLayout(layout);
-        layout.setHorizontalGroup(
-            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-            .addComponent(dataResultPanelLocal, javax.swing.GroupLayout.DEFAULT_SIZE, 967, Short.MAX_VALUE)
-        );
-        layout.setVerticalGroup(
-            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-            .addComponent(dataResultPanelLocal, javax.swing.GroupLayout.DEFAULT_SIZE, 579, Short.MAX_VALUE)
-        );
-    }// </editor-fold>//GEN-END:initComponents
-    // Variables declaration - do not modify//GEN-BEGIN:variables
-    // End of variables declaration//GEN-END:variables
-
     @Override
     public int getPersistenceType() {
         if (customModeName == null) {
@@ -245,16 +282,6 @@ public int getPersistenceType() {
 
     @Override
     public void open() {
-        setCustomMode();
-        super.open(); //To change body of generated methods, choose Tools | Templates.
-    }
-
-    @Override
-    public List<DataResultViewer> getViewers() {
-        return dataResultPanel.getViewers();
-    }
-
-    private void setCustomMode() {
         if (customModeName != null) {
             Mode mode = WindowManager.getDefault().findMode(customModeName);
             if (mode != null) {
@@ -264,6 +291,12 @@ private void setCustomMode() {
                 logger.log(Level.WARNING, "Could not find mode: {0}, will dock into the default one", customModeName);//NON-NLS
             }
         }
+        super.open();
+    }
+
+    @Override
+    public List<DataResultViewer> getViewers() {
+        return dataResultPanel.getViewers();
     }
 
     @Override
@@ -290,7 +323,7 @@ public void componentActivated() {
         } else {
             selectedNode = null;
         }
-        
+
         /*
          * If the selected node of the content viewer is different than that of
          * the result viewer, the content viewer needs to be updated. Otherwise,
@@ -343,31 +376,15 @@ public boolean isMain() {
 
     @Override
     public boolean canClose() {
-        /*
-         * If this is the results top component in the upper right of the main
-         * window, only allow it to be closed when there's no case opened or no
-         * data sources in the open case.
-         */
         Case openCase;
         try {
             openCase = Case.getOpenCase();
-        } catch (NoCurrentCaseException ex) {
+        } catch (NoCurrentCaseException unused) {
             return true;
         }
         return (!this.isMain) || openCase.hasData() == false;
     }
 
-    /**
-     * Resets the tabs based on the selected Node. If the selected node is null
-     * or not supported, disable that tab as well.
-     *
-     * @param selectedNode the selected content Node
-     */
-    public void resetTabs(Node selectedNode) {
-
-        dataResultPanel.resetTabs(selectedNode);
-    }
-
     public void setSelectedNodes(Node[] selected) {
         dataResultPanel.setSelectedNodes(selected);
     }
@@ -376,7 +393,74 @@ public Node getRootNode() {
         return dataResultPanel.getRootNode();
     }
 
-    void setNumMatches(int matches) {
-        this.dataResultPanel.setNumMatches(matches);
+    /**
+     * Sets the cardinality of the current node's children
+     *
+     * @param childNodeCount The cardinality of the node's children.
+     */
+    private void setNumberOfChildNodes(int childNodeCount) {
+        this.dataResultPanel.setNumberOfChildNodes(childNodeCount);
+    }
+
+    /**
+     * This method is called from within the constructor to initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is always
+     * regenerated by the Form Editor.
+     */
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        org.sleuthkit.autopsy.corecomponents.DataResultPanel dataResultPanelLocal = dataResultPanel;
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+        this.setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(dataResultPanelLocal, javax.swing.GroupLayout.DEFAULT_SIZE, 967, Short.MAX_VALUE)
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(dataResultPanelLocal, javax.swing.GroupLayout.DEFAULT_SIZE, 579, Short.MAX_VALUE)
+        );
+    }// </editor-fold>//GEN-END:initComponents
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    // End of variables declaration//GEN-END:variables
+
+    /**
+     * Creates a partially initialized result view top component that provides
+     * multiple views of the application data represented by a NetBeans Node.
+     * The result view will be docked into the upper right hand side of the main
+     * application window (editor mode) and will be linked to the content view
+     * in the lower right hand side of the main application window (output
+     * mode). Its result viewers are provided by the result viewer extension
+     * point (service providers that implement DataResultViewer).
+     *
+     * IMPORTANT: Initialization MUST be completed by calling initInstance.
+     *
+     * @param isMain Ignored.
+     * @param title  The title for the top component, appears on the top
+     *               component's tab.
+     *
+     * @deprecated Use an appropriate overload of createIntance instead.
+     */
+    @Deprecated
+    public DataResultTopComponent(boolean isMain, String title) {
+        this(false, title, null, Collections.emptyList(), null);
+    }
+
+    /**
+     * Sets the node for which this result view component should provide
+     * multiple views of the underlying application data.
+     *
+     * @param node The node, may be null. If null, the call to this method is
+     *             equivalent to a call to resetComponent on this result view
+     *             component's result viewers.
+     *
+     * @deprecated Use setNode instead.
+     */
+    @Deprecated
+    public void resetTabs(Node node) {
+        dataResultPanel.setNode(node);
     }
+
 }
diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java
index fe21a4ca55999a1c1c0a41874a60ce9e9a631a99..ca0185ce292a9f0109daa0af3326ae6c14878d78 100644
--- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java
+++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java
@@ -1,7 +1,7 @@
 /*
  * Autopsy Forensic Browser
  *
- * Copyright 2011-2017 Basis Technology Corp.
+ * Copyright 2012-2018 Basis Technology Corp.
  * Contact: carrier <at> sleuthkit <dot> org
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -60,151 +60,150 @@
 import org.openide.nodes.Node.Property;
 import org.openide.util.NbBundle;
 import org.openide.util.NbPreferences;
+import org.openide.util.lookup.ServiceProvider;
 import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
 import org.sleuthkit.autopsy.coreutils.Logger;
 import org.sleuthkit.autopsy.coreutils.ThreadConfined;
 import org.sleuthkit.autopsy.datamodel.NodeSelectionInfo;
 
 /**
- * A tabular viewer for the results view.
+ * A tabular result viewer that displays the children of the given root node
+ * using an OutlineView.
  *
- * TODO (JIRA-2658): Fix DataResultViewer extension point. When this is done,
- * restore implementation of DataResultViewerTable as a DataResultViewer service
- * provider.
+ * Instances of this class should use the explorer manager of an ancestor top
+ * component to connect the lookups of the nodes displayed in the OutlineView to
+ * the actions global context. The explorer manager can be supplied during
+ * construction, but the typical use case is for the result viewer to find the
+ * ancestor top component's explorer manager at runtime.
  */
-//@ServiceProvider(service = DataResultViewer.class)
-public class DataResultViewerTable extends AbstractDataResultViewer {
+@ServiceProvider(service = DataResultViewer.class)
+public final class DataResultViewerTable extends AbstractDataResultViewer {
 
     private static final long serialVersionUID = 1L;
-    private static final Logger logger = Logger.getLogger(DataResultViewerTable.class.getName());
     @NbBundle.Messages("DataResultViewerTable.firstColLbl=Name")
     static private final String FIRST_COLUMN_LABEL = Bundle.DataResultViewerTable_firstColLbl();
-    private static final Color TAGGED_COLOR = new Color(255, 255, 195);
-
+    static private final Color TAGGED_ROW_COLOR = new Color(255, 255, 195);
+    private static final Logger logger = Logger.getLogger(DataResultViewerTable.class.getName());
     private final String title;
+    private final Map<String, ETableColumn> columnMap;
+    private final Map<Integer, Property<?>> propertiesMap;
+    private final Outline outline;
+    private final TableListener outlineViewListener;
+    private Node rootNode;
 
     /**
-     * The properties map:
-     *
-     * stored value of column index -> property at that index
-     *
-     * We move around stored values instead of directly using the column indices
-     * in order to not override settings for a column that may not appear in the
-     * current table view due to its collection of its children's properties.
-     */
-    private final Map<Integer, Property<?>> propertiesMap = new TreeMap<>();
-
-    /**
-     * Stores references to the actual table column objects, keyed by column
-     * name, so that we can check there visibility later in
-     * storeColumnVisibility().
+     * Constructs a tabular result viewer that displays the children of the
+     * given root node using an OutlineView. The viewer should have an ancestor
+     * top component to connect the lookups of the nodes displayed in the
+     * OutlineView to the actions global context. The explorer manager will be
+     * discovered at runtime.
      */
-    private final Map<String, ETableColumn> columnMap = new HashMap<>();
-
-    private Node currentRoot;
-
-    /*
-     * Convience reference to internal Outline.
-     */
-    private Outline outline;
-
-    /**
-     * Listener for table model event and mouse clicks.
-     */
-    private final  TableListener tableListener;
+    public DataResultViewerTable() {
+        this(null, Bundle.DataResultViewerTable_title());
+    }
 
     /**
-     * Creates a DataResultViewerTable object that is compatible with node
-     * multiple selection actions, and the default title.
+     * Constructs a tabular result viewer that displays the children of a given
+     * root node using an OutlineView. The viewer should have an ancestor top
+     * component to connect the lookups of the nodes displayed in the
+     * OutlineView to the actions global context.
      *
-     * @param explorerManager allow for explorer manager sharing
+     * @param explorerManager The explorer manager of the ancestor top
+     *                        component.
      */
     public DataResultViewerTable(ExplorerManager explorerManager) {
         this(explorerManager, Bundle.DataResultViewerTable_title());
     }
 
     /**
-     * Creates a DataResultViewerTable object that is compatible with node
-     * multiple selection actions, and a custom title.
+     * Constructs a tabular result viewer that displays the children of a given
+     * root node using an OutlineView with a given title. The viewer should have
+     * an ancestor top component to connect the lookups of the nodes displayed
+     * in the OutlineView to the actions global context.
      *
-     * @param explorerManager allow for explorer manager sharing
-     * @param title           The custom title.
+     * @param explorerManager The explorer manager of the ancestor top
+     *                        component.
+     * @param title           The title.
      */
     public DataResultViewerTable(ExplorerManager explorerManager, String title) {
         super(explorerManager);
         this.title = title;
-        
+        this.columnMap = new HashMap<>();
+        this.propertiesMap = new TreeMap<>();
+
+        /*
+         * Execute the code generated by the GUI builder.
+         */
         initComponents();
-        
+
+        /*
+         * Configure the child OutlineView (explorer view) component.
+         */
         outlineView.setAllowedDragActions(DnDConstants.ACTION_NONE);
         outline = outlineView.getOutline();
         outline.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
-        outline.setRootVisible(false);    // don't show the root node
+        outline.setRootVisible(false);
         outline.setDragEnabled(false);
         outline.setDefaultRenderer(Object.class, new ColorTagCustomRenderer());
-        // add a listener so that when columns are moved, the new order is stored
-        tableListener = new TableListener();
-        outline.getColumnModel().addColumnModelListener(tableListener);
-        // the listener also moves columns back if user tries to move the first column out of place
-        outline.getTableHeader().addMouseListener(tableListener);
+
+        /*
+         * Add a table listener to the child OutlineView (explorer view) to
+         * persist the order of the table columns when a column is moved.
+         */
+        outlineViewListener = new TableListener();
+        outline.getColumnModel().addColumnModelListener(outlineViewListener);
+
+        /*
+         * Add a mouse listener to the child OutlineView (explorer view) to make
+         * sure the first column of the table is kept in place.
+         */
+        outline.getTableHeader().addMouseListener(outlineViewListener);
     }
 
     /**
-     * Creates a DataResultViewerTable object that is NOT compatible with node
-     * multiple selection actions.
+     * Creates a new instance of a tabular result viewer that displays the
+     * children of a given root node using an OutlineView. This method exists to
+     * make it possible to use the default service provider instance of this
+     * class in the "main" results view of the application, while using distinct
+     * instances in other places in the UI.
+     *
+     * @return A new instance of a tabular result viewer,
      */
-    public DataResultViewerTable() {
-        this(new ExplorerManager(),Bundle.DataResultViewerTable_title());
+    @Override
+    public DataResultViewer createInstance() {
+        return new DataResultViewerTable();
     }
 
-
     /**
-     * Expand node
-     *
-     * @param n Node to expand
+     * Gets the title of this tabular result viewer.
      */
     @Override
-    public void expandNode(Node n) {
-        super.expandNode(n);
-
-        outlineView.expandNode(n);
+    @NbBundle.Messages("DataResultViewerTable.title=Table")
+    public String getTitle() {
+        return title;
     }
 
     /**
-     * This method is called from within the constructor to initialize the form.
-     * WARNING: Do NOT modify this code. The content of this method is always
-     * regenerated by the Form Editor.
+     * Indicates whether a given node is supported as a root node for this
+     * tabular viewer.
+     *
+     * @param candidateRootNode The candidate root node.
+     *
+     * @return
      */
-    @SuppressWarnings("unchecked")
-    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
-    private void initComponents() {
-
-        outlineView = new OutlineView(DataResultViewerTable.FIRST_COLUMN_LABEL);
-
-        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
-        this.setLayout(layout);
-        layout.setHorizontalGroup(
-            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-            .addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 691, Short.MAX_VALUE)
-        );
-        layout.setVerticalGroup(
-            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-            .addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 366, Short.MAX_VALUE)
-        );
-    }// </editor-fold>//GEN-END:initComponents
-    // Variables declaration - do not modify//GEN-BEGIN:variables
-    private org.openide.explorer.view.OutlineView outlineView;
-    // End of variables declaration//GEN-END:variables
-
     @Override
-    public boolean isSupported(Node selectedNode) {
+    public boolean isSupported(Node candidateRootNode) {
         return true;
     }
 
+    /**
+     * Sets the current root node of this tabular result viewer.
+     *
+     * @param rootNode The node to set as the current root node, possibly null.
+     */
     @Override
     @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
-    public void setNode(Node selectedNode) {
-
+    public void setNode(Node rootNode) {
         /*
          * The quick filter must be reset because when determining column width,
          * ETable.getRowCount is called, and the documentation states that quick
@@ -213,30 +212,30 @@ public void setNode(Node selectedNode) {
          * model."
          */
         outline.unsetQuickFilter();
-        // change the cursor to "waiting cursor" for this operation
+
         this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
         try {
-            boolean hasChildren = false;
-            if (selectedNode != null) {
-                // @@@ This just did a DB round trip to get the count and the results were not saved...
-                hasChildren = selectedNode.getChildren().getNodesCount() > 0;
-            }
-
-            if (hasChildren) {
-                currentRoot = selectedNode;
-                em.setRootContext(currentRoot);
+            /*
+             * If the given node is not null and has children, set it as the
+             * root context of the child OutlineView, otherwise make an
+             * "empty"node the root context.
+             *
+             * IMPORTANT NOTE: This is the first of many times where a
+             * getChildren call on the current root node causes all of the
+             * children of the root node to be created and defeats lazy child
+             * node creation, if it is enabled. It also likely leads to many
+             * case database round trips.
+             */
+            if (rootNode != null && rootNode.getChildren().getNodesCount() > 0) {
+                this.rootNode = rootNode;
+                this.getExplorerManager().setRootContext(this.rootNode);
                 setupTable();
             } else {
                 Node emptyNode = new AbstractNode(Children.LEAF);
-                em.setRootContext(emptyNode); // make empty node
+                this.getExplorerManager().setRootContext(emptyNode);
                 outline.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
-
-                /*
-                 * Since we are modifying the columns, we don't want to listen
-                 * to added/removed events as un-hide/hide.
-                 */
-                tableListener.listenToVisibilityChanges(false);
-                outlineView.setPropertyColumns(); // set the empty property header
+                outlineViewListener.listenToVisibilityChanges(false);
+                outlineView.setPropertyColumns();
             }
         } finally {
             this.setCursor(null);
@@ -244,17 +243,18 @@ public void setNode(Node selectedNode) {
     }
 
     /**
-     * Create Column Headers based on the Content represented by the Nodes in
-     * the table. Load persisted column order, sorting and visibility.
+     * Sets up the Outline view of this tabular result viewer by creating
+     * column headers based on the children of the current root node. The
+     * persisted column order, sorting and visibility is used.
      */
     private void setupTable() {
         /*
          * Since we are modifying the columns, we don't want to listen to
          * added/removed events as un-hide/hide, until the table setup is done.
          */
-        tableListener.listenToVisibilityChanges(false);
+        outlineViewListener.listenToVisibilityChanges(false);
 
-        /**
+        /*
          * OutlineView makes the first column be the result of
          * node.getDisplayName with the icon. This duplicates our first column,
          * which is the file name, etc. So, pop that property off the list, but
@@ -286,7 +286,10 @@ private void setupTable() {
 
         setColumnWidths();
 
-        //Load column sorting information from preferences file and apply it to columns.
+        /*
+         * Load column sorting information from preferences file and apply it to
+         * columns.
+         */
         loadColumnSorting();
 
         /*
@@ -298,7 +301,10 @@ private void setupTable() {
          */
         populateColumnMap();
 
-        //Load column visibility information from preferences file and apply it to columns.
+        /*
+         * Load column visibility information from preferences file and apply it
+         * to columns.
+         */
         loadColumnVisibility();
 
         /*
@@ -306,32 +312,36 @@ private void setupTable() {
          * it.
          */
         SwingUtilities.invokeLater(() -> {
-            if (currentRoot instanceof TableFilterNode) {
-                NodeSelectionInfo selectedChildInfo = ((TableFilterNode) currentRoot).getChildNodeSelectionInfo();
+            if (rootNode instanceof TableFilterNode) {
+                NodeSelectionInfo selectedChildInfo = ((TableFilterNode) rootNode).getChildNodeSelectionInfo();
                 if (null != selectedChildInfo) {
-                    Node[] childNodes = currentRoot.getChildren().getNodes(true);
+                    Node[] childNodes = rootNode.getChildren().getNodes(true);
                     for (int i = 0; i < childNodes.length; ++i) {
                         Node childNode = childNodes[i];
                         if (selectedChildInfo.matches(childNode)) {
                             try {
-                                em.setSelectedNodes(new Node[]{childNode});
+                                this.getExplorerManager().setSelectedNodes(new Node[]{childNode});
                             } catch (PropertyVetoException ex) {
                                 logger.log(Level.SEVERE, "Failed to select node specified by selected child info", ex);
                             }
                             break;
                         }
                     }
-                    ((TableFilterNode) currentRoot).setChildNodeSelectionInfo(null);
+                    ((TableFilterNode) rootNode).setChildNodeSelectionInfo(null);
                 }
             }
         });
 
-        //the table setup is done, so any added/removed events can now be treated as un-hide/hide.
-        tableListener.listenToVisibilityChanges(true);
+        /*
+         * The table setup is done, so any added/removed events can now be
+         * treated as un-hide/hide.
+         */
+        outlineViewListener.listenToVisibilityChanges(true);
     }
 
     /*
-     * Populate the map with references to the column objects for use when
+     * Populates the column map for the child OutlineView of this tabular
+     * result viewer with references to the column objects for use when
      * loading/storing the visibility info.
      */
     private void populateColumnMap() {
@@ -348,8 +358,12 @@ private void populateColumnMap() {
         }
     }
 
+    /*
+     * Sets the column widths for the child OutlineView of this tabular results
+     * viewer.
+     */
     private void setColumnWidths() {
-        if (currentRoot.getChildren().getNodesCount() != 0) {
+        if (rootNode.getChildren().getNodesCount() != 0) {
             final Graphics graphics = outlineView.getGraphics();
             if (graphics != null) {
                 final FontMetrics metrics = graphics.getFontMetrics();
@@ -385,8 +399,11 @@ private void setColumnWidths() {
         }
     }
 
+    /*
+     * Sets up the columns for the child OutlineView of this tabular results
+     * viewer with respect to column names and visisbility.
+     */
     synchronized private void assignColumns(List<Property<?>> props) {
-        // Get the columns setup with respect to names and sortability
         String[] propStrings = new String[props.size() * 2];
         for (int i = 0; i < props.size(); i++) {
             final Property<?> prop = props.get(i);
@@ -399,29 +416,25 @@ synchronized private void assignColumns(List<Property<?>> props) {
             propStrings[2 * i] = prop.getName();
             propStrings[2 * i + 1] = prop.getDisplayName();
         }
-
         outlineView.setPropertyColumns(propStrings);
     }
 
     /**
-     * Store the current column visibility information into a preference file.
+     * Persists the current column visibility information for the child
+     * OutlineView of this tabular result viewer using a preferences file.
      */
     private synchronized void storeColumnVisibility() {
-        if (currentRoot == null || propertiesMap.isEmpty()) {
+        if (rootNode == null || propertiesMap.isEmpty()) {
             return;
         }
-        if (currentRoot instanceof TableFilterNode) {
-            TableFilterNode tfn = (TableFilterNode) currentRoot;
+        if (rootNode instanceof TableFilterNode) {
+            TableFilterNode tfn = (TableFilterNode) rootNode;
             final Preferences preferences = NbPreferences.forModule(DataResultViewerTable.class);
             final ETableColumnModel columnModel = (ETableColumnModel) outline.getColumnModel();
-
-            //store hidden state
             for (Map.Entry<String, ETableColumn> entry : columnMap.entrySet()) {
-
                 String columnName = entry.getKey();
                 final String columnHiddenKey = ResultViewerPersistence.getColumnHiddenKey(tfn, columnName);
                 final TableColumn column = entry.getValue();
-
                 boolean columnHidden = columnModel.isColumnHidden(column);
                 if (columnHidden) {
                     preferences.putBoolean(columnHiddenKey, true);
@@ -433,16 +446,16 @@ private synchronized void storeColumnVisibility() {
     }
 
     /**
-     * Store the current column order information into a preference file.
+     * Persists the current column ordering for the child OutlineView of this
+     * tabular result viewer using a preferences file.
      */
     private synchronized void storeColumnOrder() {
-        if (currentRoot == null || propertiesMap.isEmpty()) {
+        if (rootNode == null || propertiesMap.isEmpty()) {
             return;
         }
-        if (currentRoot instanceof TableFilterNode) {
-            TableFilterNode tfn = (TableFilterNode) currentRoot;
+        if (rootNode instanceof TableFilterNode) {
+            TableFilterNode tfn = (TableFilterNode) rootNode;
             final Preferences preferences = NbPreferences.forModule(DataResultViewerTable.class);
-
             // Store the current order of the columns into settings
             for (Map.Entry<Integer, Property<?>> entry : propertiesMap.entrySet()) {
                 preferences.putInt(ResultViewerPersistence.getColumnPositionKey(tfn, entry.getValue().getName()), entry.getKey());
@@ -451,20 +464,19 @@ private synchronized void storeColumnOrder() {
     }
 
     /**
-     * Store the current column sorting information into a preference file.
+     * Persists the current column sorting information using a preferences file.
      */
     private synchronized void storeColumnSorting() {
-        if (currentRoot == null || propertiesMap.isEmpty()) {
+        if (rootNode == null || propertiesMap.isEmpty()) {
             return;
         }
-        if (currentRoot instanceof TableFilterNode) {
-            final TableFilterNode tfn = ((TableFilterNode) currentRoot);
+        if (rootNode instanceof TableFilterNode) {
+            final TableFilterNode tfn = ((TableFilterNode) rootNode);
             final Preferences preferences = NbPreferences.forModule(DataResultViewerTable.class);
             ETableColumnModel columnModel = (ETableColumnModel) outline.getColumnModel();
             for (Map.Entry<String, ETableColumn> entry : columnMap.entrySet()) {
                 ETableColumn etc = entry.getValue();
                 String columnName = entry.getKey();
-
                 //store sort rank and order
                 final String columnSortOrderKey = ResultViewerPersistence.getColumnSortOrderKey(tfn, columnName);
                 final String columnSortRankKey = ResultViewerPersistence.getColumnSortRankKey(tfn, columnName);
@@ -482,47 +494,43 @@ private synchronized void storeColumnSorting() {
 
     /**
      * Reads and applies the column sorting information persisted to the
-     * preferences file. Must be called after loadColumnOrder() since it depends
-     * on propertiesMap being initialized, and after assignColumns since it
-     * cannot set the sort on columns that have not been added to the table.
+     * preferences file. Must be called after loadColumnOrder, since it depends
+     * on the properties map being initialized, and after assignColumns, since
+     * it cannot set the sort on columns that have not been added to the table.
      */
     private synchronized void loadColumnSorting() {
-        if (currentRoot == null || propertiesMap.isEmpty()) {
+        if (rootNode == null || propertiesMap.isEmpty()) {
             return;
         }
-
-        if (currentRoot instanceof TableFilterNode) {
-            final TableFilterNode tfn = (TableFilterNode) currentRoot;
-
+        if (rootNode instanceof TableFilterNode) {
+            final TableFilterNode tfn = (TableFilterNode) rootNode;
             final Preferences preferences = NbPreferences.forModule(DataResultViewerTable.class);
             //organize property sorting information, sorted by rank
             TreeSet<ColumnSortInfo> sortInfos = new TreeSet<>(Comparator.comparing(ColumnSortInfo::getRank));
             propertiesMap.entrySet().stream().forEach(entry -> {
                 final String propName = entry.getValue().getName();
                 //if the sort rank is undefined, it will be defaulted to 0 => unsorted.
-
                 Integer sortRank = preferences.getInt(ResultViewerPersistence.getColumnSortRankKey(tfn, propName), 0);
                 //default to true => ascending
                 Boolean sortOrder = preferences.getBoolean(ResultViewerPersistence.getColumnSortOrderKey(tfn, propName), true);
-
                 sortInfos.add(new ColumnSortInfo(entry.getKey(), sortRank, sortOrder));
             });
-
             //apply sort information in rank order.
             sortInfos.forEach(sortInfo -> outline.setColumnSorted(sortInfo.modelIndex, sortInfo.order, sortInfo.rank));
         }
     }
 
+    /**
+     * Reads and applies the column visibility information persisted to the
+     * preferences file.
+     */
     private synchronized void loadColumnVisibility() {
-        if (currentRoot == null || propertiesMap.isEmpty()) {
+        if (rootNode == null || propertiesMap.isEmpty()) {
             return;
         }
-
-        if (currentRoot instanceof TableFilterNode) {
-
+        if (rootNode instanceof TableFilterNode) {
             final Preferences preferences = NbPreferences.forModule(DataResultViewerTable.class);
-
-            final TableFilterNode tfn = ((TableFilterNode) currentRoot);
+            final TableFilterNode tfn = ((TableFilterNode) rootNode);
             ETableColumnModel columnModel = (ETableColumnModel) outline.getColumnModel();
             for (Map.Entry<Integer, Property<?>> entry : propertiesMap.entrySet()) {
                 final String propName = entry.getValue().getName();
@@ -535,7 +543,7 @@ private synchronized void loadColumnVisibility() {
 
     /**
      * Gets a list of child properties (columns) in the order persisted in the
-     * preference file. Also initialized the propertiesMap with the column
+     * preference file. Also initialized the properties map with the column
      * order.
      *
      * @return a List<Node.Property<?>> of the properties in the persisted
@@ -543,14 +551,14 @@ private synchronized void loadColumnVisibility() {
      */
     private synchronized List<Node.Property<?>> loadColumnOrder() {
 
-        List<Property<?>> props = ResultViewerPersistence.getAllChildProperties(currentRoot, 100);
+        List<Property<?>> props = ResultViewerPersistence.getAllChildProperties(rootNode, 100);
 
         // If node is not table filter node, use default order for columns
-        if (!(currentRoot instanceof TableFilterNode)) {
+        if (!(rootNode instanceof TableFilterNode)) {
             return props;
         }
 
-        final TableFilterNode tfn = ((TableFilterNode) currentRoot);
+        final TableFilterNode tfn = ((TableFilterNode) rootNode);
         propertiesMap.clear();
 
         /*
@@ -587,24 +595,15 @@ private synchronized List<Node.Property<?>> loadColumnOrder() {
         return new ArrayList<>(propertiesMap.values());
     }
 
-    @Override
-    @NbBundle.Messages("DataResultViewerTable.title=Table")
-    public String getTitle() {
-        return title;
-    }
-
-    @Override
-    public DataResultViewer createInstance() {
-        return new DataResultViewerTable();
-    }
-
+    /**
+     * Frees the resources that have been allocated by this tabular results
+     * viewer, in preparation for permanently disposing of it.
+     */
     @Override
     public void clearComponent() {
         this.outlineView.removeAll();
         this.outlineView = null;
-
         super.clearComponent();
-
     }
 
     /**
@@ -775,8 +774,8 @@ public Component getTableCellRendererComponent(JTable table, Object value, boole
 
             Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
             // only override the color if a node is not selected
-            if (currentRoot != null && !isSelected) {
-                Node node = currentRoot.getChildren().getNodeAt(table.convertRowIndexToModel(row));
+            if (rootNode != null && !isSelected) {
+                Node node = rootNode.getChildren().getNodeAt(table.convertRowIndexToModel(row));
                 boolean tagFound = false;
                 if (node != null) {
                     Node.PropertySet[] propSets = node.getPropertySets();
@@ -796,10 +795,37 @@ public Component getTableCellRendererComponent(JTable table, Object value, boole
                 }
                 //if the node does have associated tags, set its background color
                 if (tagFound) {
-                    component.setBackground(TAGGED_COLOR);
+                    component.setBackground(TAGGED_ROW_COLOR);
                 }
             }
             return component;
         }
     }
+
+    /**
+     * This method is called from within the constructor to initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is always
+     * regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        outlineView = new OutlineView(DataResultViewerTable.FIRST_COLUMN_LABEL);
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+        this.setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 691, Short.MAX_VALUE)
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 366, Short.MAX_VALUE)
+        );
+    }// </editor-fold>//GEN-END:initComponents
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private org.openide.explorer.view.OutlineView outlineView;
+    // End of variables declaration//GEN-END:variables
+
 }
diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java
index 6d5cd54f5b9f6a400de8ce54a7398ccb05a1305f..b1d268c5a41720d4d5c766431bdb42cb9f527a99 100644
--- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java
+++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java
@@ -1,7 +1,7 @@
 /*
  * Autopsy Forensic Browser
  *
- * Copyright 2011-2017 Basis Technology Corp.
+ * Copyright 2012-2018 Basis Technology Corp.
  * Contact: carrier <at> sleuthkit <dot> org
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -50,6 +50,7 @@
 import org.openide.nodes.NodeReorderEvent;
 import org.openide.util.NbBundle;
 import org.openide.util.NbPreferences;
+import org.openide.util.lookup.ServiceProvider;
 import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
 import static org.sleuthkit.autopsy.corecomponents.Bundle.*;
 import org.sleuthkit.autopsy.corecomponents.ResultViewerPersistence.SortCriterion;
@@ -59,64 +60,67 @@
 import org.sleuthkit.datamodel.TskCoreException;
 
 /**
- * A thumbnail viewer for the results view, with paging support.
+ * A thumbnail result viewer, with paging support, that displays the children of
+ * the given root node using an IconView. The paging is intended to reduce
+ * memory footprint by loading no more than two humdred images at a time.
  *
- * The paging is intended to reduce memory footprint by load only up to
- * (currently) 200 images at a time. This works whether or not the underlying
- * content nodes are being lazy loaded or not.
- *
- * TODO (JIRA-2658): Fix DataResultViewer extension point. When this is done,
- * restore implementation of DataResultViewerTable as a DataResultViewer service
- * provider.
+ * Instances of this class should use the explorer manager of an ancestor top
+ * component to connect the lookups of the nodes displayed in the IconView to
+ * the actions global context. The explorer manager can be supplied during
+ * construction, but the typical use case is for the result viewer to find the
+ * ancestor top component's explorer manager at runtime.
  */
-//@ServiceProvider(service = DataResultViewer.class)
-final class DataResultViewerThumbnail extends AbstractDataResultViewer {
+@ServiceProvider(service = DataResultViewer.class)
+public final class DataResultViewerThumbnail extends AbstractDataResultViewer {
 
     private static final long serialVersionUID = 1L;
     private static final Logger logger = Logger.getLogger(DataResultViewerThumbnail.class.getName());
-    private int curPage;
+    private final PageUpdater pageUpdater = new PageUpdater();
+    private TableFilterNode rootNode;
+    private ThumbnailViewChildren rootNodeChildren;
+    private NodeSelectionListener selectionListener;
+    private int currentPage;
     private int totalPages;
-    private int curPageImages;
+    private int currentPageImages;
     private int thumbSize = ImageUtils.ICON_SIZE_MEDIUM;
-    private final PageUpdater pageUpdater = new PageUpdater();
-    private TableFilterNode tfn;
-    private ThumbnailViewChildren tvc;
 
     /**
-     * Constructs a thumbnail viewer for the results view, with paging support,
-     * that is compatible with node multiple selection actions.
-     *
-     * @param explorerManager The shared ExplorerManager for the result viewers.
+     * Constructs a thumbnail result viewer, with paging support, that displays
+     * the children of the given root node using an IconView. The viewer should
+     * have an ancestor top component to connect the lookups of the nodes
+     * displayed in the IconView to the actions global context. The explorer
+     * manager will be discovered at runtime.
      */
-    DataResultViewerThumbnail(ExplorerManager explorerManager) {
-        super(explorerManager);
-        initialize();
+    public DataResultViewerThumbnail() {
+        this(null);
     }
 
     /**
-     * Constructs a thumbnail viewer for the results view, with paging support,
-     * that is NOT compatible with node multiple selection actions.
+     * Constructs a thumbnail result viewer, with paging support, that displays
+     * the children of the given root node using an IconView. The viewer should
+     * have an ancestor top component to connect the lookups of the nodes
+     * displayed in the IconView to the actions global context.
+     *
+     * @param explorerManager The explorer manager of the ancestor top
+     *                        component.
      */
-    DataResultViewerThumbnail() {
-        initialize();
-    }
-
-    @NbBundle.Messages({"DataResultViewerThumbnail.thumbnailSizeComboBox.small=Small Thumbnails",
+    @NbBundle.Messages({
+        "DataResultViewerThumbnail.thumbnailSizeComboBox.small=Small Thumbnails",
         "DataResultViewerThumbnail.thumbnailSizeComboBox.medium=Medium Thumbnails",
         "DataResultViewerThumbnail.thumbnailSizeComboBox.large=Large Thumbnails"
     })
-    private void initialize() {
+    public DataResultViewerThumbnail(ExplorerManager explorerManager) {
+        super(explorerManager);
         initComponents();
         iconView.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
-        em.addPropertyChangeListener(new ExplorerManagerNodeSelectionListener());
-        thumbnailSizeComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(
-                new String[]{Bundle.DataResultViewerThumbnail_thumbnailSizeComboBox_small(),
-                    Bundle.DataResultViewerThumbnail_thumbnailSizeComboBox_medium(),
-                    Bundle.DataResultViewerThumbnail_thumbnailSizeComboBox_large()}));
+        thumbnailSizeComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(new String[]{
+            Bundle.DataResultViewerThumbnail_thumbnailSizeComboBox_small(),
+            Bundle.DataResultViewerThumbnail_thumbnailSizeComboBox_medium(),
+            Bundle.DataResultViewerThumbnail_thumbnailSizeComboBox_large()}));
         thumbnailSizeComboBox.setSelectedIndex(1);
-        curPage = -1;
+        currentPage = -1;
         totalPages = 0;
-        curPageImages = 0;
+        currentPageImages = 0;
     }
 
     /**
@@ -297,24 +301,22 @@ private void thumbnailSizeComboBoxActionPerformed(java.awt.event.ActionEvent evt
 
         if (thumbSize != newIconSize) {
             thumbSize = newIconSize;
-            Node root = em.getRootContext();
+            Node root = this.getExplorerManager().getRootContext();
             ((ThumbnailViewChildren) root.getChildren()).setThumbsSize(thumbSize);
 
-           
-
             // Temporarily set the explored context to the root, instead of a child node.
             // This is a workaround hack to convince org.openide.explorer.ExplorerManager to
             // update even though the new and old Node values are identical. This in turn
             // will cause the entire view to update completely. After this we 
             // immediately set the node back to the current child by calling switchPage().        
-            em.setExploredContext(root);
+            this.getExplorerManager().setExploredContext(root);
             switchPage();
         }
     }//GEN-LAST:event_thumbnailSizeComboBoxActionPerformed
 
     private void sortButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sortButtonActionPerformed
-        List<Node.Property<?>> childProperties = ResultViewerPersistence.getAllChildProperties(em.getRootContext(), 100);
-        SortChooser sortChooser = new SortChooser(childProperties, ResultViewerPersistence.loadSortCriteria(tfn));
+        List<Node.Property<?>> childProperties = ResultViewerPersistence.getAllChildProperties(this.getExplorerManager().getRootContext(), 100);
+        SortChooser sortChooser = new SortChooser(childProperties, ResultViewerPersistence.loadSortCriteria(rootNode));
         DialogDescriptor dialogDescriptor = new DialogDescriptor(sortChooser, sortChooser.getDialogTitle());
         Dialog createDialog = DialogDisplayer.getDefault().createDialog(dialogDescriptor);
         createDialog.setVisible(true);
@@ -335,8 +337,8 @@ private void sortButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FI
                 Node.Property<?> prop = childProperties.get(i);
                 String propName = prop.getName();
                 SortCriterion criterion = criteriaMap.get(prop);
-                final String columnSortOrderKey = ResultViewerPersistence.getColumnSortOrderKey(tfn, propName);
-                final String columnSortRankKey = ResultViewerPersistence.getColumnSortRankKey(tfn, propName);
+                final String columnSortOrderKey = ResultViewerPersistence.getColumnSortOrderKey(rootNode, propName);
+                final String columnSortRankKey = ResultViewerPersistence.getColumnSortRankKey(rootNode, propName);
 
                 if (criterion != null) {
                     preferences.putBoolean(columnSortOrderKey, criterion.getSortOrder() == SortOrder.ASCENDING);
@@ -346,7 +348,7 @@ private void sortButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FI
                     preferences.remove(columnSortRankKey);
                 }
             }
-            setNode(tfn); //this is just to force a refresh
+            setNode(rootNode); //this is just to force a refresh
         }
     }//GEN-LAST:event_sortButtonActionPerformed
 
@@ -379,28 +381,31 @@ public boolean isSupported(Node selectedNode) {
     @Override
     public void setNode(Node givenNode) {
         setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
-        if (tvc != null) {
-            tvc.cancelLoadingThumbnails();
+        if (selectionListener == null) {
+            this.getExplorerManager().addPropertyChangeListener(new NodeSelectionListener()); // RJCTODO: remove listener on cleanup
+        }
+        if (rootNodeChildren != null) {
+            rootNodeChildren.cancelLoadingThumbnails();
         }
         try {
             if (givenNode != null) {
-                tfn = (TableFilterNode) givenNode;
+                rootNode = (TableFilterNode) givenNode;
                 /*
                  * Wrap the given node in a ThumbnailViewChildren that will
                  * produce ThumbnailPageNodes with ThumbnailViewNode children
                  * from the child nodes of the given node.
                  */
-                tvc = new ThumbnailViewChildren(givenNode,thumbSize);
-                final Node root = new AbstractNode(tvc);
+                rootNodeChildren = new ThumbnailViewChildren(givenNode, thumbSize);
+                final Node root = new AbstractNode(rootNodeChildren);
 
                 pageUpdater.setRoot(root);
                 root.addNodeListener(pageUpdater);
-                em.setRootContext(root);
+                this.getExplorerManager().setRootContext(root);
             } else {
-                tfn = null;
-                tvc = null;
+                rootNode = null;
+                rootNodeChildren = null;
                 Node emptyNode = new AbstractNode(Children.LEAF);
-                em.setRootContext(emptyNode);
+                this.getExplorerManager().setRootContext(emptyNode);
                 iconView.setBackground(Color.BLACK);
             }
         } finally {
@@ -422,8 +427,8 @@ public DataResultViewer createInstance() {
     public void resetComponent() {
         super.resetComponent();
         this.totalPages = 0;
-        this.curPage = -1;
-        curPageImages = 0;
+        this.currentPage = -1;
+        currentPageImages = 0;
         updateControls();
     }
 
@@ -435,15 +440,15 @@ public void clearComponent() {
     }
 
     private void nextPage() {
-        if (curPage < totalPages) {
-            curPage++;
+        if (currentPage < totalPages) {
+            currentPage++;
             switchPage();
         }
     }
 
     private void previousPage() {
-        if (curPage > 1) {
-            curPage--;
+        if (currentPage > 1) {
+            currentPage--;
             switchPage();
         }
     }
@@ -465,7 +470,7 @@ private void goToPage(String pageNumText) {
             return;
         }
 
-        curPage = newPage;
+        currentPage = newPage;
         switchPage();
     }
 
@@ -488,10 +493,11 @@ protected Object doInBackground() throws Exception {
                         NbBundle.getMessage(this.getClass(), "DataResultViewerThumbnail.genThumbs"));
                 progress.start();
                 progress.switchToIndeterminate();
-                Node root = em.getRootContext();
-                Node pageNode = root.getChildren().getNodeAt(curPage - 1);
-                em.setExploredContext(pageNode);
-                curPageImages = pageNode.getChildren().getNodesCount();
+                ExplorerManager explorerManager = DataResultViewerThumbnail.this.getExplorerManager();
+                Node root = explorerManager.getRootContext();
+                Node pageNode = root.getChildren().getNodeAt(currentPage - 1);
+                explorerManager.setExploredContext(pageNode);
+                currentPageImages = pageNode.getChildren().getNodesCount();
                 return null;
             }
 
@@ -504,8 +510,8 @@ protected void done() {
                 try {
                     get();
                 } catch (InterruptedException | ExecutionException ex) {
-                    NotifyDescriptor d =
-                            new NotifyDescriptor.Message(
+                    NotifyDescriptor d
+                            = new NotifyDescriptor.Message(
                                     NbBundle.getMessage(this.getClass(), "DataResultViewerThumbnail.switchPage.done.errMsg",
                                             ex.getMessage()),
                                     NotifyDescriptor.ERROR_MESSAGE);
@@ -534,20 +540,19 @@ private void updateControls() {
             sortLabel.setText(DataResultViewerThumbnail_sortLabel_text());
 
         } else {
-            pageNumLabel.setText(
-                    NbBundle.getMessage(this.getClass(), "DataResultViewerThumbnail.pageNumbers.curOfTotal",
-                            Integer.toString(curPage), Integer.toString(totalPages)));
-            final int imagesFrom = (curPage - 1) * ThumbnailViewChildren.IMAGES_PER_PAGE + 1;
-            final int imagesTo = curPageImages + (curPage - 1) * ThumbnailViewChildren.IMAGES_PER_PAGE;
+            pageNumLabel.setText(NbBundle.getMessage(this.getClass(), "DataResultViewerThumbnail.pageNumbers.curOfTotal",
+                    Integer.toString(currentPage), Integer.toString(totalPages)));
+            final int imagesFrom = (currentPage - 1) * ThumbnailViewChildren.IMAGES_PER_PAGE + 1;
+            final int imagesTo = currentPageImages + (currentPage - 1) * ThumbnailViewChildren.IMAGES_PER_PAGE;
             imagesRangeLabel.setText(imagesFrom + "-" + imagesTo);
 
-            pageNextButton.setEnabled(!(curPage == totalPages));
-            pagePrevButton.setEnabled(!(curPage == 1));
+            pageNextButton.setEnabled(!(currentPage == totalPages));
+            pagePrevButton.setEnabled(!(currentPage == 1));
             goToPageField.setEnabled(totalPages > 1);
             sortButton.setEnabled(true);
             thumbnailSizeComboBox.setEnabled(true);
-            if (tfn != null) {
-                String sortString = ResultViewerPersistence.loadSortCriteria(tfn).stream()
+            if (rootNode != null) {
+                String sortString = ResultViewerPersistence.loadSortCriteria(rootNode).stream()
                         .map(SortCriterion::toString)
                         .collect(Collectors.joining(" "));
                 sortString = StringUtils.defaultIfBlank(sortString, "---");
@@ -578,30 +583,30 @@ public void childrenAdded(NodeMemberEvent nme) {
             totalPages = root.getChildren().getNodesCount();
 
             if (totalPages == 0) {
-                curPage = -1;
+                currentPage = -1;
                 updateControls();
                 return;
             }
 
-            if (curPage == -1 || curPage > totalPages) {
-                curPage = 1;
+            if (currentPage == -1 || currentPage > totalPages) {
+                currentPage = 1;
             }
 
             //force load the curPage node
-            final Node pageNode = root.getChildren().getNodeAt(curPage - 1);
+            final Node pageNode = root.getChildren().getNodeAt(currentPage - 1);
 
             //em.setSelectedNodes(new Node[]{pageNode});
             if (pageNode != null) {
                 pageNode.addNodeListener(new NodeListener() {
                     @Override
                     public void childrenAdded(NodeMemberEvent nme) {
-                        curPageImages = pageNode.getChildren().getNodesCount();
+                        currentPageImages = pageNode.getChildren().getNodesCount();
                         updateControls();
                     }
 
                     @Override
                     public void childrenRemoved(NodeMemberEvent nme) {
-                        curPageImages = 0;
+                        currentPageImages = 0;
                         updateControls();
                     }
 
@@ -618,7 +623,7 @@ public void propertyChange(PropertyChangeEvent evt) {
                     }
                 });
 
-                em.setExploredContext(pageNode);
+                DataResultViewerThumbnail.this.getExplorerManager().setExploredContext(pageNode);
             }
 
             updateControls();
@@ -627,7 +632,7 @@ public void propertyChange(PropertyChangeEvent evt) {
         @Override
         public void childrenRemoved(NodeMemberEvent nme) {
             totalPages = 0;
-            curPage = -1;
+            currentPage = -1;
             updateControls();
         }
 
@@ -640,14 +645,14 @@ public void nodeDestroyed(NodeEvent ne) {
         }
     }
 
-    private class ExplorerManagerNodeSelectionListener implements PropertyChangeListener {
+    private class NodeSelectionListener implements PropertyChangeListener {
 
         @Override
         public void propertyChange(PropertyChangeEvent evt) {
             if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
                 setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
                 try {
-                    Node[] selectedNodes = em.getSelectedNodes();
+                    Node[] selectedNodes = DataResultViewerThumbnail.this.getExplorerManager().getSelectedNodes();
                     if (selectedNodes.length == 1) {
                         AbstractFile af = selectedNodes[0].getLookup().lookup(AbstractFile.class);
                         if (af == null) {
diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java
index 13219f863d13cd981354321f96f2cdea8fa96f49..3069b7fb5d8792a34a27d33e59eca3f532e65c6e 100644
--- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java
+++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java
@@ -101,7 +101,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
 
     private final transient ExplorerManager em = new ExplorerManager();
     private static DirectoryTreeTopComponent instance;
-    private final DataResultTopComponent dataResult = new DataResultTopComponent(true, Bundle.DirectoryTreeTopComponent_resultsView_title());
+    private final DataResultTopComponent dataResult = new DataResultTopComponent(Bundle.DirectoryTreeTopComponent_resultsView_title());
     private final LinkedList<String[]> backList;
     private final LinkedList<String[]> forwardList;
     private static final String PREFERRED_ID = "DirectoryTreeTopComponent"; //NON-NLS