diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java index 25b97aed66..d44eed57a7 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java @@ -26,10 +26,15 @@ import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import javax.swing.JTabbedPane; +import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.openide.explorer.ExplorerManager; import org.openide.nodes.Node; +import org.openide.nodes.NodeEvent; +import org.openide.nodes.NodeListener; +import org.openide.nodes.NodeMemberEvent; +import org.openide.nodes.NodeReorderEvent; import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent; @@ -59,6 +64,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C private DataContent customContentViewer; private boolean isMain; private String title; + private final DummyNodeListener dummyNodeListener = new DummyNodeListener(); private static final Logger logger = Logger.getLogger(DataResultPanel.class.getName() ); private boolean listeningToTabbedPane = false; @@ -340,56 +346,80 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C @Override public void setNode(Node selectedNode) { + if (this.rootNode != null) { + this.rootNode.removeNodeListener(dummyNodeListener); + } // Deferring becoming a listener to the tabbed pane until this point // eliminates handling a superfluous stateChanged event during construction. if (listeningToTabbedPane == false) { dataResultTabbedPanel.addChangeListener(this); listeningToTabbedPane = true; } - + this.rootNode = selectedNode; + if (this.rootNode != null) { + this.rootNode.addNodeListener(dummyNodeListener); + } + + setupTabs(selectedNode); + if (selectedNode != null) { - int childrenCount = selectedNode.getChildren().getNodesCount(true); + int childrenCount = selectedNode.getChildren().getNodesCount(); this.numberMatchLabel.setText(Integer.toString(childrenCount)); } this.numberMatchLabel.setVisible(true); resetTabs(selectedNode); - - //update/disable tabs based on if supported for this node - int drvC = 0; - for (UpdateWrapper drv : viewers) { - - if (drv.isSupported(selectedNode)) { - dataResultTabbedPanel.setEnabledAt(drvC, true); - } else { - dataResultTabbedPanel.setEnabledAt(drvC, false); - } - ++drvC; - } - - // if the current tab is no longer enabled, then find one that is - boolean hasViewerEnabled = true; + + // set the display on the current active tab int currentActiveTab = this.dataResultTabbedPanel.getSelectedIndex(); - if ((currentActiveTab == -1) || (dataResultTabbedPanel.isEnabledAt(currentActiveTab) == false)) { - hasViewerEnabled = false; - for (int i = 0; i < dataResultTabbedPanel.getTabCount(); i++) { - if (dataResultTabbedPanel.isEnabledAt(i)) { - currentActiveTab = i; - hasViewerEnabled = true; - break; + if (currentActiveTab != -1) { + UpdateWrapper drv = viewers.get(currentActiveTab); + drv.setNode(selectedNode); + } + } + + private void setupTabs(final Node selectedNode) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + //update/disable tabs based on if supported for this node + int drvC = 0; + for (UpdateWrapper drv : viewers) { + + if (drv.isSupported(selectedNode)) { + dataResultTabbedPanel.setEnabledAt(drvC, true); + } else { + dataResultTabbedPanel.setEnabledAt(drvC, false); + } + ++drvC; + } + + // if the current tab is no longer enabled, then find one that is + boolean hasViewerEnabled = true; + int currentActiveTab = dataResultTabbedPanel.getSelectedIndex(); + if ((currentActiveTab == -1) || (dataResultTabbedPanel.isEnabledAt(currentActiveTab) == false)) { + hasViewerEnabled = false; + for (int i = 0; i < dataResultTabbedPanel.getTabCount(); i++) { + if (dataResultTabbedPanel.isEnabledAt(i)) { + currentActiveTab = i; + hasViewerEnabled = true; + break; + } + } + + if (hasViewerEnabled) { + dataResultTabbedPanel.setSelectedIndex(currentActiveTab); + } + } + + if (hasViewerEnabled) { + viewers.get(currentActiveTab).setNode(selectedNode); } } - - if (hasViewerEnabled) { - dataResultTabbedPanel.setSelectedIndex(currentActiveTab); - } - } + }); - if (hasViewerEnabled) { - viewers.get(currentActiveTab).setNode(selectedNode); - } } @Override @@ -579,4 +609,34 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C public void setNumMatches(int numMatches) { this.numberMatchLabel.setText(Integer.toString(numMatches)); } + + private class DummyNodeListener implements NodeListener { + private static final String DUMMY_NODE_DISPLAY_NAME = "Please Wait..."; + + @Override + public void childrenAdded(final NodeMemberEvent nme) { + Node added = nme.getNode(); + if (added.getDisplayName().equals(DUMMY_NODE_DISPLAY_NAME)) { + // don't set up tabs if the new node is a waiting node + return; + } + setupTabs(nme.getNode()); + } + + @Override + public void childrenRemoved(NodeMemberEvent nme) { + } + + @Override + public void childrenReordered(NodeReorderEvent nre) { + } + + @Override + public void nodeDestroyed(NodeEvent ne) { + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java index da5642e6b6..6c42c9f7bf 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java @@ -22,14 +22,17 @@ import java.awt.Cursor; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.dnd.DnDConstants; +import java.beans.PropertyChangeEvent; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.JTable; import javax.swing.ListSelectionModel; +import javax.swing.SwingUtilities; import org.netbeans.swing.outline.DefaultOutlineModel; import org.openide.explorer.ExplorerManager; import org.openide.explorer.view.OutlineView; @@ -38,6 +41,10 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Node.Property; import org.openide.nodes.Node.PropertySet; +import org.openide.nodes.NodeEvent; +import org.openide.nodes.NodeListener; +import org.openide.nodes.NodeMemberEvent; +import org.openide.nodes.NodeReorderEvent; import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer; @@ -53,6 +60,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { private String firstColumnLabel = "Name"; private Set propertiesAcc = new LinkedHashSet<>(); private static final Logger logger = Logger.getLogger(DataResultViewerTable.class.getName()); + private final DummyNodeListener dummyNodeListener = new DummyNodeListener(); /** * Creates a DataResultViewerTable object that is compatible with node @@ -241,11 +249,38 @@ public class DataResultViewerTable extends AbstractDataResultViewer { hasChildren = selectedNode.getChildren().getNodesCount() > 0; } - + Node oldNode = this.em.getRootContext(); + if (oldNode != null) { + oldNode.removeNodeListener(dummyNodeListener); + } + // if there's no selection node, do nothing if (hasChildren) { Node root = selectedNode; - + root.addNodeListener(dummyNodeListener); + setupTable(root); + } else { + final OutlineView ov = ((OutlineView) this.tableScrollPanel); + Node emptyNode = new AbstractNode(Children.LEAF); + em.setRootContext(emptyNode); // make empty node + ov.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); + ov.setPropertyColumns(); // set the empty property header + } + } finally { + this.setCursor(null); + } + } + + /** + * Create Column Headers based on the Content represented by the Nodes in + * the table. + * + * @param root The parent Node of the ContentNodes + */ + private void setupTable(final Node root) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { //wrap to filter out children //note: this breaks the tree view mode in this generic viewer, //so wrap nodes earlier if want 1 level view @@ -256,11 +291,11 @@ public class DataResultViewerTable extends AbstractDataResultViewer { em.setRootContext(root); - final OutlineView ov = ((OutlineView) this.tableScrollPanel); + final OutlineView ov = ((OutlineView) DataResultViewerTable.this.tableScrollPanel); propertiesAcc.clear(); - this.getAllChildPropertyHeadersRec(selectedNode, 100); + DataResultViewerTable.this.getAllChildPropertyHeadersRec(root, 100); List props = new ArrayList(propertiesAcc); if (props.size() > 0) { Node.Property prop = props.remove(0); @@ -310,7 +345,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { // get first 100 rows values for the table Object[][] content = null; - content = getRowValues(selectedNode, 100); + content = getRowValues(root, 100); if (content != null) { @@ -336,17 +371,8 @@ public class DataResultViewerTable extends AbstractDataResultViewer { // turn on the auto resize ov.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); } - - } else { - final OutlineView ov = ((OutlineView) this.tableScrollPanel); - Node emptyNode = new AbstractNode(Children.LEAF); - em.setRootContext(emptyNode); // make empty node - ov.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); - ov.setPropertyColumns(); // set the empty property header } - } finally { - this.setCursor(null); - } + }); } private static Object[][] getRowValues(Node node, int rows) { @@ -449,4 +475,36 @@ public class DataResultViewerTable extends AbstractDataResultViewer { super.clearComponent(); } + + private class DummyNodeListener implements NodeListener { + private static final String DUMMY_NODE_DISPLAY_NAME = "Please Wait..."; + + @Override + public void childrenAdded(NodeMemberEvent nme) { + Node added = nme.getNode(); + if (added.getDisplayName().equals(DUMMY_NODE_DISPLAY_NAME)) { + // If it's the dummy waiting node, we don't want + // to reload the table headers + return; + } + setupTable(added); + } + + @Override + public void childrenRemoved(NodeMemberEvent nme) { + + } + + @Override + public void childrenReordered(NodeReorderEvent nre) { + } + + @Override + public void nodeDestroyed(NodeEvent ne) { + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java index 72f8bd451c..66390045ee 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java @@ -22,6 +22,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.logging.Level; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; import org.openide.nodes.AbstractNode; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; @@ -213,6 +215,8 @@ public class DeletedContent implements AutopsyVisitableItem { private SleuthkitCase skCase; private DeletedContent.DeletedContentFilter filter; private final Logger logger = Logger.getLogger(DeletedContentChildren.class.getName()); + + private static final int MAX_OBJECTS = 2001; DeletedContentChildren(DeletedContent.DeletedContentFilter filter, SleuthkitCase skCase) { this.skCase = skCase; @@ -221,7 +225,20 @@ public class DeletedContent implements AutopsyVisitableItem { @Override protected boolean createKeys(List list) { - list.addAll(runFsQuery()); + List queryList = runFsQuery(); + if (queryList.size() == MAX_OBJECTS) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + JOptionPane.showMessageDialog(null, "There are more Deleted Files than can be displayed. Only the first " + + (MAX_OBJECTS - 1) + + " Deleted Files will be shown."); + } + }); + } + + queryList.remove(queryList.size() - 1); + list.addAll(queryList); return true; } @@ -258,6 +275,7 @@ public class DeletedContent implements AutopsyVisitableItem { } + query += " LIMIT " + MAX_OBJECTS; return query; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeChildren.java index 91bd14f248..3376e9f0d9 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeChildren.java @@ -57,7 +57,6 @@ class FileTypeChildren extends ChildFactory { list.addAll(runQuery()); return true; } - private String createQuery(){ String query = "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")" @@ -66,7 +65,7 @@ class FileTypeChildren extends ChildFactory { query += " OR name LIKE '%" + s + "'"; } query += ')'; - //query += " LIMIT " + MAX_OBJECTS; +// query += " LIMIT " + MAX_OBJECTS; return query; } @@ -74,10 +73,7 @@ class FileTypeChildren extends ChildFactory { private List runQuery(){ List list = new ArrayList<>(); try { - List res = skCase.findAllFilesWhere(createQuery()); - for(AbstractFile c : res){ - list.add(c); - } + list = skCase.findAllFilesWhere(createQuery()); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Couldn't get search results", ex); } diff --git a/build-windows.xml b/build-windows.xml index cb9f2faec8..0c1ec700a9 100644 --- a/build-windows.xml +++ b/build-windows.xml @@ -27,6 +27,17 @@ + + + + + + + + + + + @@ -196,7 +207,7 @@ - +