mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-11 23:46:15 +00:00
Merge pull request #3726 from rcordovano/3726-result-view-infrastructure
3726 result view infrastructure
This commit is contained in:
commit
ef58e61759
@ -128,7 +128,7 @@ public final class MessageBrowser extends JPanel implements ExplorerManager.Prov
|
||||
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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 java.util.List;
|
||||
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();
|
||||
|
||||
|
@ -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 java.awt.Component;
|
||||
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.
|
||||
*/
|
||||
public void setNode(Node selectedNode);
|
||||
|
||||
/**
|
||||
* Gets the title of this viewer
|
||||
*/
|
||||
public String getTitle();
|
||||
|
||||
/**
|
||||
* Get a new instance of DataResultViewer
|
||||
* 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 DataResultViewer createInstance();
|
||||
|
||||
/**
|
||||
* Get the Swing component (i.e. JPanel) for 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 boolean isSupported(Node node);
|
||||
|
||||
/**
|
||||
* 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 void setNode(Node node);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
default public void setSelectedNodes(Node[] selectedNodes) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the title of this result viewer.
|
||||
*
|
||||
* @return The title.
|
||||
*/
|
||||
public String getTitle();
|
||||
|
||||
/**
|
||||
* Gets the Swing component for this viewer.
|
||||
*
|
||||
* @return The component.
|
||||
*/
|
||||
public Component getComponent();
|
||||
|
||||
/**
|
||||
* Resets the viewer.
|
||||
* Resets the state of the Swing component for this viewer to its default
|
||||
* state.
|
||||
*/
|
||||
public void resetComponent();
|
||||
default public void resetComponent() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the objects that have been allocated by this viewer, in preparation
|
||||
* for permanently disposing of it.
|
||||
* Frees any resources tha have been allocated by this result viewer, in
|
||||
* preparation for permanently disposing of it.
|
||||
*/
|
||||
public void clearComponent();
|
||||
default public void clearComponent() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand node, if supported by the viewed
|
||||
* Sets the node for which this result viewer should provide a view of the
|
||||
* underlying application data model object, and expands the node.
|
||||
*
|
||||
* @param n Node to expand
|
||||
*/
|
||||
public void expandNode(Node n);
|
||||
|
||||
/**
|
||||
* Select the given node array
|
||||
*/
|
||||
public void setSelectedNodes(Node[] selected);
|
||||
|
||||
/**
|
||||
* Checks whether the currently selected root node is supported by this
|
||||
* viewer
|
||||
* @param node The node.
|
||||
*
|
||||
* @param selectedNode the selected node
|
||||
*
|
||||
* @return True if supported, else false
|
||||
*/
|
||||
public boolean isSupported(Node selectedNode);
|
||||
|
||||
/**
|
||||
* Set a custom content viewer to respond to selection events from this
|
||||
* result viewer. If not set, the default content viewer is used
|
||||
*
|
||||
* @param contentViewer content viewer to respond to selection events from
|
||||
* this 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 expandNode(Node node) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a custom content viewer to which nodes selected in this result
|
||||
* viewer should be pushed via DataContent.setNode.
|
||||
*
|
||||
* @param contentViewer The content viewer.
|
||||
*
|
||||
* @deprecated This API is not used by the application.
|
||||
*/
|
||||
@Deprecated
|
||||
default public void setContentViewer(DataContent contentViewer) {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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,65 +23,64 @@ import java.beans.PropertyVetoException;
|
||||
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
|
||||
* @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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public AbstractDataResultViewer() {
|
||||
this(new ExplorerManager());
|
||||
public AbstractDataResultViewer(ExplorerManager explorerManager) {
|
||||
this.explorerManager = explorerManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearComponent() {
|
||||
public ExplorerManager getExplorerManager() {
|
||||
if (this.explorerManager == null) {
|
||||
this.explorerManager = ExplorerManager.find(this);
|
||||
}
|
||||
|
||||
public Node getSelectedNode() {
|
||||
Node result = null;
|
||||
Node[] selectedNodes = this.getExplorerManager().getSelectedNodes();
|
||||
if (selectedNodes.length > 0) {
|
||||
result = selectedNodes[0];
|
||||
}
|
||||
return result;
|
||||
return this.explorerManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expandNode(Node n) {
|
||||
public void setSelectedNodes(Node[] selected) {
|
||||
try {
|
||||
this.getExplorerManager().setSelectedNodes(selected);
|
||||
} catch (PropertyVetoException ex) {
|
||||
logger.log(Level.SEVERE, "Couldn't set selected nodes", ex); //NON-NLS
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetComponent() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -89,22 +88,4 @@ abstract class AbstractDataResultViewer extends JPanel implements DataResultView
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExplorerManager getExplorerManager() {
|
||||
return this.em;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedNodes(Node[] selected) {
|
||||
try {
|
||||
this.em.setSelectedNodes(selected);
|
||||
} catch (PropertyVetoException ex) {
|
||||
logger.log(Level.WARNING, "Couldn't set selected nodes.", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void setContentViewer(DataContent contentViewer) {
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultPanel.descriptionLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultPanel.numberOfChildNodesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</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]"/>
|
||||
|
@ -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.awt.Cursor;
|
||||
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.corecomponentinterfaces.DataResultViewer;
|
||||
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 ExplorerManager explorerManager;
|
||||
private ExplorerManagerNodeSelectionListener emNodeSelectionListener;
|
||||
private Node rootNode;
|
||||
private final RootNodeListener rootNodeListener = new RootNodeListener();
|
||||
private boolean listeningToTabbedPane;
|
||||
private final boolean isMain;
|
||||
private final List<DataResultViewer> resultViewers;
|
||||
private final ExplorerManagerListener explorerManagerListener;
|
||||
private final RootNodeListener rootNodeListener;
|
||||
private DataContent contentView;
|
||||
private ExplorerManager explorerManager;
|
||||
private Node currentRootNode;
|
||||
private boolean listeningToTabbedPane;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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.
|
||||
*
|
||||
* @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) {
|
||||
DataResultPanel resultPanel = new DataResultPanel(title, false, Collections.emptyList(), 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 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 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 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, 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, Collection<DataResultViewer> viewers) {
|
||||
DataResultPanel resultPanel = new DataResultPanel(title, false, viewers, null);
|
||||
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 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 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 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes code common to all of the DataSreultPanel factory methods.
|
||||
* 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 resultViewPanel A content view to use in place of the default
|
||||
* @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 result view panel.
|
||||
*/
|
||||
private static void createInstanceCommon(String title, String pathText, Node rootNode, int totalMatches, DataResultPanel resultViewPanel) {
|
||||
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 result view panel factory methods.
|
||||
*
|
||||
* @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 resultViewPanel A new results view panel.
|
||||
*/
|
||||
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 class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
|
||||
/**
|
||||
* 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 class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
explorerManager = ExplorerManager.find(this);
|
||||
emNodeSelectionListener = new ExplorerManagerNodeSelectionListener();
|
||||
explorerManager.addPropertyChangeListener(emNodeSelectionListener);
|
||||
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;
|
||||
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 {
|
||||
resultViewer = factory.createInstance();
|
||||
}
|
||||
addResultViewer(resultViewer);
|
||||
this.resultViewers.add(resultViewer.createInstance());
|
||||
}
|
||||
}
|
||||
|
||||
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 class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
* 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 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
* 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 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
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 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
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,52 +524,39 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
@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;
|
||||
}
|
||||
|
||||
if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES) && contentView != null) {
|
||||
/*
|
||||
* Only interested in node selection events.
|
||||
* 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.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -578,6 +564,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
* 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 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
*
|
||||
*/
|
||||
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 class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
// <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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,7 +28,7 @@
|
||||
<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>
|
||||
|
@ -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,201 +40,237 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a partially initialized result view top component.
|
||||
*
|
||||
* @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 description, Node node, int childNodeCount, DataResultTopComponent resultViewTopComponent) {
|
||||
resultViewTopComponent.setNumberOfChildNodes(childNodeCount);
|
||||
resultViewTopComponent.open();
|
||||
resultViewTopComponent.setNode(node);
|
||||
resultViewTopComponent.setPath(description);
|
||||
resultViewTopComponent.requestActive();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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 The result view top component.
|
||||
*/
|
||||
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 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 The title for the top component, appears on the top
|
||||
* component's tab.
|
||||
*/
|
||||
public DataResultTopComponent(String title) {
|
||||
this(true, title, null, Collections.emptyList(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a result view top component that provides multiple views of
|
||||
* the application data represented by a NetBeans Node.
|
||||
*
|
||||
* @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,
|
||||
*/
|
||||
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;
|
||||
dataResultPanel = new DataResultPanel(name, customContentViewer);
|
||||
this.dataResultPanel = new DataResultPanel(title, isMain, viewers, contentViewTopComponent);
|
||||
initComponents();
|
||||
customizeComponent(isMain, name);
|
||||
customizeComponent(title);
|
||||
}
|
||||
|
||||
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
|
||||
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); // set option to close compoment in GUI
|
||||
putClientProperty(TopComponent.PROP_CLOSING_DISABLED, isMain);
|
||||
putClientProperty(TopComponent.PROP_MAXIMIZATION_DISABLED, true);
|
||||
putClientProperty(TopComponent.PROP_DRAGGING_DISABLED, true);
|
||||
|
||||
activeComponentIds.add(title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize previously created tc instance with additional data
|
||||
*
|
||||
* @param pathText
|
||||
* @param givenNode
|
||||
* @param totalMatches
|
||||
* @param newDataResult previously created with createInstance()
|
||||
* uninitialized instance
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new non-default DataResult component and initializes it
|
||||
*
|
||||
* @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
|
||||
*
|
||||
* @return a new, not default, initialized DataResultTopComponent instance
|
||||
*/
|
||||
public static DataResultTopComponent createInstance(String title, String pathText, Node givenNode, int totalMatches) {
|
||||
DataResultTopComponent newDataResult = new DataResultTopComponent(false, title);
|
||||
|
||||
initInstance(pathText, givenNode, totalMatches, newDataResult);
|
||||
|
||||
return newDataResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new non-default DataResult component linked with a custom data
|
||||
* content, and initializes it.
|
||||
*
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new non-default DataResult component. You probably want to use
|
||||
* initInstance after it
|
||||
*
|
||||
* @param title
|
||||
*
|
||||
* @return a new, not default, not fully initialized DataResultTopComponent
|
||||
* instance
|
||||
*/
|
||||
public static DataResultTopComponent createInstance(String title) {
|
||||
final DataResultTopComponent newDataResult = new DataResultTopComponent(false, title);
|
||||
|
||||
return newDataResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExplorerManager getExplorerManager() {
|
||||
return explorerManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 class DataResultTopComponent extends TopComponent implements DataResult,
|
||||
|
||||
@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 @@ public class DataResultTopComponent extends TopComponent implements DataResult,
|
||||
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
|
||||
@ -343,31 +376,15 @@ public class DataResultTopComponent extends TopComponent implements DataResult,
|
||||
|
||||
@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 class DataResultTopComponent extends TopComponent implements DataResult,
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
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:
|
||||
* 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.
|
||||
*/
|
||||
public DataResultViewerTable() {
|
||||
this(null, Bundle.DataResultViewerTable_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.
|
||||
*
|
||||
* 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().
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Creates a DataResultViewerTable object that is compatible with node
|
||||
* multiple selection actions, and the default title.
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DataResultViewerTable object that is NOT compatible with node
|
||||
* multiple selection actions.
|
||||
/*
|
||||
* Add a table listener to the child OutlineView (explorer view) to
|
||||
* persist the order of the table columns when a column is moved.
|
||||
*/
|
||||
public DataResultViewerTable() {
|
||||
this(new ExplorerManager(),Bundle.DataResultViewerTable_title());
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Expand node
|
||||
* 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.
|
||||
*
|
||||
* @param n Node to expand
|
||||
* @return A new instance of a tabular result viewer,
|
||||
*/
|
||||
@Override
|
||||
public void expandNode(Node n) {
|
||||
super.expandNode(n);
|
||||
|
||||
outlineView.expandNode(n);
|
||||
public DataResultViewer createInstance() {
|
||||
return new DataResultViewerTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Gets the title of this tabular result viewer.
|
||||
*/
|
||||
@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) {
|
||||
@NbBundle.Messages("DataResultViewerTable.title=Table")
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether a given node is supported as a root node for this
|
||||
* tabular viewer.
|
||||
*
|
||||
* @param candidateRootNode The candidate root node.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
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 class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
* 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 class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
|
||||
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 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
*/
|
||||
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 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
* 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 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
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 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
|
||||
/**
|
||||
* 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 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
|
||||
/**
|
||||
* 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 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
*/
|
||||
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 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
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 class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
|
||||
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 class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
}
|
||||
//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
|
||||
|
||||
}
|
||||
|
@ -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.NodeMemberEvent;
|
||||
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.AbstractFile;
|
||||
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 int totalPages;
|
||||
private int curPageImages;
|
||||
private int thumbSize = ImageUtils.ICON_SIZE_MEDIUM;
|
||||
private final PageUpdater pageUpdater = new PageUpdater();
|
||||
private TableFilterNode tfn;
|
||||
private ThumbnailViewChildren tvc;
|
||||
private TableFilterNode rootNode;
|
||||
private ThumbnailViewChildren rootNodeChildren;
|
||||
private NodeSelectionListener selectionListener;
|
||||
private int currentPage;
|
||||
private int totalPages;
|
||||
private int currentPageImages;
|
||||
private int thumbSize = ImageUtils.ICON_SIZE_MEDIUM;
|
||||
|
||||
/**
|
||||
* Constructs a thumbnail viewer for the results view, with paging support,
|
||||
* that is 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. The explorer
|
||||
* manager will be discovered at runtime.
|
||||
*/
|
||||
public DataResultViewerThumbnail() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 shared ExplorerManager for the result viewers.
|
||||
* @param explorerManager The explorer manager of the ancestor top
|
||||
* component.
|
||||
*/
|
||||
DataResultViewerThumbnail(ExplorerManager explorerManager) {
|
||||
super(explorerManager);
|
||||
initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a thumbnail viewer for the results view, with paging support,
|
||||
* that is NOT compatible with node multiple selection actions.
|
||||
*/
|
||||
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(),
|
||||
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 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
||||
|
||||
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 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
||||
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 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
||||
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 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
||||
@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 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
||||
public void resetComponent() {
|
||||
super.resetComponent();
|
||||
this.totalPages = 0;
|
||||
this.curPage = -1;
|
||||
curPageImages = 0;
|
||||
this.currentPage = -1;
|
||||
currentPageImages = 0;
|
||||
updateControls();
|
||||
}
|
||||
|
||||
@ -435,15 +440,15 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
||||
}
|
||||
|
||||
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 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
||||
return;
|
||||
}
|
||||
|
||||
curPage = newPage;
|
||||
currentPage = newPage;
|
||||
switchPage();
|
||||
}
|
||||
|
||||
@ -488,10 +493,11 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
||||
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 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
||||
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 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
||||
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 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
||||
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 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
||||
}
|
||||
});
|
||||
|
||||
em.setExploredContext(pageNode);
|
||||
DataResultViewerThumbnail.this.getExplorerManager().setExploredContext(pageNode);
|
||||
}
|
||||
|
||||
updateControls();
|
||||
@ -627,7 +632,7 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
||||
@Override
|
||||
public void childrenRemoved(NodeMemberEvent nme) {
|
||||
totalPages = 0;
|
||||
curPage = -1;
|
||||
currentPage = -1;
|
||||
updateControls();
|
||||
}
|
||||
|
||||
@ -640,14 +645,14 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user