diff --git a/Core/build.xml b/Core/build.xml index 9a3fe484fe..128d0c1286 100644 --- a/Core/build.xml +++ b/Core/build.xml @@ -23,7 +23,7 @@ - + diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index 3ec5353c90..9cdbb08f9e 100644 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -2,20 +2,22 @@ file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone-2.7.0.jar file.reference.jython.jar-1=release/modules/ext/jython.jar -file.reference.metadata-extractor-2.6.2.jar=release/modules/ext/metadata-extractor-2.6.2.jar +file.reference.metadata-extractor-2.8.1.jar=release/modules/ext/metadata-extractor-2.8.1.jar +file.reference.opencv-248.jar=release/modules/ext/opencv-248.jar file.reference.Rejistry-1.0-SNAPSHOT.jar=release/modules/ext/Rejistry-1.0-SNAPSHOT.jar file.reference.sevenzipjbinding-AllPlatforms.jar=release/modules/ext/sevenzipjbinding-AllPlatforms.jar file.reference.sevenzipjbinding.jar=release/modules/ext/sevenzipjbinding.jar -file.reference.sqlite-jdbc-3.7.15-M1.jar=release/modules/ext/sqlite-jdbc-3.7.15-M1.jar +file.reference.sqlite-jdbc-3.8.11.jar=release/modules/ext/sqlite-jdbc-3.8.11.jar file.reference.StixLib.jar=release/modules/ext/StixLib.jar file.reference.tika-core-1.2.jar=release/modules/ext/tika-core-1.2.jar file.reference.Tsk_DataModel.jar=release/modules/ext/Tsk_DataModel.jar -file.reference.xmpcore.jar=release/modules/ext/xmpcore.jar +file.reference.xmpcore-5.1.2.jar=release/modules/ext/xmpcore-5.1.2.jar javac.source=1.8 javac.compilerargs=-Xlint -Xlint:-serial license.file=../LICENSE-2.0.txt nbm.homepage=http://www.sleuthkit.org/ nbm.module.author=Brian Carrier nbm.needs.restart=true +source.reference.metadata-extractor-2.8.1.jar=release/modules/ext/metadata-extractor-2.8.1-src.zip!/Source/ spec.version.base=10.3 diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 463e1c1903..c8089bda6c 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -203,10 +203,26 @@ org.sleuthkit.autopsy.report org.sleuthkit.datamodel + + ext/xmpcore-5.1.2.jar + release/modules/ext/xmpcore-5.1.2.jar + ext/jdom-2.0.5.jar release/modules/ext/jdom-2.0.5.jar + + ext/StixLib.jar + release/modules/ext/StixLib.jar + + + ext/sqlite-jdbc-3.8.11.jar + release/modules/ext/sqlite-jdbc-3.8.11.jar + + + ext/opencv-248.jar + release/modules/ext/opencv-248.jar + ext/Rejistry-1.0-SNAPSHOT.jar release/modules/ext/Rejistry-1.0-SNAPSHOT.jar @@ -219,30 +235,18 @@ ext/jython-standalone-2.7.0.jar release/modules/ext/jython-standalone-2.7.0.jar - - ext/StixLib.jar - release/modules/ext/StixLib.jar - - - ext/sqlite-jdbc-3.7.15-M1.jar - release/modules/ext/sqlite-jdbc-3.7.15-M1.jar - ext/sevenzipjbinding-AllPlatforms.jar release/modules/ext/sevenzipjbinding-AllPlatforms.jar - - ext/metadata-extractor-2.6.2.jar - release/modules/ext/metadata-extractor-2.6.2.jar - - - ext/xmpcore.jar - release/modules/ext/xmpcore.jar - ext/tika-core-1.2.jar release/modules/ext/tika-core-1.2.jar + + ext/metadata-extractor-2.8.1.jar + release/modules/ext/metadata-extractor-2.8.1.jar + ext/jdom-2.0.5-contrib.jar release/modules/ext/jdom-2.0.5-contrib.jar diff --git a/Core/release/modules/ext/jython-standalone-2.7.0.jar b/Core/release/modules/ext/jython-standalone-2.7.0.jar index c49498347a..e7b35d6c5f 100755 Binary files a/Core/release/modules/ext/jython-standalone-2.7.0.jar and b/Core/release/modules/ext/jython-standalone-2.7.0.jar differ diff --git a/Core/release/modules/ext/metadata-extractor-2.6.2.jar b/Core/release/modules/ext/metadata-extractor-2.6.2.jar deleted file mode 100755 index 68426ac059..0000000000 Binary files a/Core/release/modules/ext/metadata-extractor-2.6.2.jar and /dev/null differ diff --git a/Core/release/modules/ext/metadata-extractor-2.8.1.jar b/Core/release/modules/ext/metadata-extractor-2.8.1.jar new file mode 100755 index 0000000000..a5fe48640b Binary files /dev/null and b/Core/release/modules/ext/metadata-extractor-2.8.1.jar differ diff --git a/Core/release/modules/ext/opencv-248.jar b/Core/release/modules/ext/opencv-248.jar new file mode 100644 index 0000000000..f09b29077d Binary files /dev/null and b/Core/release/modules/ext/opencv-248.jar differ diff --git a/Core/release/modules/ext/xmpcore-5.1.2.jar b/Core/release/modules/ext/xmpcore-5.1.2.jar new file mode 100755 index 0000000000..ecd5db142e Binary files /dev/null and b/Core/release/modules/ext/xmpcore-5.1.2.jar differ diff --git a/Core/release/modules/ext/xmpcore.jar b/Core/release/modules/ext/xmpcore.jar deleted file mode 100755 index 884c2dd57f..0000000000 Binary files a/Core/release/modules/ext/xmpcore.jar and /dev/null differ diff --git a/Core/release/modules/lib/amd64/opencv_ffmpeg248_64.dll b/Core/release/modules/lib/amd64/opencv_ffmpeg248_64.dll new file mode 100644 index 0000000000..37236e5424 Binary files /dev/null and b/Core/release/modules/lib/amd64/opencv_ffmpeg248_64.dll differ diff --git a/Core/release/modules/lib/amd64/opencv_java248.dll b/Core/release/modules/lib/amd64/opencv_java248.dll new file mode 100644 index 0000000000..ab989a6b11 Binary files /dev/null and b/Core/release/modules/lib/amd64/opencv_java248.dll differ diff --git a/Core/release/modules/lib/i386/opencv_ffmpeg248.dll b/Core/release/modules/lib/i386/opencv_ffmpeg248.dll new file mode 100644 index 0000000000..b1e70df6a3 Binary files /dev/null and b/Core/release/modules/lib/i386/opencv_ffmpeg248.dll differ diff --git a/Core/release/modules/lib/i386/opencv_java248.dll b/Core/release/modules/lib/i386/opencv_java248.dll new file mode 100644 index 0000000000..f1c1bc9a43 Binary files /dev/null and b/Core/release/modules/lib/i386/opencv_java248.dll differ diff --git a/Core/release/modules/lib/i586/opencv_ffmpeg248_64.dll b/Core/release/modules/lib/i586/opencv_ffmpeg248_64.dll new file mode 100644 index 0000000000..b1e70df6a3 Binary files /dev/null and b/Core/release/modules/lib/i586/opencv_ffmpeg248_64.dll differ diff --git a/Core/release/modules/lib/i586/opencv_java248.dll b/Core/release/modules/lib/i586/opencv_java248.dll new file mode 100644 index 0000000000..f1c1bc9a43 Binary files /dev/null and b/Core/release/modules/lib/i586/opencv_java248.dll differ diff --git a/Core/release/modules/lib/i686/opencv_ffmpeg248_64.dll b/Core/release/modules/lib/i686/opencv_ffmpeg248_64.dll new file mode 100644 index 0000000000..b1e70df6a3 Binary files /dev/null and b/Core/release/modules/lib/i686/opencv_ffmpeg248_64.dll differ diff --git a/Core/release/modules/lib/i686/opencv_java248.dll b/Core/release/modules/lib/i686/opencv_java248.dll new file mode 100644 index 0000000000..f1c1bc9a43 Binary files /dev/null and b/Core/release/modules/lib/i686/opencv_java248.dll differ diff --git a/Core/release/modules/lib/x86/opencv_ffmpeg248.dll b/Core/release/modules/lib/x86/opencv_ffmpeg248.dll new file mode 100644 index 0000000000..b1e70df6a3 Binary files /dev/null and b/Core/release/modules/lib/x86/opencv_ffmpeg248.dll differ diff --git a/Core/release/modules/lib/x86/opencv_java248.dll b/Core/release/modules/lib/x86/opencv_java248.dll new file mode 100644 index 0000000000..f1c1bc9a43 Binary files /dev/null and b/Core/release/modules/lib/x86/opencv_java248.dll differ diff --git a/Core/release/modules/lib/x86_64/opencv_ffmpeg248_64.dll b/Core/release/modules/lib/x86_64/opencv_ffmpeg248_64.dll new file mode 100644 index 0000000000..37236e5424 Binary files /dev/null and b/Core/release/modules/lib/x86_64/opencv_ffmpeg248_64.dll differ diff --git a/Core/release/modules/lib/x86_64/opencv_java248.dll b/Core/release/modules/lib/x86_64/opencv_java248.dll new file mode 100644 index 0000000000..ab989a6b11 Binary files /dev/null and b/Core/release/modules/lib/x86_64/opencv_java248.dll differ diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java index 2568ba2936..73121b13dc 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java @@ -31,12 +31,14 @@ import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.TskCoreException; /** - * Instances of this Action allow users to apply tags to blackboard artifacts. + * Instances of this Action allow users to apply tags to blackboard artifacts. */ public class AddBlackboardArtifactTagAction extends AddTagAction { + // This class is a singleton to support multi-selection of nodes, since // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every // node in the array returns a reference to the same action object from Node.getActions(boolean). + private static AddBlackboardArtifactTagAction instance; public static synchronized AddBlackboardArtifactTagAction getInstance() { @@ -49,13 +51,13 @@ public class AddBlackboardArtifactTagAction extends AddTagAction { private AddBlackboardArtifactTagAction() { super(""); } - + @Override protected String getActionDisplayName() { String singularTagResult = NbBundle.getMessage(this.getClass(), - "AddBlackboardArtifactTagAction.singularTagResult"); + "AddBlackboardArtifactTagAction.singularTagResult"); String pluralTagResult = NbBundle.getMessage(this.getClass(), - "AddBlackboardArtifactTagAction.pluralTagResult"); + "AddBlackboardArtifactTagAction.pluralTagResult"); return Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class).size() > 1 ? pluralTagResult : singularTagResult; } @@ -65,17 +67,16 @@ public class AddBlackboardArtifactTagAction extends AddTagAction { for (BlackboardArtifact artifact : selectedArtifacts) { try { Case.getCurrentCase().getServices().getTagsManager().addBlackboardArtifactTag(artifact, tagName, comment); - } - catch (TskCoreException ex) { + } catch (TskCoreException ex) { Logger.getLogger(AddBlackboardArtifactTagAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex); //NON-NLS JOptionPane.showMessageDialog(null, - NbBundle.getMessage(this.getClass(), - "AddBlackboardArtifactTagAction.unableToTag.msg", - artifact.getDisplayName()), - NbBundle.getMessage(this.getClass(), - "AddBlackboardArtifactTagAction.taggingErr"), - JOptionPane.ERROR_MESSAGE); - } - } - } + NbBundle.getMessage(this.getClass(), + "AddBlackboardArtifactTagAction.unableToTag.msg", + artifact.getDisplayName()), + NbBundle.getMessage(this.getClass(), + "AddBlackboardArtifactTagAction.taggingErr"), + JOptionPane.ERROR_MESSAGE); + } + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java index cff35af7c1..47c0f69c0c 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,13 +22,11 @@ import java.util.Collection; import java.util.List; import java.util.logging.Level; import javax.swing.JOptionPane; - import org.openide.util.NbBundle; import org.openide.util.Utilities; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; @@ -36,9 +34,10 @@ import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; /** - * Instances of this Action allow users to apply tags to content. + * Instances of this Action allow users to apply tags to content. */ -public class AddContentTagAction extends AddTagAction { +public class AddContentTagAction extends AddTagAction { + // This class is a singleton to support multi-selection of nodes, since // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every // node in the array returns a reference to the same action object from Node.getActions(boolean). @@ -54,7 +53,7 @@ public class AddContentTagAction extends AddTagAction { private AddContentTagAction() { super(""); } - + @Override protected String getActionDisplayName() { String singularTagFile = NbBundle.getMessage(this.getClass(), "AddContentTagAction.singularTagFile"); @@ -68,77 +67,67 @@ public class AddContentTagAction extends AddTagAction { for (AbstractFile file : selectedFiles) { try { // Handle the special cases of current (".") and parent ("..") directory entries. - if (file.getName().equals(".")) { - Content parentFile = file.getParent(); + if (".".equals(file.getName())) { + Content parentFile = file.getParent(); if (parentFile instanceof AbstractFile) { - file = (AbstractFile)parentFile; - } - else { + file = (AbstractFile) parentFile; + } else { JOptionPane.showMessageDialog(null, - NbBundle.getMessage(this.getClass(), - "AddContentTagAction.unableToTag.msg", - parentFile.getName()), - NbBundle.getMessage(this.getClass(), - "AddContentTagAction.cannotApplyTagErr"), - JOptionPane.WARNING_MESSAGE); + NbBundle.getMessage(this.getClass(), + "AddContentTagAction.unableToTag.msg", + parentFile.getName()), + NbBundle.getMessage(this.getClass(), + "AddContentTagAction.cannotApplyTagErr"), + JOptionPane.WARNING_MESSAGE); continue; } - } - else if (file.getName().equals("..")) { - Content parentFile = file.getParent(); + } else if ("..".equals(file.getName())) { + Content parentFile = file.getParent(); if (parentFile instanceof AbstractFile) { - parentFile = (AbstractFile)((AbstractFile)parentFile).getParent(); + parentFile = parentFile.getParent(); if (parentFile instanceof AbstractFile) { - file = (AbstractFile)parentFile; - } - else { + file = (AbstractFile) parentFile; + } else { JOptionPane.showMessageDialog(null, - NbBundle.getMessage(this.getClass(), - "AddContentTagAction.unableToTag.msg", - parentFile.getName()), - NbBundle.getMessage(this.getClass(), - "AddContentTagAction.cannotApplyTagErr"), - JOptionPane.WARNING_MESSAGE); + NbBundle.getMessage(this.getClass(), + "AddContentTagAction.unableToTag.msg", + parentFile.getName()), + NbBundle.getMessage(this.getClass(), + "AddContentTagAction.cannotApplyTagErr"), + JOptionPane.WARNING_MESSAGE); continue; } - } - else { + } else { JOptionPane.showMessageDialog(null, - NbBundle.getMessage(this.getClass(), - "AddContentTagAction.unableToTag.msg", - parentFile.getName()), - NbBundle.getMessage(this.getClass(), - "AddContentTagAction.cannotApplyTagErr"), - JOptionPane.WARNING_MESSAGE); + NbBundle.getMessage(this.getClass(), + "AddContentTagAction.unableToTag.msg", + parentFile.getName()), + NbBundle.getMessage(this.getClass(), + "AddContentTagAction.cannotApplyTagErr"), + JOptionPane.WARNING_MESSAGE); continue; - } + } } // check if the same tag is being added for the same abstract file. TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); List contentTagList = tagsManager.getContentTagsByContent(file); - for (ContentTag contentTag : contentTagList) { - if (contentTag.getName().getDisplayName().equals(tagName.getDisplayName())) { - JOptionPane.showMessageDialog(null, - NbBundle.getMessage(this.getClass(), - "AddContentTagAction.tagExists", - file.getName(), tagName.getDisplayName()), - NbBundle.getMessage(this.getClass(), - "AddContentTagAction.cannotApplyTagErr"), - JOptionPane.WARNING_MESSAGE); - return; - } + boolean alreadyTaggedWithTagName = contentTagList.stream() + .map(ContentTag::getName) + .filter(tagName::equals) + .findAny().isPresent(); + if (alreadyTaggedWithTagName) { + continue; //skip this file, it already has a tag with this TagName. } tagsManager.addContentTag(file, tagName, comment); - } - catch (TskCoreException ex) { + } catch (TskCoreException ex) { Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex); //NON-NLS JOptionPane.showMessageDialog(null, - NbBundle.getMessage(this.getClass(), - "AddContentTagAction.unableToTag.msg2", - file.getName()), - NbBundle.getMessage(this.getClass(), "AddContentTagAction.taggingErr"), - JOptionPane.ERROR_MESSAGE); - } - } + NbBundle.getMessage(this.getClass(), + "AddContentTagAction.unableToTag.msg2", + file.getName()), + NbBundle.getMessage(this.getClass(), "AddContentTagAction.taggingErr"), + JOptionPane.ERROR_MESSAGE); + } + } } -} \ No newline at end of file +} diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java index ac9e29fe59..beaea6dc1d 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java @@ -31,12 +31,14 @@ import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.TskCoreException; /** - * Instances of this Action allow users to delete tags applied to blackboard artifacts. + * Instances of this Action allow users to delete tags applied to blackboard + * artifacts. */ public class DeleteBlackboardArtifactTagAction extends AbstractAction { + private static final String MENU_TEXT = NbBundle.getMessage(DeleteBlackboardArtifactTagAction.class, - "DeleteBlackboardArtifactTagAction.deleteTags"); - + "DeleteBlackboardArtifactTagAction.deleteTags"); + // This class is a singleton to support multi-selection of nodes, since // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every // node in the array returns a reference to the same action object from Node.getActions(boolean). @@ -51,26 +53,24 @@ public class DeleteBlackboardArtifactTagAction extends AbstractAction { private DeleteBlackboardArtifactTagAction() { super(MENU_TEXT); - } - + } + @Override public void actionPerformed(ActionEvent event) { Collection selectedTags = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifactTag.class); for (BlackboardArtifactTag tag : selectedTags) { try { Case.getCurrentCase().getServices().getTagsManager().deleteBlackboardArtifactTag(tag); - } - catch (TskCoreException ex) { + } catch (TskCoreException ex) { Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); //NON-NLS JOptionPane.showMessageDialog(null, - NbBundle.getMessage(this.getClass(), - "DeleteBlackboardArtifactTagAction.unableToDelTag.msg", - tag.getName()), - NbBundle.getMessage(this.getClass(), - "DeleteBlackboardArtifactTagAction.tagDelErr"), - JOptionPane.ERROR_MESSAGE); - } - } - } -} - + NbBundle.getMessage(this.getClass(), + "DeleteBlackboardArtifactTagAction.unableToDelTag.msg", + tag.getName()), + NbBundle.getMessage(this.getClass(), + "DeleteBlackboardArtifactTagAction.tagDelErr"), + JOptionPane.ERROR_MESSAGE); + } + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java index c716311eea..88dac00654 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java @@ -31,12 +31,13 @@ import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TskCoreException; /** - * Instances of this Action allow users to delete tags applied to content. + * Instances of this Action allow users to delete tags applied to content. */ public class DeleteContentTagAction extends AbstractAction { + private static final String MENU_TEXT = NbBundle.getMessage(DeleteContentTagAction.class, - "DeleteContentTagAction.deleteTags"); - + "DeleteContentTagAction.deleteTags"); + // This class is a singleton to support multi-selection of nodes, since // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every // node in the array returns a reference to the same action object from Node.getActions(boolean). @@ -51,24 +52,23 @@ public class DeleteContentTagAction extends AbstractAction { private DeleteContentTagAction() { super(MENU_TEXT); - } - + } + @Override public void actionPerformed(ActionEvent e) { Collection selectedTags = Utilities.actionsGlobalContext().lookupAll(ContentTag.class); for (ContentTag tag : selectedTags) { try { Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(tag); - } - catch (TskCoreException ex) { + } catch (TskCoreException ex) { Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); //NON-NLS JOptionPane.showMessageDialog(null, - NbBundle.getMessage(this.getClass(), - "DeleteContentTagAction.unableToDelTag.msg", - tag.getName()), - NbBundle.getMessage(this.getClass(), "DeleteContentTagAction.tagDelErr"), - JOptionPane.ERROR_MESSAGE); - } - } - } + NbBundle.getMessage(this.getClass(), + "DeleteContentTagAction.unableToDelTag.msg", + tag.getName()), + NbBundle.getMessage(this.getClass(), "DeleteContentTagAction.tagDelErr"), + JOptionPane.ERROR_MESSAGE); + } + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java index 21c8dfc154..fe1dc07968 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java @@ -40,12 +40,14 @@ import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; public class GetTagNameAndCommentDialog extends JDialog { + private static final String NO_TAG_NAMES_MESSAGE = NbBundle.getMessage(GetTagNameAndCommentDialog.class, - "GetTagNameAndCommentDialog.noTags"); + "GetTagNameAndCommentDialog.noTags"); private final HashMap tagNames = new HashMap<>(); private TagNameAndComment tagNameAndComment = null; public static class TagNameAndComment { + private TagName tagName; private String comment; @@ -53,7 +55,7 @@ public class GetTagNameAndCommentDialog extends JDialog { this.tagName = tagName; this.comment = comment; } - + public TagName getTagName() { return tagName; } @@ -62,16 +64,16 @@ public class GetTagNameAndCommentDialog extends JDialog { return comment; } } - + public static TagNameAndComment doDialog() { GetTagNameAndCommentDialog dialog = new GetTagNameAndCommentDialog(); return dialog.tagNameAndComment; } - + private GetTagNameAndCommentDialog() { - super((JFrame)WindowManager.getDefault().getMainWindow(), - NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.createTag"), - true); + super((JFrame) WindowManager.getDefault().getMainWindow(), + NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.createTag"), + true); initComponents(); // Set up the dialog to close when Esc is pressed. @@ -85,32 +87,30 @@ public class GetTagNameAndCommentDialog extends JDialog { dispose(); } }); - + // Populate the combo box with the available tag names and save the // tag name DTOs to be enable to return the one the user selects. TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); List currentTagNames = null; try { - currentTagNames = tagsManager.getAllTagNames(); - } - catch (TskCoreException ex) { + currentTagNames = tagsManager.getAllTagNames(); + } catch (TskCoreException ex) { Logger.getLogger(GetTagNameAndCommentDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS - } + } if (null != currentTagNames && currentTagNames.isEmpty()) { tagCombo.addItem(NO_TAG_NAMES_MESSAGE); - } - else { + } else { for (TagName tagName : currentTagNames) { tagNames.put(tagName.getDisplayName(), tagName); tagCombo.addItem(tagName.getDisplayName()); - } + } } - + // Center and show the dialog box. - this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); + this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); setVisible(true); } - + /** * 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 @@ -216,7 +216,7 @@ public class GetTagNameAndCommentDialog extends JDialog { }// //GEN-END:initComponents private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed - tagNameAndComment = new TagNameAndComment(tagNames.get((String)tagCombo.getSelectedItem()), commentText.getText()); + tagNameAndComment = new TagNameAndComment(tagNames.get((String) tagCombo.getSelectedItem()), commentText.getText()); dispose(); }//GEN-LAST:event_okButtonActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java index 83813701e9..876d411699 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java @@ -43,6 +43,7 @@ import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; public class GetTagNameDialog extends JDialog { + private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS private final HashMap tagNames = new HashMap<>(); private TagName tagName = null; @@ -50,15 +51,15 @@ public class GetTagNameDialog extends JDialog { public static TagName doDialog() { GetTagNameDialog dialog = new GetTagNameDialog(); return dialog.tagName; - } - + } + private GetTagNameDialog() { - super((JFrame)WindowManager.getDefault().getMainWindow(), - NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.createTag"), - true); + super((JFrame) WindowManager.getDefault().getMainWindow(), + NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.createTag"), + true); setIconImage(ImageUtilities.loadImage(TAG_ICON_PATH)); initComponents(); - + // Set up the dialog to close when Esc is pressed. String cancelName = NbBundle.getMessage(this.getClass(), "GetTagNameDialog.cancelName"); InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); @@ -70,52 +71,51 @@ public class GetTagNameDialog extends JDialog { dispose(); } }); - + // Get the current set of tag names and hash them for a speedy lookup in // case the user chooses an existing tag name from the tag names table. TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); List currentTagNames = null; try { - currentTagNames = tagsManager.getAllTagNames(); - } - catch (TskCoreException ex) { + currentTagNames = tagsManager.getAllTagNames(); + } catch (TskCoreException ex) { Logger.getLogger(GetTagNameDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS - } + } if (null != currentTagNames) { for (TagName name : currentTagNames) { this.tagNames.put(name.getDisplayName(), name); - } - } - else { + } + } else { currentTagNames = new ArrayList<>(); } - + // Populate the tag names table. tagsTable.setModel(new TagsTableModel(currentTagNames)); tagsTable.setTableHeader(null); tagsTable.setCellSelectionEnabled(false); tagsTable.setFocusable(false); tagsTable.setRowHeight(tagsTable.getRowHeight() + 5); - + // Center and show the dialog box. - this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); + this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); setVisible(true); } - + private boolean containsIllegalCharacters(String content) { - return (content.contains("\\")|| - content.contains(":") || - content.contains("*") || - content.contains("?") || - content.contains("\"")|| - content.contains("<") || - content.contains(">") || - content.contains("|")); + return (content.contains("\\") + || content.contains(":") + || content.contains("*") + || content.contains("?") + || content.contains("\"") + || content.contains("<") + || content.contains(">") + || content.contains("|")); } - private class TagsTableModel extends AbstractTableModel { + private class TagsTableModel extends AbstractTableModel { + private final ArrayList tagNames = new ArrayList<>(); - + TagsTableModel(List tagNames) { for (TagName tagName : tagNames) { this.tagNames.add(tagName); @@ -142,7 +142,7 @@ public class GetTagNameDialog extends JDialog { return tagNames.get(rowIndex).getDisplayName(); } } - + /** * 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 @@ -280,46 +280,41 @@ public class GetTagNameDialog extends JDialog { String tagDisplayName = tagNameField.getText(); if (tagDisplayName.isEmpty()) { JOptionPane.showMessageDialog(null, - NbBundle.getMessage(this.getClass(), - "GetTagNameDialog.mustSupplyTtagName.msg"), - NbBundle.getMessage(this.getClass(), "GetTagNameDialog.tagNameErr"), - JOptionPane.ERROR_MESSAGE); - } - else if (containsIllegalCharacters(tagDisplayName)) { + NbBundle.getMessage(this.getClass(), + "GetTagNameDialog.mustSupplyTtagName.msg"), + NbBundle.getMessage(this.getClass(), "GetTagNameDialog.tagNameErr"), + JOptionPane.ERROR_MESSAGE); + } else if (containsIllegalCharacters(tagDisplayName)) { JOptionPane.showMessageDialog(null, - NbBundle.getMessage(this.getClass(), "GetTagNameDialog.illegalChars.msg"), - NbBundle.getMessage(this.getClass(), "GetTagNameDialog.illegalCharsErr"), - JOptionPane.ERROR_MESSAGE); - } - else { + NbBundle.getMessage(this.getClass(), "GetTagNameDialog.illegalChars.msg"), + NbBundle.getMessage(this.getClass(), "GetTagNameDialog.illegalCharsErr"), + JOptionPane.ERROR_MESSAGE); + } else { tagName = tagNames.get(tagDisplayName); if (tagName == null) { try { tagName = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName); dispose(); - } - catch (TskCoreException ex) { + } catch (TskCoreException ex) { Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex); //NON-NLS JOptionPane.showMessageDialog(null, - NbBundle.getMessage(this.getClass(), - "GetTagNameDialog.unableToAddTagNameToCase.msg", - tagDisplayName), - NbBundle.getMessage(this.getClass(), "GetTagNameDialog.taggingErr"), - JOptionPane.ERROR_MESSAGE); + NbBundle.getMessage(this.getClass(), + "GetTagNameDialog.unableToAddTagNameToCase.msg", + tagDisplayName), + NbBundle.getMessage(this.getClass(), "GetTagNameDialog.taggingErr"), + JOptionPane.ERROR_MESSAGE); tagName = null; - } - catch (TagsManager.TagNameAlreadyExistsException ex) { + } catch (TagsManager.TagNameAlreadyExistsException ex) { Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex); //NON-NLS JOptionPane.showMessageDialog(null, - NbBundle.getMessage(this.getClass(), - "GetTagNameDialog.tagNameAlreadyDef.msg", - tagDisplayName), - NbBundle.getMessage(this.getClass(), "GetTagNameDialog.dupTagErr"), - JOptionPane.ERROR_MESSAGE); + NbBundle.getMessage(this.getClass(), + "GetTagNameDialog.tagNameAlreadyDef.msg", + tagDisplayName), + NbBundle.getMessage(this.getClass(), "GetTagNameDialog.dupTagErr"), + JOptionPane.ERROR_MESSAGE); tagName = null; } - } - else { + } else { dispose(); } } @@ -349,4 +344,3 @@ public class GetTagNameDialog extends JDialog { // End of variables declaration//GEN-END:variables } - diff --git a/Core/src/org/sleuthkit/autopsy/actions/OpenLogFolderAction.java b/Core/src/org/sleuthkit/autopsy/actions/OpenLogFolderAction.java index a1edbe0bd7..014d2d4299 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/OpenLogFolderAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/OpenLogFolderAction.java @@ -33,7 +33,6 @@ import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; - /** * Action in menu to open the folder containing the log files */ @@ -49,13 +48,12 @@ public final class OpenLogFolderAction implements ActionListener { File logDir; if (Case.isCaseOpen()) { logDir = new File(Case.getCurrentCase().getLogDirectoryPath()); - } - else { + } else { logDir = new File(Places.getUserDirectory().getAbsolutePath() + File.separator + "var" + File.separator + "log"); } if (logDir.exists() == false) { - NotifyDescriptor d = - new NotifyDescriptor.Message( + NotifyDescriptor d + = new NotifyDescriptor.Message( NbBundle.getMessage(this.getClass(), "OpenLogFolder.error1", logDir.getAbsolutePath()), NotifyDescriptor.ERROR_MESSAGE); DialogDisplayer.getDefault().notify(d); diff --git a/Core/src/org/sleuthkit/autopsy/actions/ShowIngestProgressSnapshotAction.java b/Core/src/org/sleuthkit/autopsy/actions/ShowIngestProgressSnapshotAction.java index 9a9e1995e3..b769e1e84c 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/ShowIngestProgressSnapshotAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/ShowIngestProgressSnapshotAction.java @@ -35,7 +35,7 @@ import org.sleuthkit.autopsy.ingest.IngestProgressSnapshotDialog; ) @ActionRegistration( displayName = "#CTL_ShowIngestProgressSnapshotAction", - lazy=false + lazy = false ) @ActionReference(path = "Menu/Help", position = 1125) @Messages("CTL_ShowIngestProgressSnapshotAction=Ingest Status Details") diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java index 363a7f8824..ee30eb8283 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.casemodule; import java.awt.Component; @@ -44,8 +43,9 @@ import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.Image; /** - * The action to add an image to the current Case. This action should be disabled - * on creation and it will be enabled on new case creation or case opened. + * The action to add an image to the current Case. This action should be + * disabled on creation and it will be enabled on new case creation or case + * opened. * * @author jantonius */ @@ -73,7 +73,6 @@ public final class AddImageAction extends CallableSystemAction implements Presen // boolean: whether or not to skip processing orphan files on FAT filesystems static final String NOFATORPHANS_PROP = "nofatorphans"; //NON-NLS - static final Logger logger = Logger.getLogger(AddImageAction.class.getName()); private WizardDescriptor wizardDescriptor; @@ -101,7 +100,7 @@ public final class AddImageAction extends CallableSystemAction implements Presen /** * Pop-up the "Add Image" wizard panel. - * + * * @param e */ @Override @@ -109,9 +108,9 @@ public final class AddImageAction extends CallableSystemAction implements Presen if (IngestManager.getInstance().isIngestRunning()) { final String msg = NbBundle.getMessage(this.getClass(), "AddImageAction.ingestConfig.ongoingIngest.msg"); if (JOptionPane.showConfirmDialog(null, msg, - NbBundle.getMessage(this.getClass(), - "AddImageAction.ingestConfig.ongoingIngest.title"), - JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.NO_OPTION) { + NbBundle.getMessage(this.getClass(), + "AddImageAction.ingestConfig.ongoingIngest.title"), + JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.NO_OPTION) { return; } } @@ -127,12 +126,12 @@ public final class AddImageAction extends CallableSystemAction implements Presen dialog = DialogDisplayer.getDefault().createDialog(wizardDescriptor); dialog.setVisible(true); dialog.toFront(); - + // Do any cleanup that needs to happen (potentially: stopping the //add-image process, reverting an image) runCleanupTasks(); - } - + } + /** * Closes the current dialog and wizard, and opens a new one. Used in the * "Add another image" action on the last panel @@ -144,22 +143,24 @@ public final class AddImageAction extends CallableSystemAction implements Presen // let the previous call to AddImageAction.actionPerformed() finish up // after the wizard, this will run when its it's done - final Runnable r = new Runnable() { + final Runnable r = new Runnable() { @Override public void run() { actionPerformed(null); } }; - + SwingUtilities.invokeLater(r); } - + public interface IndexImageTask { + void runTask(Image newImage); } /** - * This method does nothing. Use the "actionPerformed(ActionEvent e)" instead of this method. + * This method does nothing. Use the "actionPerformed(ActionEvent e)" + * instead of this method. */ @Override public void performAction() { @@ -187,8 +188,8 @@ public final class AddImageAction extends CallableSystemAction implements Presen /** * Returns the toolbar component of this action - * - * @return component the toolbar button + * + * @return component the toolbar button */ @Override public Component getToolbarPresenter() { @@ -201,7 +202,7 @@ public final class AddImageAction extends CallableSystemAction implements Presen /** * Set this action to be enabled/disabled * - * @param value whether to enable this action or not + * @param value whether to enable this action or not */ @Override public void setEnabled(boolean value) { @@ -216,7 +217,7 @@ public final class AddImageAction extends CallableSystemAction implements Presen * "Cancel", and "Finish". If you change the name of any of those buttons, * use the latest name instead. * - * @param buttonText the text of the button + * @param buttonText the text of the button */ public void requestFocusButton(String buttonText) { // get all buttons on this wizard panel @@ -229,7 +230,7 @@ public final class AddImageAction extends CallableSystemAction implements Presen } } } - + /** * Run and clear any cleanup tasks for wizard closing that might be * registered. This should be run even when the wizard exits cleanly, so @@ -238,16 +239,16 @@ public final class AddImageAction extends CallableSystemAction implements Presen private void runCleanupTasks() { cleanupSupport.fireChange(); } - + ChangeSupport cleanupSupport = new ChangeSupport(this); /** * Instances of this class implement the cleanup() method to run cleanup * code when the wizard exits. - * + * * After enable() has been called on an instance it will run once after the * wizard closes (on both a cancel and a normal finish). - * + * * If disable() is called before the wizard exits, the task will not run. */ abstract class CleanupTask implements ChangeListener { @@ -274,7 +275,8 @@ public final class AddImageAction extends CallableSystemAction implements Presen /** * Performs cleanup action when called - * @throws Exception + * + * @throws Exception */ abstract void cleanup() throws Exception; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageErrorsDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageErrorsDialog.java index d0f2d3fa65..742cb1750c 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageErrorsDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageErrorsDialog.java @@ -21,7 +21,7 @@ package org.sleuthkit.autopsy.casemodule; /** * Dialog to show add image error messages */ - public class AddImageErrorsDialog extends javax.swing.JDialog { +public class AddImageErrorsDialog extends javax.swing.JDialog { /** * Creates new form AddImageErrorsDialog diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java index 3c3e647cb4..a00117178e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java @@ -16,10 +16,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.casemodule; - import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -39,282 +37,278 @@ import org.sleuthkit.datamodel.TskDataException; import org.sleuthkit.datamodel.TskException; /* - * A background task that adds the given image to - * database using the Sleuthkit JNI interface. - * + * A background task that adds the given image to database using the Sleuthkit + * JNI interface. + * * It updates the given ProgressMonitor as it works through adding the image, * and et the end, calls the specified Callback. */ - class AddImageTask implements Runnable { +class AddImageTask implements Runnable { - private final Logger logger = Logger.getLogger(AddImageTask.class.getName()); - - private final Case currentCase; - - // true if the process was requested to cancel - private final Object lock = new Object(); // synchronization object for cancelRequested - private volatile boolean cancelRequested = false; - - //true if revert has been invoked. - private boolean reverted = false; - - // true if there was a critical error in adding the data source - private boolean hasCritError = false; - - private final List errorList = new ArrayList<>(); - - private final DataSourceProcessorProgressMonitor progressMonitor; - private final DataSourceProcessorCallback callbackObj; - - private final List newContents = Collections.synchronizedList(new ArrayList()); - - private SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess; - private Thread dirFetcher; - - private final String imagePath; - String timeZone; - boolean noFatOrphans; - - /* - * A thread that updates the progressMonitor with the name of the - * directory currently being processed by the AddImageTask - */ - private class CurrentDirectoryFetcher implements Runnable { + private final Logger logger = Logger.getLogger(AddImageTask.class.getName()); - DataSourceProcessorProgressMonitor progressMonitor; - SleuthkitJNI.CaseDbHandle.AddImageProcess process; + private final Case currentCase; - CurrentDirectoryFetcher(DataSourceProcessorProgressMonitor aProgressMonitor, SleuthkitJNI.CaseDbHandle.AddImageProcess proc) { - this.progressMonitor = aProgressMonitor; - this.process = proc; - } + // true if the process was requested to cancel + private final Object lock = new Object(); // synchronization object for cancelRequested + private volatile boolean cancelRequested = false; - /** - * @return the currently processing directory - */ - @Override - public void run() { - try { - while (!Thread.currentThread().isInterrupted()) { - String currDir = process.currentDirectory(); - if (currDir != null) { - if (!currDir.isEmpty() ) { - progressMonitor.setProgressText( - NbBundle.getMessage(this.getClass(), "AddImageTask.run.progress.adding", - currDir)); - } - } - // this sleep here prevents the UI from locking up - // due to too frequent updates to the progressMonitor above - Thread.sleep(500); - } - } catch (InterruptedException ie) { - // nothing to do, thread was interrupted externally - // signaling the end of AddImageProcess - } - } - } - - public AddImageTask(String imgPath, String tz, boolean noOrphans, DataSourceProcessorProgressMonitor aProgressMonitor, DataSourceProcessorCallback cbObj ) { - - currentCase = Case.getCurrentCase(); - - this.imagePath = imgPath; - this.timeZone = tz; - this.noFatOrphans = noOrphans; - - this.callbackObj = cbObj; + //true if revert has been invoked. + private boolean reverted = false; + + // true if there was a critical error in adding the data source + private boolean hasCritError = false; + + private final List errorList = new ArrayList<>(); + + private final DataSourceProcessorProgressMonitor progressMonitor; + private final DataSourceProcessorCallback callbackObj; + + private final List newContents = Collections.synchronizedList(new ArrayList()); + + private SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess; + private Thread dirFetcher; + + private final String imagePath; + String timeZone; + boolean noFatOrphans; + + /* + * A thread that updates the progressMonitor with the name of the directory + * currently being processed by the AddImageTask + */ + private class CurrentDirectoryFetcher implements Runnable { + + DataSourceProcessorProgressMonitor progressMonitor; + SleuthkitJNI.CaseDbHandle.AddImageProcess process; + + CurrentDirectoryFetcher(DataSourceProcessorProgressMonitor aProgressMonitor, SleuthkitJNI.CaseDbHandle.AddImageProcess proc) { this.progressMonitor = aProgressMonitor; + this.process = proc; } /** - * Starts the addImage process, but does not commit the results. - * - * @return - * - * @throws Exception + * @return the currently processing directory */ @Override - public void run() { - errorList.clear(); + public void run() { try { - currentCase.getSleuthkitCase().acquireExclusiveLock(); - addImageProcess = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans); - dirFetcher = new Thread( new CurrentDirectoryFetcher(progressMonitor, addImageProcess)); - try { - progressMonitor.setIndeterminate(true); - progressMonitor.setProgress(0); - dirFetcher.start(); - addImageProcess.run(new String[]{this.imagePath}); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Core errors occurred while running add image. ", ex); //NON-NLS - hasCritError = true; - errorList.add(ex.getMessage()); - } catch (TskDataException ex) { - logger.log(Level.WARNING, "Data errors occurred while running add image. ", ex); //NON-NLS - errorList.add(ex.getMessage()); - } - postProcess(); - } finally { - currentCase.getSleuthkitCase().releaseExclusiveLock(); - } - } - - /** - * Commit the newly added image to DB - * - * - * @throws Exception if commit or adding the image to the case failed - */ - private void commitImage() throws Exception { - - long imageId = 0; - try { - imageId = addImageProcess.commit(); - } catch (TskCoreException e) { - logger.log(Level.WARNING, "Errors occured while committing the image", e); //NON-NLS - errorList.add(e.getMessage()); - } finally { - if (imageId != 0) { - // get the newly added Image so we can return to caller - Image newImage = currentCase.getSleuthkitCase().getImageById(imageId); - - //while we have the image, verify the size of its contents - String verificationErrors = newImage.verifyImageSize(); - if (verificationErrors.equals("") == false) { - //data error (non-critical) - errorList.add(verificationErrors); - } - - // Add the image to the list of new content - newContents.add(newImage); - } - - logger.log(Level.INFO, "Image committed, imageId: {0}", imageId); //NON-NLS - logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo()); - } - } - - /** - * Post processing after the addImageProcess is done. - * - */ - private void postProcess() { - - // cancel the directory fetcher - dirFetcher.interrupt(); - - if (cancelRequested() || hasCritError) { - logger.log(Level.WARNING, "Critical errors or interruption in add image process. Image will not be committed."); //NON-NLS - revert(); - } - - if (!errorList.isEmpty()) { - logger.log(Level.INFO, "There were errors that occured in add image process"); //NON-NLS - } - - // When everything happens without an error: - if (!(cancelRequested() || hasCritError)) { - try { - if (addImageProcess != null) { - // commit image - try { - commitImage(); - } catch (Exception ex) { - errorList.add(ex.getMessage()); - // Log error/display warning - logger.log(Level.SEVERE, "Error adding image to case.", ex); //NON-NLS + while (!Thread.currentThread().isInterrupted()) { + String currDir = process.currentDirectory(); + if (currDir != null) { + if (!currDir.isEmpty()) { + progressMonitor.setProgressText( + NbBundle.getMessage(this.getClass(), "AddImageTask.run.progress.adding", + currDir)); } - } else { - logger.log(Level.SEVERE, "Missing image process object"); //NON-NLS } - - // Tell the progress monitor we're done - progressMonitor.setProgress(100); - } catch (Exception ex) { - //handle unchecked exceptions post image add - errorList.add(ex.getMessage()); - - logger.log(Level.WARNING, "Unexpected errors occurred while running post add image cleanup. ", ex); //NON-NLS - logger.log(Level.SEVERE, "Error adding image to case", ex); //NON-NLS - } - } - - // invoke the callBack, unless the caller cancelled - if (!cancelRequested()) { - doCallBack(); - } - } - - /* - * Call the callback with results, new content, and errors, if any - */ - private void doCallBack() - { - DataSourceProcessorCallback.DataSourceProcessorResult result; - - if (hasCritError) { - result = DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS; - } - else if (!errorList.isEmpty()) { - result = DataSourceProcessorCallback.DataSourceProcessorResult.NONCRITICAL_ERRORS; - } - else { - result = DataSourceProcessorCallback.DataSourceProcessorResult.NO_ERRORS; - } - - // invoke the callback, passing it the result, list of new contents, and list of errors - callbackObj.done(result, errorList, newContents); - } - - /* - * cancel the image addition, if possible - */ - public void cancelTask() { - - synchronized (lock) { - cancelRequested = true; - try { - interrupt(); + // this sleep here prevents the UI from locking up + // due to too frequent updates to the progressMonitor above + Thread.sleep(500); } - catch (Exception ex) { - logger.log(Level.SEVERE, "Failed to interrupt the add image task..."); //NON-NLS - } - } - } - - /* - * Interrupt the add image process if it is still running - */ - private void interrupt() throws Exception { - - try { - logger.log(Level.INFO, "interrupt() add image process"); //NON-NLS - addImageProcess.stop(); //it might take time to truly stop processing and writing to db - } catch (TskCoreException ex) { - throw new Exception(NbBundle.getMessage(this.getClass(), "AddImageTask.interrupt.exception.msg"), ex); - } - } - - /* - * Revert - if image has already been added but not committed yet - */ - private void revert() { - - if (!reverted) { - logger.log(Level.INFO, "Revert after add image process"); //NON-NLS - try { - addImageProcess.revert(); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error reverting add image process", ex); //NON-NLS - } - reverted = true; - } - } - - private boolean cancelRequested() { - synchronized (lock) { - return cancelRequested; + } catch (InterruptedException ie) { + // nothing to do, thread was interrupted externally + // signaling the end of AddImageProcess } } } + + public AddImageTask(String imgPath, String tz, boolean noOrphans, DataSourceProcessorProgressMonitor aProgressMonitor, DataSourceProcessorCallback cbObj) { + + currentCase = Case.getCurrentCase(); + + this.imagePath = imgPath; + this.timeZone = tz; + this.noFatOrphans = noOrphans; + + this.callbackObj = cbObj; + this.progressMonitor = aProgressMonitor; + } + + /** + * Starts the addImage process, but does not commit the results. + * + * @return + * + * @throws Exception + */ + @Override + public void run() { + errorList.clear(); + try { + currentCase.getSleuthkitCase().acquireExclusiveLock(); + addImageProcess = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans); + dirFetcher = new Thread(new CurrentDirectoryFetcher(progressMonitor, addImageProcess)); + try { + progressMonitor.setIndeterminate(true); + progressMonitor.setProgress(0); + dirFetcher.start(); + addImageProcess.run(new String[]{this.imagePath}); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Core errors occurred while running add image. ", ex); //NON-NLS + hasCritError = true; + errorList.add(ex.getMessage()); + } catch (TskDataException ex) { + logger.log(Level.WARNING, "Data errors occurred while running add image. ", ex); //NON-NLS + errorList.add(ex.getMessage()); + } + postProcess(); + } finally { + currentCase.getSleuthkitCase().releaseExclusiveLock(); + } + } + + /** + * Commit the newly added image to DB + * + * + * @throws Exception if commit or adding the image to the case failed + */ + private void commitImage() throws Exception { + + long imageId = 0; + try { + imageId = addImageProcess.commit(); + } catch (TskCoreException e) { + logger.log(Level.WARNING, "Errors occured while committing the image", e); //NON-NLS + errorList.add(e.getMessage()); + } finally { + if (imageId != 0) { + // get the newly added Image so we can return to caller + Image newImage = currentCase.getSleuthkitCase().getImageById(imageId); + + //while we have the image, verify the size of its contents + String verificationErrors = newImage.verifyImageSize(); + if (verificationErrors.equals("") == false) { + //data error (non-critical) + errorList.add(verificationErrors); + } + + // Add the image to the list of new content + newContents.add(newImage); + } + + logger.log(Level.INFO, "Image committed, imageId: {0}", imageId); //NON-NLS + logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo()); + } + } + + /** + * Post processing after the addImageProcess is done. + * + */ + private void postProcess() { + + // cancel the directory fetcher + dirFetcher.interrupt(); + + if (cancelRequested() || hasCritError) { + logger.log(Level.WARNING, "Critical errors or interruption in add image process. Image will not be committed."); //NON-NLS + revert(); + } + + if (!errorList.isEmpty()) { + logger.log(Level.INFO, "There were errors that occured in add image process"); //NON-NLS + } + + // When everything happens without an error: + if (!(cancelRequested() || hasCritError)) { + try { + if (addImageProcess != null) { + // commit image + try { + commitImage(); + } catch (Exception ex) { + errorList.add(ex.getMessage()); + // Log error/display warning + logger.log(Level.SEVERE, "Error adding image to case.", ex); //NON-NLS + } + } else { + logger.log(Level.SEVERE, "Missing image process object"); //NON-NLS + } + + // Tell the progress monitor we're done + progressMonitor.setProgress(100); + } catch (Exception ex) { + //handle unchecked exceptions post image add + errorList.add(ex.getMessage()); + + logger.log(Level.WARNING, "Unexpected errors occurred while running post add image cleanup. ", ex); //NON-NLS + logger.log(Level.SEVERE, "Error adding image to case", ex); //NON-NLS + } + } + + // invoke the callBack, unless the caller cancelled + if (!cancelRequested()) { + doCallBack(); + } + } + + /* + * Call the callback with results, new content, and errors, if any + */ + private void doCallBack() { + DataSourceProcessorCallback.DataSourceProcessorResult result; + + if (hasCritError) { + result = DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS; + } else if (!errorList.isEmpty()) { + result = DataSourceProcessorCallback.DataSourceProcessorResult.NONCRITICAL_ERRORS; + } else { + result = DataSourceProcessorCallback.DataSourceProcessorResult.NO_ERRORS; + } + + // invoke the callback, passing it the result, list of new contents, and list of errors + callbackObj.done(result, errorList, newContents); + } + + /* + * cancel the image addition, if possible + */ + public void cancelTask() { + + synchronized (lock) { + cancelRequested = true; + try { + interrupt(); + } catch (Exception ex) { + logger.log(Level.SEVERE, "Failed to interrupt the add image task..."); //NON-NLS + } + } + } + + /* + * Interrupt the add image process if it is still running + */ + private void interrupt() throws Exception { + + try { + logger.log(Level.INFO, "interrupt() add image process"); //NON-NLS + addImageProcess.stop(); //it might take time to truly stop processing and writing to db + } catch (TskCoreException ex) { + throw new Exception(NbBundle.getMessage(this.getClass(), "AddImageTask.interrupt.exception.msg"), ex); + } + } + + /* + * Revert - if image has already been added but not committed yet + */ + private void revert() { + + if (!reverted) { + logger.log(Level.INFO, "Revert after add image process"); //NON-NLS + try { + addImageProcess.revert(); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Error reverting add image process", ex); //NON-NLS + } + reverted = true; + } + } + + private boolean cancelRequested() { + synchronized (lock) { + return cancelRequested; + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java index 14920f7183..7204664d2f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.casemodule; - import java.awt.Color; import java.awt.EventQueue; import java.util.HashSet; @@ -55,48 +54,48 @@ class AddImageWizardAddingProgressPanel implements WizardDescriptor.FinishablePa private final Set listeners = new HashSet<>(1); // or can use ChangeSupport in NB 6.0 private DSPProgressMonitorImpl dspProgressMonitorImpl = new DSPProgressMonitorImpl(); - + public DSPProgressMonitorImpl getDSPProgressMonitorImpl() { return dspProgressMonitorImpl; } - + private class DSPProgressMonitorImpl implements DataSourceProcessorProgressMonitor { + @Override public void setIndeterminate(final boolean indeterminate) { - // update the progress bar asynchronously - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - getComponent().getProgressBar().setIndeterminate(indeterminate); - } - }); + // update the progress bar asynchronously + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + getComponent().getProgressBar().setIndeterminate(indeterminate); + } + }); } - + @Override - public void setProgress(final int progress) { - // update the progress bar asynchronously - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - getComponent().getProgressBar().setValue(progress); - } - }); + public void setProgress(final int progress) { + // update the progress bar asynchronously + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + getComponent().getProgressBar().setValue(progress); + } + }); } - + @Override public void setProgressText(final String text) { // update the progress UI asynchronously - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - getComponent().setProgressMsgText(text); - } - }); + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + getComponent().setProgressMsgText(text); + } + }); } - - - + } + /** * Get the visual component for the panel. In this template, the component * is kept separate. This can be more efficient: if the wizard is created diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressVisual.java index 6015b6fb14..3b6772637f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressVisual.java @@ -29,7 +29,7 @@ import org.openide.util.NbBundle; * visual component to display progress bar and status updates while adding an * image in the wizard */ - class AddImageWizardAddingProgressVisual extends javax.swing.JPanel { +class AddImageWizardAddingProgressVisual extends javax.swing.JPanel { private static final String ADDING_DATA_SOURCE_COMPLETE = NbBundle .getMessage(AddImageWizardAddingProgressVisual.class, "AddImageWizardAddingProgressVisual.addingDsComplete.text"); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java index 7bbf664e99..384f8f9cc3 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java @@ -53,12 +53,12 @@ class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel { - private IngestJobSettingsPanel ingestJobSettingsPanel; - + /** * The visual component that displays this panel. If you need to access the * component from this class, just use getComponent(). */ private Component component = null; - + private final List newContents = Collections.synchronizedList(new ArrayList()); private boolean ingested = false; private boolean readyToIngest = false; - + // task that will clean up the created database file if the wizard is cancelled before it finishes - private AddImageAction.CleanupTask cleanupTask; - + private AddImageAction.CleanupTask cleanupTask; + private final AddImageAction addImageAction; - + private final AddImageWizardAddingProgressPanel progressPanel; private final AddImageWizardChooseDataSourcePanel dataSourcePanel; - + private DataSourceProcessor dsProcessor; - AddImageWizardIngestConfigPanel(AddImageWizardChooseDataSourcePanel dsPanel, AddImageAction action, AddImageWizardAddingProgressPanel proPanel) { this.addImageAction = action; this.progressPanel = proPanel; this.dataSourcePanel = dsPanel; - - IngestJobSettings ingestJobSettings = new IngestJobSettings(AddImageWizardIngestConfigPanel.class.getCanonicalName()); + + IngestJobSettings ingestJobSettings = new IngestJobSettings(AddImageWizardIngestConfigPanel.class.getCanonicalName()); showWarnings(ingestJobSettings); this.ingestJobSettingsPanel = new IngestJobSettingsPanel(ingestJobSettings); } @@ -167,7 +166,7 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel errList, List contents) { - dataSourceProcessorDone(result, errList, contents ); + public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List errList, List contents) { + dataSourceProcessorDone(result, errList, contents); } - + }; - + progressPanel.setStateStarted(); - + // Kick off the DSProcessor dsProcessor.run(progressPanel.getDSPProgressMonitorImpl(), cbObj); - + } /* * Cancels the data source processing - in case the users presses 'Cancel' */ private void cancelDataSourceProcessing() { - dsProcessor.cancel(); + dsProcessor.cancel(); } - + /* - * Callback for the data source processor. - * Invoked by the DSP on the EDT thread, when it finishes processing the data source. + * Callback for the data source processor. Invoked by the DSP on the EDT + * thread, when it finishes processing the data source. */ - private void dataSourceProcessorDone(DataSourceProcessorCallback.DataSourceProcessorResult result, List errList, List contents) { - - // disable the cleanup task + private void dataSourceProcessorDone(DataSourceProcessorCallback.DataSourceProcessorResult result, List errList, List contents) { + + // disable the cleanup task cleanupTask.disable(); - + // Get attention for the process finish java.awt.Toolkit.getDefaultToolkit().beep(); //BEEP! AddImageWizardAddingProgressVisual panel = progressPanel.getComponent(); @@ -279,40 +277,38 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel> getPanels() { if (panels == null) { panels = new ArrayList>(); - + AddImageWizardAddingProgressPanel progressPanel = new AddImageWizardAddingProgressPanel(); - + AddImageWizardChooseDataSourcePanel dsPanel = new AddImageWizardChooseDataSourcePanel(progressPanel); AddImageWizardIngestConfigPanel ingestConfigPanel = new AddImageWizardIngestConfigPanel(dsPanel, action, progressPanel); - + panels.add(dsPanel); panels.add(ingestConfigPanel); panels.add(progressPanel); @@ -83,10 +82,10 @@ class AddImageWizardIterator implements WizardDescriptor.Iterator current() { @@ -109,18 +108,18 @@ class AddImageWizardIterator implements WizardDescriptor.Iterator reports, boolean deleteFromDisk) throws TskCoreException { + + String pathToReportsFolder = Paths.get(this.db.getDbDirPath(), "Reports").normalize().toString(); // NON-NLS + for (Report report : reports) { + + // delete from the database. + this.db.deleteReport(report); + + if (deleteFromDisk) { + // traverse to the root directory of Report report. + String reportPath = report.getPath(); + while (!Paths.get(reportPath, "..").normalize().toString().equals(pathToReportsFolder)) { // NON-NLS + reportPath = Paths.get(reportPath, "..").normalize().toString(); // NON-NLS + } + + // delete from the disk. + try { + FileUtils.deleteDirectory(new File(reportPath)); + } catch (IOException | SecurityException ex) { + logger.log(Level.WARNING, NbBundle.getMessage(Case.class, "Case.deleteReports.deleteFromDiskException.log.msg"), ex); + JOptionPane.showMessageDialog(null, NbBundle.getMessage(Case.class, "Case.deleteReports.deleteFromDiskException.msg", report.getReportName(), reportPath)); + } + } + + // fire property change event. + try { + Case.pcs.firePropertyChange(Events.REPORT_DELETED.toString(), null, null); + } catch (Exception ex) { + String errorMessage = String.format("A Case %s listener threw an exception", Events.REPORT_DELETED.toString()); //NON-NLS + logger.log(Level.SEVERE, errorMessage, ex); + } + } + } + /** * Returns if the case has data in it yet. * diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseCloseAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseCloseAction.java index 900a355bf0..5f953c7bf9 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseCloseAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseCloseAction.java @@ -16,31 +16,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.casemodule; import java.awt.Component; import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.logging.Level;import org.sleuthkit.autopsy.coreutils.Logger; -import javax.swing.Action; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import org.openide.util.HelpCtx; -import org.openide.util.NbBundle; -import org.openide.util.actions.CallableSystemAction; -import org.openide.util.actions.Presenter; -; -import org.sleuthkit.autopsy.coreutils.Logger; -import javax.swing.Action; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import org.openide.util.HelpCtx; -import org.openide.util.NbBundle; -import org.openide.util.actions.CallableSystemAction; -import org.openide.util.actions.Presenter; +import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import javax.swing.Action; import javax.swing.ImageIcon; import javax.swing.JButton; @@ -53,7 +37,7 @@ import org.openide.util.actions.Presenter; * The action to close the current Case. This class should be disabled on * creation and it will be enabled on new case creation or case opened. */ - final class CaseCloseAction extends CallableSystemAction implements Presenter.Toolbar{ +final class CaseCloseAction extends CallableSystemAction implements Presenter.Toolbar { JButton toolbarButton = new JButton(); @@ -79,14 +63,20 @@ import org.openide.util.actions.Presenter; /** * Closes the current opened case. * - * @param e the action event for this method + * @param e the action event for this method */ @Override public void actionPerformed(ActionEvent e) { - if (Case.existsCurrentCase() == false) + if (Case.existsCurrentCase() == false) { return; - + } + Case result = Case.getCurrentCase(); + + if (!MessageNotifyUtil.Message.confirm("Are you sure you want to close current case?")) { + return; + } + try { result.closeCase(); EventQueue.invokeLater(new Runnable() { @@ -101,7 +91,8 @@ import org.openide.util.actions.Presenter; } /** - * This method does nothing. Use the "actionPerformed(ActionEvent e)" instead of this method. + * This method does nothing. Use the "actionPerformed(ActionEvent e)" + * instead of this method. */ @Override public void performAction() { @@ -119,18 +110,18 @@ import org.openide.util.actions.Presenter; /** * Gets the HelpCtx associated with implementing object - * + * * @return HelpCtx or HelpCtx.DEFAULT_HELP */ @Override public HelpCtx getHelpCtx() { - return HelpCtx.DEFAULT_HELP; + return HelpCtx.DEFAULT_HELP; } /** * Returns the toolbar component of this action * - * @return component the toolbar button + * @return component the toolbar button */ @Override public Component getToolbarPresenter() { @@ -143,10 +134,10 @@ import org.openide.util.actions.Presenter; /** * Set this action to be enabled/disabled * - * @param value whether to enable this action or not + * @param value whether to enable this action or not */ @Override - public void setEnabled(boolean value){ + public void setEnabled(boolean value) { super.setEnabled(value); toolbarButton.setEnabled(value); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseConfigFileInterface.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseConfigFileInterface.java index 4a91bf9c1e..8b7964a76e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseConfigFileInterface.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseConfigFileInterface.java @@ -16,31 +16,37 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.casemodule; /** * NOTE: NOTHING ACTUALLY USES THIS - * + * * The interface for the classes that edit the case configuration file */ //TODO: check that this can just be deleted. interface CaseConfigFileInterface { + public void open(String conFilePath) throws Exception; // opens the confiuation store (XML, DB...) + public void writeFile() throws Exception; // writes out the configuration to store + public void close() throws Exception; // close and clear the document handler // public int[] getImageIDs() throws Exception; // returns a list of image IDs and names // public int getNextImageID() throws Exception; // returns the next free ID to be assigned to new image, and increments the internal counter // all the get and set methods public String getCaseName() throws Exception; // get the case name + public void setCaseName(String caseName) throws Exception; // set the case name + public String getCaseNumber() throws Exception; // get the case number + public void setCaseNumber(String caseNumber) throws Exception; // set the case number + public String getCaseExaminer() throws Exception; // get the examiner + public void setCaseExaminer(String examiner) throws Exception; // set the examiner // public void getXXX(); // methods to get the case attributes // public void setXXX(); // methods to set the case attributes - } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java index cff30efed0..54920ec79e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java @@ -16,12 +16,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.casemodule; import java.awt.event.ActionEvent; import java.io.File; -import java.util.logging.Level;import org.sleuthkit.autopsy.coreutils.Logger; +import java.util.logging.Level; +import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.Action; import javax.swing.JOptionPane; import javax.swing.JPanel; @@ -57,10 +57,12 @@ import org.openide.util.actions.CallableSystemAction; * The action to delete the current Case. This class should be disabled on * creation and it will be enabled on new case creation or case opened. */ - final class CaseDeleteAction extends CallableSystemAction { + + +final class CaseDeleteAction extends CallableSystemAction { private JPanel caller; // for error handling - + private static final Logger logger = Logger.getLogger(CaseDeleteAction.class.getName()); /** @@ -73,6 +75,7 @@ import org.openide.util.actions.CallableSystemAction; /** * Deletes the current opened case. + * * @param e */ @Override @@ -81,24 +84,23 @@ import org.openide.util.actions.CallableSystemAction; File configFile = new File(currentCase.getConfigFilePath()); File caseFolder = new File(configFile.getParent()); String caseName = currentCase.getName(); - if(!caseFolder.exists()){ + if (!caseFolder.exists()) { // throw an error - + logger.log(Level.WARNING, "Couldn't delete case.", new Exception("The case directory doesn't exist.")); //NON-NLS - } - else{ + } else { // show the confirmation first to close the current case and open the "New Case" wizard panel - String closeCurrentCase = NbBundle.getMessage(this.getClass(), "CaseDeleteAction.closeConfMsg.text", caseName, caseFolder.getPath()); + String closeCurrentCase = NbBundle.getMessage(this.getClass(), "CaseDeleteAction.closeConfMsg.text", caseName, caseFolder.getPath()); NotifyDescriptor d = new NotifyDescriptor.Confirmation(closeCurrentCase, - NbBundle.getMessage(this.getClass(), - "CaseDeleteAction.closeConfMsg.title"), - NotifyDescriptor.YES_NO_OPTION, NotifyDescriptor.WARNING_MESSAGE); + NbBundle.getMessage(this.getClass(), + "CaseDeleteAction.closeConfMsg.title"), + NotifyDescriptor.YES_NO_OPTION, NotifyDescriptor.WARNING_MESSAGE); d.setValue(NotifyDescriptor.NO_OPTION); Object res = DialogDisplayer.getDefault().notify(d); - if(res != null && res == DialogDescriptor.YES_OPTION){ + if (res != null && res == DialogDescriptor.YES_OPTION) { boolean success = false; - + try { Case.getCurrentCase().deleteCase(caseFolder); // delete the current case success = true; @@ -107,26 +109,26 @@ import org.openide.util.actions.CallableSystemAction; } // show notification whether the case has been deleted or it failed to delete... - if(!success){ + if (!success) { JOptionPane.showMessageDialog(caller, - NbBundle.getMessage(this.getClass(), - "CaseDeleteAction.msgDlg.fileInUse.msg"), - NbBundle.getMessage(this.getClass(), - "CaseDeleteAction.msgDlg.fileInUse.title"), - JOptionPane.ERROR_MESSAGE); // throw an error - } - else{ + NbBundle.getMessage(this.getClass(), + "CaseDeleteAction.msgDlg.fileInUse.msg"), + NbBundle.getMessage(this.getClass(), + "CaseDeleteAction.msgDlg.fileInUse.title"), + JOptionPane.ERROR_MESSAGE); // throw an error + } else { CasePropertiesAction.closeCasePropertiesWindow(); // because the "Delete Case" button is in the "CaseProperties" window, we have to close that window when we delete the case. JOptionPane.showMessageDialog(caller, NbBundle.getMessage(this.getClass(), - "CaseDeleteAction.msgDlg.caseDelete.msg", - caseName)); + "CaseDeleteAction.msgDlg.caseDelete.msg", + caseName)); } } } } /** - * This method does nothing. Use the "actionPerformed(ActionEvent e)" instead of this method. + * This method does nothing. Use the "actionPerformed(ActionEvent e)" + * instead of this method. */ @Override public void performAction() { @@ -135,6 +137,7 @@ import org.openide.util.actions.CallableSystemAction; /** * Gets the name of this action. This may be presented as an item in a menu. + * * @return actionName */ @Override @@ -144,6 +147,7 @@ import org.openide.util.actions.CallableSystemAction; /** * Gets the HelpCtx associated with implementing object + * * @return HelpCtx or HelpCtx.DEFAULT_HELP */ @Override diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseNewAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseNewAction.java index 3be5ec7c57..125063f4be 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseNewAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseNewAction.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.casemodule; import java.awt.event.ActionEvent; @@ -35,6 +34,7 @@ public final class CaseNewAction implements CaseNewActionInterface { /** * Calls the "New Case" wizard panel action. + * * @param e */ @Override diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseNewActionInterface.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseNewActionInterface.java index a99db1aab2..04791b8fcb 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseNewActionInterface.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseNewActionInterface.java @@ -16,8 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - - package org.sleuthkit.autopsy.casemodule; import java.awt.event.ActionListener; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java index 8bf7392026..f6bb0070dd 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java @@ -50,7 +50,7 @@ public final class CaseOpenAction implements ActionListener { public CaseOpenAction() { autFilter = new FileNameExtensionFilter( NbBundle.getMessage(CaseOpenAction.class, "CaseOpenAction.autFilter.title", Version.getName(), - Case.CASE_DOT_EXTENSION), + Case.CASE_DOT_EXTENSION), Case.CASE_EXTENSION); fc.setDragEnabled(false); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); @@ -80,11 +80,11 @@ public final class CaseOpenAction implements ActionListener { // check if the file exists if (!new File(path).exists()) { JOptionPane.showMessageDialog(null, - NbBundle.getMessage(this.getClass(), - "CaseOpenAction.msgDlg.fileNotExist.msg"), - NbBundle.getMessage(this.getClass(), - "CaseOpenAction.msgDlg.fileNotExist.title"), - JOptionPane.ERROR_MESSAGE); + NbBundle.getMessage(this.getClass(), + "CaseOpenAction.msgDlg.fileNotExist.msg"), + NbBundle.getMessage(this.getClass(), + "CaseOpenAction.msgDlg.fileNotExist.title"), + JOptionPane.ERROR_MESSAGE); this.actionPerformed(e); // show the dialog box again } else { // try to close Startup window if there's one @@ -98,12 +98,12 @@ public final class CaseOpenAction implements ActionListener { Case.open(path); // open the case } catch (CaseActionException ex) { JOptionPane.showMessageDialog(null, - NbBundle.getMessage(this.getClass(), - "CaseOpenAction.msgDlg.cantOpenCase.msg", path, - ex.getMessage()), - NbBundle.getMessage(this.getClass(), - "CaseOpenAction.msgDlg.cantOpenCase.title"), - JOptionPane.ERROR_MESSAGE); + NbBundle.getMessage(this.getClass(), + "CaseOpenAction.msgDlg.cantOpenCase.msg", path, + ex.getMessage()), + NbBundle.getMessage(this.getClass(), + "CaseOpenAction.msgDlg.cantOpenCase.title"), + JOptionPane.ERROR_MESSAGE); logger.log(Level.WARNING, "Error opening case in folder " + path, ex); //NON-NLS StartupWindowProvider.getInstance().open(); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesAction.java index 7254112e85..5cae020845 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesAction.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.casemodule; import java.awt.Dimension; @@ -40,7 +39,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; * * @author jantonius */ - final class CasePropertiesAction extends CallableSystemAction { +final class CasePropertiesAction extends CallableSystemAction { private static JDialog popUpWindow; @@ -64,12 +63,11 @@ import org.sleuthkit.autopsy.coreutils.Logger; final JFrame frame = new JFrame(title); popUpWindow = new JDialog(frame, title, true); // to make the popUp Window to be modal - // get the information that needed Case currentCase = Case.getCurrentCase(); String crDate = currentCase.getCreatedDate(); String caseDir = currentCase.getCaseDirectory(); - + // put the image paths information into hashmap Map imgPaths = Case.getImagePaths(currentCase.getSleuthkitCase()); @@ -104,6 +102,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; /** * Gets the name of this action. This may be presented as an item in a menu. + * * @return actionName */ @Override @@ -113,6 +112,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; /** * Gets the HelpCtx associated with implementing object + * * @return HelpCtx or HelpCtx.DEFAULT_HELP */ @Override diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java index 914e0bdf88..5a60ca75d7 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java @@ -22,7 +22,6 @@ * * Created on Mar 14, 2011, 1:48:20 PM */ - package org.sleuthkit.autopsy.casemodule; import java.awt.*; @@ -46,26 +45,26 @@ import org.openide.util.actions.CallableSystemAction; * * @author jantonius */ -class CasePropertiesForm extends javax.swing.JPanel{ +class CasePropertiesForm extends javax.swing.JPanel { Case current = null; private static JPanel caller; // panel for error - + // Shrink a path to fit in targetLength (if necessary), by replaceing part // of the path with "...". Ex: "C:\Users\bob\...\folder\other\Image.img" private String shrinkPath(String path, int targetLength) { - if(path.length() > targetLength){ + if (path.length() > targetLength) { String fill = "..."; - + int partsLength = targetLength - fill.length(); - - String front = path.substring(0, partsLength/4); + + String front = path.substring(0, partsLength / 4); int frontSep = front.lastIndexOf(File.separatorChar); if (frontSep != -1) { - front = front.substring(0, frontSep+1); + front = front.substring(0, frontSep + 1); } - - String back = path.substring(partsLength*3/4); + + String back = path.substring(partsLength * 3 / 4); int backSep = back.indexOf(File.separatorChar); if (backSep != -1) { back = back.substring(backSep); @@ -75,9 +74,10 @@ class CasePropertiesForm extends javax.swing.JPanel{ return path; } } - - - /** Creates new form CasePropertiesForm */ + + /** + * Creates new form CasePropertiesForm + */ CasePropertiesForm(Case currentCase, String crDate, String caseDir, Map imgPaths) { initComponents(); caseNameTextField.setText(currentCase.getName()); @@ -89,37 +89,35 @@ class CasePropertiesForm extends javax.swing.JPanel{ current = currentCase; int totalImages = imgPaths.size(); - + // create the headers and add all the rows String[] headers = {"Path"}; //NON-NLS String[][] rows = new String[totalImages][]; - + int i = 0; - for(long key : imgPaths.keySet()){ + for (long key : imgPaths.keySet()) { String path = imgPaths.get(key); String shortenPath = shrinkPath(path, 70); rows[i++] = new String[]{shortenPath}; } // create the table inside with the imgPaths information - DefaultTableModel model = new DefaultTableModel(rows, headers) - { + DefaultTableModel model = new DefaultTableModel(rows, headers) { @Override // make the cells in the FileContentTable "read only" - public boolean isCellEditable(int row, int column){ + public boolean isCellEditable(int row, int column) { return false; //return column == lastColumn; // make the last column (Remove button), only the editable } }; imagesTable.setModel(model); - + // // set the size of the remove column // TableColumn removeCol = imagesTable.getColumnModel().getColumn(lastColumn); // removeCol.setPreferredWidth(75); // removeCol.setMaxWidth(75); // removeCol.setMinWidth(75); // removeCol.setResizable(false); - // // create the delete action to remove the image from the current case // Action delete = new AbstractAction() // { @@ -158,7 +156,8 @@ class CasePropertiesForm extends javax.swing.JPanel{ // buttonColumn.setMnemonic(KeyEvent.VK_D); } - /** This method is called from within the constructor to initialize the form. + /** + * 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. */ @@ -355,7 +354,7 @@ class CasePropertiesForm extends javax.swing.JPanel{ /** * Updates the case name. * - * @param evt The action event + * @param evt The action event */ private void updateCaseNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_updateCaseNameButtonActionPerformed String oldCaseName = Case.getCurrentCase().getName(); @@ -364,47 +363,45 @@ class CasePropertiesForm extends javax.swing.JPanel{ //String newPath = caseDirTextArea.getText() + File.separator + newCaseName + ".aut"; // check if the old and new case name is not equal - if(!oldCaseName.equals(newCaseName)){ + if (!oldCaseName.equals(newCaseName)) { // check if the case name is empty - if(newCaseName.trim().equals("")){ + if (newCaseName.trim().equals("")) { JOptionPane.showMessageDialog(caller, - NbBundle.getMessage(this.getClass(), - "CasePropertiesForm.updateCaseName.msgDlg.empty.msg"), - NbBundle.getMessage(this.getClass(), - "CasePropertiesForm.updateCaseName.msgDlg.empty.title"), - JOptionPane.ERROR_MESSAGE); - } - else{ + NbBundle.getMessage(this.getClass(), + "CasePropertiesForm.updateCaseName.msgDlg.empty.msg"), + NbBundle.getMessage(this.getClass(), + "CasePropertiesForm.updateCaseName.msgDlg.empty.title"), + JOptionPane.ERROR_MESSAGE); + } else { // check if case Name contain one of this following symbol: // \ / : * ? " < > | - if(newCaseName.contains("\\") || newCaseName.contains("/") || newCaseName.contains(":") || - newCaseName.contains("*") || newCaseName.contains("?") || newCaseName.contains("\"") || - newCaseName.contains("<") || newCaseName.contains(">") || newCaseName.contains("|")){ + if (newCaseName.contains("\\") || newCaseName.contains("/") || newCaseName.contains(":") + || newCaseName.contains("*") || newCaseName.contains("?") || newCaseName.contains("\"") + || newCaseName.contains("<") || newCaseName.contains(">") || newCaseName.contains("|")) { String errorMsg = NbBundle .getMessage(this.getClass(), "CasePropertiesForm.updateCaseName.msgDlg.invalidSymbols.msg"); JOptionPane.showMessageDialog(caller, errorMsg, - NbBundle.getMessage(this.getClass(), - "CasePropertiesForm.updateCaseName.msgDlg.invalidSymbols.title"), - JOptionPane.ERROR_MESSAGE); - } - else{ + NbBundle.getMessage(this.getClass(), + "CasePropertiesForm.updateCaseName.msgDlg.invalidSymbols.title"), + JOptionPane.ERROR_MESSAGE); + } else { // ask for the confirmation first String confMsg = NbBundle .getMessage(this.getClass(), "CasePropertiesForm.updateCaseName.confMsg.msg", oldCaseName, - newCaseName); + newCaseName); NotifyDescriptor d = new NotifyDescriptor.Confirmation(confMsg, - NbBundle.getMessage(this.getClass(), - "CasePropertiesForm.updateCaseName.confMsg.title"), - NotifyDescriptor.YES_NO_OPTION, NotifyDescriptor.WARNING_MESSAGE); + NbBundle.getMessage(this.getClass(), + "CasePropertiesForm.updateCaseName.confMsg.title"), + NotifyDescriptor.YES_NO_OPTION, NotifyDescriptor.WARNING_MESSAGE); d.setValue(NotifyDescriptor.NO_OPTION); Object res = DialogDisplayer.getDefault().notify(d); - if(res != null && res == DialogDescriptor.YES_OPTION){ + if (res != null && res == DialogDescriptor.YES_OPTION) { // if user select "Yes" String oldPath = current.getConfigFilePath(); try { - current.updateCaseName(oldCaseName, oldPath , newCaseName, oldPath); + current.updateCaseName(oldCaseName, oldPath, newCaseName, oldPath); } catch (Exception ex) { Logger.getLogger(CasePropertiesForm.class.getName()).log(Level.WARNING, "Error: problem updating case name.", ex); //NON-NLS } @@ -418,13 +415,12 @@ class CasePropertiesForm extends javax.swing.JPanel{ CallableSystemAction.get(CaseDeleteAction.class).actionPerformed(evt); }//GEN-LAST:event_deleteCaseButtonActionPerformed - /** * Sets the listener for the OK button * - * @param e The action listener + * @param e The action listener */ - public void setOKButtonActionListener(ActionListener e){ + public void setOKButtonActionListener(ActionListener e) { OKButton.addActionListener(e); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java index d5a974a587..793629da66 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.casemodule; import java.awt.*; @@ -59,10 +58,10 @@ public class CueBannerPanel extends javax.swing.JPanel { } } - /** 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. + /** + * 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") // //GEN-BEGIN:initComponents @@ -209,14 +208,14 @@ public class CueBannerPanel extends javax.swing.JPanel { int h = recentCasesWindow.getSize().height; // set the location of the popUp Window on the center of the screen - recentCasesWindow.setLocation((screenDimension.width - w)/2, (screenDimension.height - h)/2); + recentCasesWindow.setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); OpenRecentCasePanel welcomeWindow = OpenRecentCasePanel.getInstance(); // add the command to close the window to the button on the Volume Detail Panel - welcomeWindow.setCloseButtonActionListener( new ActionListener(){ + welcomeWindow.setCloseButtonActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent e){ + public void actionPerformed(ActionEvent e) { recentCasesWindow.dispose(); } }); @@ -228,7 +227,6 @@ public class CueBannerPanel extends javax.swing.JPanel { recentCasesWindow.setVisible(true); }//GEN-LAST:event_openRecentButtonActionPerformed - // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel autopsyLogo; private javax.swing.JButton closeButton; @@ -244,9 +242,9 @@ public class CueBannerPanel extends javax.swing.JPanel { /** * Sets the Close button action listener. * - * @param e the action listener + * @param e the action listener */ - public void setCloseButtonActionListener(ActionListener e){ + public void setCloseButtonActionListener(ActionListener e) { closeButton.addActionListener(e); } @@ -257,12 +255,12 @@ public class CueBannerPanel extends javax.swing.JPanel { */ public void setCloseButtonText(String text) { closeButton.setText(text); - } - + } + /** * Close the open recent cases window. */ - public static void closeOpenRecentCasesWindow(){ + public static void closeOpenRecentCasesWindow() { //startupWindow.setVisible(false); recentCasesWindow.dispose(); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/GeneralFilter.java b/Core/src/org/sleuthkit/autopsy/casemodule/GeneralFilter.java index 98bc71b675..55a7c051f7 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/GeneralFilter.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/GeneralFilter.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.casemodule; import org.openide.util.NbBundle; @@ -29,23 +28,20 @@ import javax.swing.filechooser.FileFilter; /** * FileFilter helper class. Matches files based on extension */ -public class GeneralFilter extends FileFilter{ +public class GeneralFilter extends FileFilter { - // Extensions & Descriptions for commonly used filters public static final List RAW_IMAGE_EXTS = Arrays.asList(new String[]{".img", ".dd", ".001", ".aa", ".raw", ".bin"}); //NON-NLS public static final String RAW_IMAGE_DESC = NbBundle.getMessage(GeneralFilter.class, "GeneralFilter.rawImageDesc.text"); - + public static final List ENCASE_IMAGE_EXTS = Arrays.asList(new String[]{".e01"}); //NON-NLS public static final String ENCASE_IMAGE_DESC = NbBundle.getMessage(GeneralFilter.class, - "GeneralFilter.encaseImageDesc.text"); - - - + "GeneralFilter.encaseImageDesc.text"); + private List extensions; private String desc; - public GeneralFilter(List ext, String desc){ + public GeneralFilter(List ext, String desc) { super(); this.extensions = ext; this.desc = desc; @@ -54,12 +50,13 @@ public class GeneralFilter extends FileFilter{ /** * Checks whether the given file is accepted by this filter. * - * @param f the given file - * @return boolean return true if accepted, false otherwise + * @param f the given file + * + * @return boolean return true if accepted, false otherwise */ @Override public boolean accept(File f) { - if(f.isDirectory()){ + if (f.isDirectory()) { return true; } else { Boolean result = false; @@ -77,7 +74,7 @@ public class GeneralFilter extends FileFilter{ /** * Returns the description of this file filter * - * @return desc return the description + * @return desc return the description */ @Override public String getDescription() { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java index d8c4b31de6..be46ed5408 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java @@ -31,181 +31,190 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; /** - * Image data source processor. - * Handles the addition of "disk images" to Autopsy. - * + * Image data source processor. Handles the addition of "disk images" to + * Autopsy. + * * An instance of this class is created via the Netbeans Lookup() method. - * + * */ @ServiceProvider(service = DataSourceProcessor.class) public class ImageDSProcessor implements DataSourceProcessor { - + static final Logger logger = Logger.getLogger(ImageDSProcessor.class.getName()); - + // Data source type handled by this processor private final static String dsType = NbBundle.getMessage(ImageDSProcessor.class, "ImageDSProcessor.dsType.text"); - + // The Config UI panel that plugins into the Choose Data Source Wizard private final ImageFilePanel imageFilePanel; - + // The Background task that does the actual work of adding the image private AddImageTask addImageTask; - + // true of cancelled by the caller private boolean cancelled = false; - + DataSourceProcessorCallback callbackObj = null; - + // set to TRUE if the image options have been set via API and config Jpanel should be ignored private boolean imageOptionsSet = false; - + // image options private String imagePath; private String timeZone; private boolean noFatOrphans; - + static final GeneralFilter rawFilter = new GeneralFilter(GeneralFilter.RAW_IMAGE_EXTS, GeneralFilter.RAW_IMAGE_DESC); static final GeneralFilter encaseFilter = new GeneralFilter(GeneralFilter.ENCASE_IMAGE_EXTS, GeneralFilter.ENCASE_IMAGE_DESC); - + static final List allExt = new ArrayList<>(); + static { allExt.addAll(GeneralFilter.RAW_IMAGE_EXTS); allExt.addAll(GeneralFilter.ENCASE_IMAGE_EXTS); } static final String allDesc = NbBundle.getMessage(ImageDSProcessor.class, "ImageDSProcessor.allDesc.text"); static final GeneralFilter allFilter = new GeneralFilter(allExt, allDesc); - + static final List filtersList = new ArrayList<>(); - + static { filtersList.add(allFilter); filtersList.add(rawFilter); filtersList.add(encaseFilter); } - + /* - * A no argument constructor is required for the NM lookup() method to create an object + * A no argument constructor is required for the NM lookup() method to + * create an object */ public ImageDSProcessor() { - + // Create the config panel - imageFilePanel = ImageFilePanel.createInstance(ImageDSProcessor.class.getName(), filtersList); - + imageFilePanel = ImageFilePanel.createInstance(ImageDSProcessor.class.getName(), filtersList); + } - + // this static method is used by the wizard to determine dsp type for 'core' data source processors public static String getType() { return dsType; } - + /** * Returns the Data source type (string) handled by this DSP * * @return String the data source type - **/ + * + */ @Override public String getDataSourceType() { return dsType; } - + /** * Returns the JPanel for collecting the Data source information * * @return JPanel the config panel - **/ - @Override + * + */ + @Override public JPanel getPanel() { - imageFilePanel.readSettings(); - imageFilePanel.select(); - - return imageFilePanel; - } - + imageFilePanel.readSettings(); + imageFilePanel.select(); + + return imageFilePanel; + } + /** * Validates the data collected by the JPanel * - * @return String returns NULL if success, error string if there is any errors - **/ - @Override - public boolean isPanelValid() { - - return imageFilePanel.validatePanel(); - } - - /** - * Runs the data source processor. - * This must kick off processing the data source in background + * @return String returns NULL if success, error string if there is any + * errors * - * @param progressMonitor Progress monitor to report progress during processing - * @param cbObj callback to call when processing is done. - **/ - @Override - public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback cbObj) { - - callbackObj = cbObj; - cancelled = false; - - if (!imageOptionsSet) - { - //tell the panel to save the current settings - imageFilePanel.storeSettings(); - - // get the image options from the panel - imagePath = imageFilePanel.getContentPaths(); - timeZone = imageFilePanel.getTimeZone(); - noFatOrphans = imageFilePanel.getNoFatOrphans(); - } - - addImageTask = new AddImageTask(imagePath, timeZone, noFatOrphans, progressMonitor, cbObj); - new Thread(addImageTask).start(); - - } - + */ + @Override + public boolean isPanelValid() { + + return imageFilePanel.validatePanel(); + } + + /** + * Runs the data source processor. This must kick off processing the data + * source in background + * + * @param progressMonitor Progress monitor to report progress during + * processing + * @param cbObj callback to call when processing is done. + * + */ + @Override + public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback cbObj) { + + callbackObj = cbObj; + cancelled = false; + + if (!imageOptionsSet) { + //tell the panel to save the current settings + imageFilePanel.storeSettings(); + + // get the image options from the panel + imagePath = imageFilePanel.getContentPaths(); + timeZone = imageFilePanel.getTimeZone(); + noFatOrphans = imageFilePanel.getNoFatOrphans(); + } + + addImageTask = new AddImageTask(imagePath, timeZone, noFatOrphans, progressMonitor, cbObj); + new Thread(addImageTask).start(); + + } + /** * Cancel the data source processing - **/ - @Override - public void cancel() { - - cancelled = true; - addImageTask.cancelTask(); - } - - /** - * Reset the data source processor - **/ - @Override - public void reset() { - - // reset the config panel - imageFilePanel.reset(); - - // reset state - imageOptionsSet = false; - imagePath = null; - timeZone = null; - noFatOrphans = false; - } - - /** - * Sets the data source options externally. - * To be used by a client that does not have a UI and does not use the JPanel to - * collect this information from a user. - * - * @param imgPath path to thew image or first image - * @param tz timeZone - * @param noFat whether to parse FAT orphans - **/ - public void setDataSourceOptions(String imgPath, String tz, boolean noFat) { - - this.imagePath = imgPath; - this.timeZone = tz; - this.noFatOrphans = noFat; - - imageOptionsSet = true; - - } - - + * + */ + @Override + public void cancel() { + + cancelled = true; + addImageTask.cancelTask(); + } + + /** + * Reset the data source processor + * + */ + @Override + public void reset() { + + // reset the config panel + imageFilePanel.reset(); + + // reset state + imageOptionsSet = false; + imagePath = null; + timeZone = null; + noFatOrphans = false; + } + + /** + * Sets the data source options externally. To be used by a client that does + * not have a UI and does not use the JPanel to collect this information + * from a user. + * + * @param imgPath path to thew image or first image + * @param tz timeZone + * @param noFat whether to parse FAT orphans + * + */ + public void setDataSourceOptions(String imgPath, String tz, boolean noFat) { + + this.imagePath = imgPath; + this.timeZone = tz; + this.noFatOrphans = noFat; + + imageOptionsSet = true; + + } + } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index 045fe691a4..a1a285ede9 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -42,53 +42,55 @@ import org.sleuthkit.autopsy.coreutils.Logger; * ImageTypePanel for adding an image file such as .img, .E0x, .00x, etc. */ public class ImageFilePanel extends JPanel implements DocumentListener { - + private final String PROP_LASTIMAGE_PATH = "LBL_LastImage_PATH"; //NON-NLS private static final Logger logger = Logger.getLogger(ImageFilePanel.class.getName()); private PropertyChangeSupport pcs = null; private JFileChooser fc = new JFileChooser(); - + // Externally supplied name is used to store settings private String contextName; /** * Creates new form ImageFilePanel - * @param context a string context name used to read/store last used settings - * @param fileChooserFilters a list of filters to be used with the FileChooser + * + * @param context a string context name used to read/store last + * used settings + * @param fileChooserFilters a list of filters to be used with the + * FileChooser */ private ImageFilePanel(String context, List fileChooserFilters) { initComponents(); fc.setDragEnabled(false); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); fc.setMultiSelectionEnabled(false); - + boolean firstFilter = true; - for (FileFilter filter: fileChooserFilters ) { + for (FileFilter filter : fileChooserFilters) { if (firstFilter) { // set the first on the list as the default selection fc.setFileFilter(filter); firstFilter = false; - } - else { + } else { fc.addChoosableFileFilter(filter); } } - + this.contextName = context; pcs = new PropertyChangeSupport(this); - + createTimeZoneList(); } - + /** * Creates and returns an instance of a ImageFilePanel. */ public static synchronized ImageFilePanel createInstance(String context, List fileChooserFilters) { - - ImageFilePanel instance = new ImageFilePanel(context, fileChooserFilters ); - - instance.postInit(); - - return instance; + + ImageFilePanel instance = new ImageFilePanel(context, fileChooserFilters); + + instance.postInit(); + + return instance; } //post-constructor initialization to properly initialize listener support @@ -96,8 +98,6 @@ public class ImageFilePanel extends JPanel implements DocumentListener { private void postInit() { pathTextField.getDocument().addDocumentListener(this); } - - /** * This method is called from within the constructor to initialize the form. @@ -194,17 +194,14 @@ public class ImageFilePanel extends JPanel implements DocumentListener { String path = fc.getSelectedFile().getPath(); pathTextField.setText(path); } - - - + try { pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.FOCUS_NEXT.toString(), false, true); - } - catch (Exception e) { + } catch (Exception e) { logger.log(Level.SEVERE, "ImageFilePanel listener threw exception", e); //NON-NLS MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "ImageFilePanel.moduleErr"), - NbBundle.getMessage(this.getClass(), "ImageFilePanel.moduleErr.msg"), - MessageNotifyUtil.MessageType.ERROR); + NbBundle.getMessage(this.getClass(), "ImageFilePanel.moduleErr.msg"), + MessageNotifyUtil.MessageType.ERROR); } }//GEN-LAST:event_browseButtonActionPerformed @@ -217,9 +214,10 @@ public class ImageFilePanel extends JPanel implements DocumentListener { private javax.swing.JComboBox timeZoneComboBox; private javax.swing.JLabel timeZoneLabel; // End of variables declaration//GEN-END:variables - + /** * Get the path of the user selected image. + * * @return the image path */ public String getContentPaths() { @@ -236,22 +234,21 @@ public class ImageFilePanel extends JPanel implements DocumentListener { public String getTimeZone() { String tz = timeZoneComboBox.getSelectedItem().toString(); return tz.substring(tz.indexOf(")") + 2).trim(); - + } - + public boolean getNoFatOrphans() { return noFatOrphansCheckbox.isSelected(); } - - public void reset() { //reset the UI elements to default - pathTextField.setText(null); + pathTextField.setText(null); } - + /** * Should we enable the next button of the wizard? + * * @return true if a proper image has been selected, false otherwise */ public boolean validatePanel() { @@ -259,35 +256,36 @@ public class ImageFilePanel extends JPanel implements DocumentListener { if (path == null || path.isEmpty()) { return false; } - + boolean isExist = Case.pathExists(path); boolean isPhysicalDrive = Case.isPhysicalDrive(path); boolean isPartition = Case.isPartition(path); - + return (isExist || isPhysicalDrive || isPartition); } - public void storeSettings() { String imagePathName = getContentPaths(); - if (null != imagePathName ) { + if (null != imagePathName) { String imagePath = imagePathName.substring(0, imagePathName.lastIndexOf(File.separator) + 1); ModuleSettings.setConfigSetting(contextName, PROP_LASTIMAGE_PATH, imagePath); } } - + public void readSettings() { String lastImagePath = ModuleSettings.getConfigSetting(contextName, PROP_LASTIMAGE_PATH); if (null != lastImagePath) { - if (!lastImagePath.isEmpty()) - pathTextField.setText(lastImagePath); - } + if (!lastImagePath.isEmpty()) { + pathTextField.setText(lastImagePath); + } + } } + /** * Creates the drop down list for the time zones and then makes the local * machine time zone to be selected. */ - public void createTimeZoneList() { + public void createTimeZoneList() { // load and add all timezone String[] ids = SimpleTimeZone.getAvailableIDs(); for (String id : ids) { @@ -318,75 +316,73 @@ public class ImageFilePanel extends JPanel implements DocumentListener { // set the selected timezone timeZoneComboBox.setSelectedItem(formatted); } + /** - * Update functions are called by the pathTextField which has this set - * as it's DocumentEventListener. Each update function fires a property change + * Update functions are called by the pathTextField which has this set as + * it's DocumentEventListener. Each update function fires a property change * to be caught by the parent panel. + * * @param e the event, which is ignored */ @Override public void insertUpdate(DocumentEvent e) { - + try { pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true); - } - catch (Exception ee) { + } catch (Exception ee) { logger.log(Level.SEVERE, "ImageFilePanel listener threw exception", ee); //NON-NLS MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "ImageFilePanel.moduleErr"), - NbBundle.getMessage(this.getClass(), "ImageFilePanel.moduleErr.msg"), - MessageNotifyUtil.MessageType.ERROR); + NbBundle.getMessage(this.getClass(), "ImageFilePanel.moduleErr.msg"), + MessageNotifyUtil.MessageType.ERROR); } } @Override - public void removeUpdate(DocumentEvent e) { + public void removeUpdate(DocumentEvent e) { try { - pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true); - } - catch (Exception ee) { + pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true); + } catch (Exception ee) { logger.log(Level.SEVERE, "ImageFilePanel listener threw exception", ee); //NON-NLS MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "ImageFilePanel.moduleErr"), - NbBundle.getMessage(this.getClass(), "ImageFilePanel.moduleErr.msg"), - MessageNotifyUtil.MessageType.ERROR); + NbBundle.getMessage(this.getClass(), "ImageFilePanel.moduleErr.msg"), + MessageNotifyUtil.MessageType.ERROR); } } @Override public void changedUpdate(DocumentEvent e) { - + try { pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true); - } - catch (Exception ee) { + } catch (Exception ee) { logger.log(Level.SEVERE, "ImageFilePanel listener threw exception", ee); //NON-NLS MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "ImageFilePanel.moduleErr"), - NbBundle.getMessage(this.getClass(), "ImageFilePanel.moduleErr.msg"), - MessageNotifyUtil.MessageType.ERROR); + NbBundle.getMessage(this.getClass(), "ImageFilePanel.moduleErr.msg"), + MessageNotifyUtil.MessageType.ERROR); } } - + /** * Set the focus to the pathTextField. */ public void select() { pathTextField.requestFocusInWindow(); } - - + @Override public synchronized void addPropertyChangeListener(PropertyChangeListener pcl) { - super.addPropertyChangeListener(pcl); + super.addPropertyChangeListener(pcl); - if (pcs == null) { - pcs = new PropertyChangeSupport(this); - } + if (pcs == null) { + pcs = new PropertyChangeSupport(this); + } pcs.addPropertyChangeListener(pcl); } - + @Override public void removePropertyChangeListener(PropertyChangeListener pcl) { - super.removePropertyChangeListener(pcl); + super.removePropertyChangeListener(pcl); pcs.removePropertyChangeListener(pcl); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java index 997e69348b..4c331bd793 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.casemodule; import javax.swing.JPanel; @@ -28,150 +27,160 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgress import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.Logger; - @ServiceProvider(service = DataSourceProcessor.class) -public class LocalDiskDSProcessor implements DataSourceProcessor { - +public class LocalDiskDSProcessor implements DataSourceProcessor { + static final Logger logger = Logger.getLogger(ImageDSProcessor.class.getName()); - + // Data source type handled by this processor - private static final String dsType = NbBundle.getMessage(LocalDiskDSProcessor.class, "LocalDiskDSProcessor.dsType.text"); - + private static final String dsType = NbBundle.getMessage(LocalDiskDSProcessor.class, "LocalDiskDSProcessor.dsType.text"); + // The Config UI panel that plugins into the Choose Data Source Wizard private final LocalDiskPanel localDiskPanel; - + // The Background task that does the actual work of adding the local Disk // Adding a local disk is exactly same as adding an Image. private AddImageTask addDiskTask; - + // true if cancelled by the caller private boolean cancelled = false; - + DataSourceProcessorCallback callbackObj = null; - + // set to TRUE if the image options have been set via API and config Jpanel should be ignored private boolean localDiskOptionsSet = false; - + // data source options private String localDiskPath; private String timeZone; private boolean noFatOrphans; - - /* - * A no argument constructor is required for the NM lookup() method to create an object + + /* + * A no argument constructor is required for the NM lookup() method to + * create an object */ public LocalDiskDSProcessor() { - + // Create the config panel - localDiskPanel = LocalDiskPanel.getDefault(); - + localDiskPanel = LocalDiskPanel.getDefault(); + } - + // this static method is used by the wizard to determine dsp type for 'core' data source processors public static String getType() { return dsType; } - + /** * Returns the Data source type (string) handled by this DSP * * @return String the data source type - **/ + * + */ @Override public String getDataSourceType() { return dsType; } - + /** * Returns the JPanel for collecting the Data source information * * @return JPanel the config panel - **/ - @Override + * + */ + @Override public JPanel getPanel() { - - localDiskPanel.select(); - return localDiskPanel; - } + + localDiskPanel.select(); + return localDiskPanel; + } + /** * Validates the data collected by the JPanel * - * @return String returns NULL if success, error string if there is any errors - **/ - @Override - public boolean isPanelValid() { - return localDiskPanel.validatePanel(); - } - - /** - * Runs the data source processor. - * This must kick off processing the data source in background + * @return String returns NULL if success, error string if there is any + * errors * - * @param progressMonitor Progress monitor to report progress during processing - * @param cbObj callback to call when processing is done. - **/ - @Override - public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback cbObj) { - - callbackObj = cbObj; - cancelled = false; - - if (!localDiskOptionsSet) { - // get the image options from the panel - localDiskPath = localDiskPanel.getContentPaths(); - timeZone = localDiskPanel.getTimeZone(); - noFatOrphans = localDiskPanel.getNoFatOrphans(); - } - - addDiskTask = new AddImageTask(localDiskPath, timeZone, noFatOrphans, progressMonitor, cbObj); - new Thread(addDiskTask).start(); - - } - - /** + */ + @Override + public boolean isPanelValid() { + return localDiskPanel.validatePanel(); + } + + /** + * Runs the data source processor. This must kick off processing the data + * source in background + * + * @param progressMonitor Progress monitor to report progress during + * processing + * @param cbObj callback to call when processing is done. + * + */ + @Override + public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback cbObj) { + + callbackObj = cbObj; + cancelled = false; + + if (!localDiskOptionsSet) { + // get the image options from the panel + localDiskPath = localDiskPanel.getContentPaths(); + timeZone = localDiskPanel.getTimeZone(); + noFatOrphans = localDiskPanel.getNoFatOrphans(); + } + + addDiskTask = new AddImageTask(localDiskPath, timeZone, noFatOrphans, progressMonitor, cbObj); + new Thread(addDiskTask).start(); + + } + + /** * Cancel the data source processing - **/ - @Override - public void cancel() { - - cancelled = true; - - addDiskTask.cancelTask(); - } - - /** - * Reset the data source processor - **/ - @Override - public void reset() { - - // reset the config panel - localDiskPanel.reset(); - - // reset state - localDiskOptionsSet = false; - localDiskPath = null; - timeZone = null; - noFatOrphans = false; - - } - - /** - * Sets the data source options externally. - * To be used by a client that does not have a UI and does not use the JPanel to - * collect this information from a user. - * - * @param diskPath path to the local disk - * @param tz time zone - * @param noFat whether to parse FAT orphans - **/ - public void setDataSourceOptions(String diskPath, String tz, boolean noFat) { - - this.localDiskPath = diskPath; - this.timeZone = tz; - this.noFatOrphans = noFat; - - localDiskOptionsSet = true; - - } + * + */ + @Override + public void cancel() { + + cancelled = true; + + addDiskTask.cancelTask(); + } + + /** + * Reset the data source processor + * + */ + @Override + public void reset() { + + // reset the config panel + localDiskPanel.reset(); + + // reset state + localDiskOptionsSet = false; + localDiskPath = null; + timeZone = null; + noFatOrphans = false; + + } + + /** + * Sets the data source options externally. To be used by a client that does + * not have a UI and does not use the JPanel to collect this information + * from a user. + * + * @param diskPath path to the local disk + * @param tz time zone + * @param noFat whether to parse FAT orphans + * + */ + public void setDataSourceOptions(String diskPath, String tz, boolean noFat) { + + this.localDiskPath = diskPath; + this.timeZone = tz; + this.noFatOrphans = noFat; + + localDiskOptionsSet = true; + + } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java index 38d067c153..4502a8dde5 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java @@ -218,8 +218,8 @@ final class LocalDiskPanel extends JPanel { } /** - * Should we enable the wizard's next button? - * Always return true because we control the possible selections. + * Should we enable the wizard's next button? Always return true because we + * control the possible selections. * * @return true */ @@ -313,7 +313,7 @@ final class LocalDiskPanel extends JPanel { //private String SELECT = "Select a local disk:"; private String LOADING = NbBundle.getMessage(this.getClass(), "LocalDiskPanel.localDiskModel.loading.msg"); private String NO_DRIVES = NbBundle.getMessage(this.getClass(), "LocalDiskPanel.localDiskModel.nodrives.msg"); - + LocalDiskThread worker = null; private void loadDisks() { @@ -349,8 +349,8 @@ final class LocalDiskPanel extends JPanel { } catch (Exception e) { logger.log(Level.SEVERE, "LocalDiskPanel listener threw exception", e); //NON-NLS MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "LocalDiskPanel.moduleErr"), - NbBundle.getMessage(this.getClass(), "LocalDiskPanel.moduleErr.msg"), - MessageNotifyUtil.MessageType.ERROR); + NbBundle.getMessage(this.getClass(), "LocalDiskPanel.moduleErr.msg"), + MessageNotifyUtil.MessageType.ERROR); } } } @@ -362,8 +362,7 @@ final class LocalDiskPanel extends JPanel { return NO_DRIVES; } return selected; - } - else { + } else { return LOADING; } } @@ -375,8 +374,7 @@ final class LocalDiskPanel extends JPanel { return 1; } return disks.size(); - } - else { + } else { return 1; } } @@ -388,8 +386,7 @@ final class LocalDiskPanel extends JPanel { return NO_DRIVES; } return disks.get(index); - } - else { + } else { return LOADING; } } @@ -453,19 +450,19 @@ final class LocalDiskPanel extends JPanel { errorLabel.setText( NbBundle.getMessage(this.getClass(), "LocalDiskPanel.errLabel.disksNotDetected.text")); errorLabel.setToolTipText(NbBundle.getMessage(this.getClass(), - "LocalDiskPanel.errLabel.disksNotDetected.toolTipText")); + "LocalDiskPanel.errLabel.disksNotDetected.toolTipText")); } else { errorLabel.setText( NbBundle.getMessage(this.getClass(), "LocalDiskPanel.errLabel.drivesNotDetected.text")); errorLabel.setToolTipText(NbBundle.getMessage(this.getClass(), - "LocalDiskPanel.errLabel.drivesNotDetected.toolTipText")); + "LocalDiskPanel.errLabel.drivesNotDetected.toolTipText")); } diskComboBox.setEnabled(false); } else if (physicalDrives.isEmpty()) { errorLabel.setText( NbBundle.getMessage(this.getClass(), "LocalDiskPanel.errLabel.someDisksNotDetected.text")); errorLabel.setToolTipText(NbBundle.getMessage(this.getClass(), - "LocalDiskPanel.errLabel.someDisksNotDetected.toolTipText")); + "LocalDiskPanel.errLabel.someDisksNotDetected.toolTipText")); } } @@ -483,7 +480,7 @@ final class LocalDiskPanel extends JPanel { if (!this.isCancelled()) { enableNext = false; displayErrors(); - + worker = null; loadingDisks = false; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java index 898e414e8f..f8f8353ee9 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.casemodule; import javax.swing.JPanel; @@ -30,138 +29,147 @@ import org.sleuthkit.autopsy.coreutils.Logger; @ServiceProvider(service = DataSourceProcessor.class) public class LocalFilesDSProcessor implements DataSourceProcessor { - + static final Logger logger = Logger.getLogger(LocalFilesDSProcessor.class.getName()); - + // Data source type handled by this processor private static final String dsType = NbBundle.getMessage(LocalFilesDSProcessor.class, "LocalFilesDSProcessor.dsType"); - + // The Config UI panel that plugins into the Choose Data Source Wizard private final LocalFilesPanel localFilesPanel; - + // The Background task that does the actual work of adding the files private AddLocalFilesTask addFilesTask; - + // true if cancelled by the caller private boolean cancelled = false; - + DataSourceProcessorCallback callbackObj = null; - + // set to TRUE if the image options have been set via API and config Jpanel should be ignored private boolean localFilesOptionsSet = false; - + // data source options private String localFilesPath; - + /* - * A no argument constructor is required for the NM lookup() method to create an object + * A no argument constructor is required for the NM lookup() method to + * create an object */ public LocalFilesDSProcessor() { - + // Create the config panel - localFilesPanel = LocalFilesPanel.getDefault(); + localFilesPanel = LocalFilesPanel.getDefault(); } - + // this static method is used by the wizard to determine dsp type for 'core' data source processors public static String getType() { return dsType; } - + /** * Returns the Data source type (string) handled by this DSP * * @return String the data source type - **/ + * + */ @Override public String getDataSourceType() { return dsType; } - + /** * Returns the JPanel for collecting the Data source information * * @return JPanel the config panel - **/ - @Override + * + */ + @Override public JPanel getPanel() { - localFilesPanel.select(); - return localFilesPanel; - } - + localFilesPanel.select(); + return localFilesPanel; + } + /** * Validates the data collected by the JPanel * - * @return String returns NULL if success, error string if there is any errors - **/ - @Override - public boolean isPanelValid() { - return localFilesPanel.validatePanel(); - } - - /** - * Runs the data source processor. - * This must kick off processing the data source in background + * @return String returns NULL if success, error string if there is any + * errors * - * @param progressMonitor Progress monitor to report progress during processing - * @param cbObj callback to call when processing is done. - **/ - @Override - public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback cbObj) { - - callbackObj = cbObj; - cancelled = false; - - if (!localFilesOptionsSet) { - // get the selected file paths from the panel - localFilesPath = localFilesPanel.getContentPaths(); - } - - addFilesTask = new AddLocalFilesTask(localFilesPath, progressMonitor, cbObj); - new Thread(addFilesTask).start(); - - } - - /** - * Cancel the data source processing - **/ - @Override - public void cancel() { - - cancelled = true; - addFilesTask.cancelTask(); - - } - - /** - * Reset the data source processor - **/ - @Override - public void reset() { - - // reset the config panel - localFilesPanel.reset(); - - // reset state - localFilesOptionsSet = false; - localFilesPath = null; + */ + @Override + public boolean isPanelValid() { + return localFilesPanel.validatePanel(); + } - } - - /** - * Sets the data source options externally. - * To be used by a client that does not have a UI and does not use the JPanel to - * collect this information from a user. - * - * @param filesPath PATH_SEP list of paths to local files + /** + * Runs the data source processor. This must kick off processing the data + * source in background + * + * @param progressMonitor Progress monitor to report progress during + * processing + * @param cbObj callback to call when processing is done. + * + */ + @Override + public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback cbObj) { + + callbackObj = cbObj; + cancelled = false; + + if (!localFilesOptionsSet) { + // get the selected file paths from the panel + localFilesPath = localFilesPanel.getContentPaths(); + } + + addFilesTask = new AddLocalFilesTask(localFilesPath, progressMonitor, cbObj); + new Thread(addFilesTask).start(); + + } + + /** + * Cancel the data source processing + * + */ + @Override + public void cancel() { + + cancelled = true; + addFilesTask.cancelTask(); + + } + + /** + * Reset the data source processor * - **/ - public void setDataSourceOptions(String filesPath) { - - localFilesPath = filesPath; - - localFilesOptionsSet = true; - - } - - + */ + @Override + public void reset() { + + // reset the config panel + localFilesPanel.reset(); + + // reset state + localFilesOptionsSet = false; + localFilesPath = null; + + } + + /** + * Sets the data source options externally. To be used by a client that does + * not have a UI and does not use the JPanel to collect this information + * from a user. + * + * @param filesPath PATH_SEP list of paths to local files + * + * + */ + public void setDataSourceOptions(String filesPath) { + + localFilesPath = filesPath; + + localFilesOptionsSet = true; + + } + } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java index 256276809b..15b042bbc1 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java @@ -31,10 +31,11 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; + /** * Add input wizard subpanel for adding local files / dirs to the case */ - class LocalFilesPanel extends JPanel { +class LocalFilesPanel extends JPanel { private PropertyChangeSupport pcs = null; private Set currentFiles = new TreeSet(); //keep currents in a set to disallow duplicates per add @@ -42,6 +43,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; private static LocalFilesPanel instance; public static final String FILES_SEP = ","; private static final Logger logger = Logger.getLogger(LocalFilesPanel.class.getName()); + /** * Creates new form LocalFilesPanel */ @@ -60,19 +62,19 @@ import org.sleuthkit.autopsy.coreutils.Logger; private void customInit() { localFileChooser.setMultiSelectionEnabled(true); selectedPaths.setText(""); - + } - + //@Override public String getContentPaths() { //TODO consider interface change to return list of paths instead - + if (currentFiles == null) { return ""; } StringBuilder b = new StringBuilder(); for (File f : currentFiles) { - b.append(f.getAbsolutePath() ); + b.append(f.getAbsolutePath()); b.append(FILES_SEP); } return b.toString(); @@ -83,7 +85,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; //for the local file panel we don't need to restore the last paths used //when the wizard restarts } - + //@Override public String getContentType() { return NbBundle.getMessage(this.getClass(), "LocalFilesPanel.contentType.text"); @@ -98,35 +100,34 @@ import org.sleuthkit.autopsy.coreutils.Logger; public void select() { reset(); } - + //@Override public void reset() { currentFiles.clear(); selectedPaths.setText(""); enableNext = false; - + //pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true); } @Override - public synchronized void addPropertyChangeListener(PropertyChangeListener pcl) { - super.addPropertyChangeListener(pcl); + public synchronized void addPropertyChangeListener(PropertyChangeListener pcl) { + super.addPropertyChangeListener(pcl); - if (pcs == null) { - pcs = new PropertyChangeSupport(this); - } + if (pcs == null) { + pcs = new PropertyChangeSupport(this); + } pcs.addPropertyChangeListener(pcl); } @Override public void removePropertyChangeListener(PropertyChangeListener pcl) { - super.removePropertyChangeListener(pcl); + super.removePropertyChangeListener(pcl); pcs.removePropertyChangeListener(pcl); } - @Override public String toString() { return NbBundle.getMessage(this.getClass(), "LocalFilesDSProcessor.toString.text"); @@ -217,11 +218,11 @@ import org.sleuthkit.autopsy.coreutils.Logger; private void selectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectButtonActionPerformed int returnVal = localFileChooser.showOpenDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { - File [] files = localFileChooser.getSelectedFiles(); + File[] files = localFileChooser.getSelectedFiles(); for (File f : files) { currentFiles.add(f); } - + //update label StringBuilder allPaths = new StringBuilder(); for (File f : currentFiles) { @@ -229,31 +230,28 @@ import org.sleuthkit.autopsy.coreutils.Logger; } this.selectedPaths.setText(allPaths.toString()); this.selectedPaths.setToolTipText(allPaths.toString()); - + } - + if (!currentFiles.isEmpty()) { enableNext = true; - } - else { + } else { enableNext = false; } - + try { pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true); - } - catch (Exception e) { + } catch (Exception e) { logger.log(Level.SEVERE, "LocalFilesPanel listener threw exception", e); //NON-NLS MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "LocalFilesPanel.moduleErr"), - NbBundle.getMessage(this.getClass(), "LocalFilesPanel.moduleErr.msg"), - MessageNotifyUtil.MessageType.ERROR); + NbBundle.getMessage(this.getClass(), "LocalFilesPanel.moduleErr.msg"), + MessageNotifyUtil.MessageType.ERROR); } }//GEN-LAST:event_selectButtonActionPerformed private void clearButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearButtonActionPerformed reset(); - - + }//GEN-LAST:event_clearButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java index 598772401c..18eda3fffc 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java @@ -65,7 +65,6 @@ class MissingImageDialog extends javax.swing.JDialog { fc.addChoosableFileFilter(encaseFilter); fc.setFileFilter(allFilter); - customInit(); } @@ -307,9 +306,9 @@ class MissingImageDialog extends javax.swing.JDialog { void cancel() { int ret = JOptionPane.showConfirmDialog(null, NbBundle.getMessage(this.getClass(), - "MissingImageDialog.confDlg.noFileSel.msg"), + "MissingImageDialog.confDlg.noFileSel.msg"), NbBundle.getMessage(this.getClass(), - "MissingImageDialog.confDlg.noFileSel.title"), + "MissingImageDialog.confDlg.noFileSel.title"), JOptionPane.YES_NO_OPTION); if (ret == JOptionPane.YES_OPTION) { this.dispose(); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java index 53497e45c7..1c758179f1 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.casemodule; import org.openide.util.NbBundle; @@ -34,14 +33,14 @@ import javax.swing.event.DocumentListener; * * @author jantonius */ -final class NewCaseVisualPanel1 extends JPanel implements DocumentListener{ +final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { private JFileChooser fc = new JFileChooser(); private NewCaseWizardPanel1 wizPanel; NewCaseVisualPanel1(NewCaseWizardPanel1 wizPanel) { initComponents(); - this.wizPanel = wizPanel; + this.wizPanel = wizPanel; caseNameTextField.getDocument().addDocumentListener(this); caseParentDirTextField.getDocument().addDocumentListener(this); } @@ -50,7 +49,7 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener{ * Returns the name of the this panel. This name will be shown on the left * panel of the "New Case" wizard panel. * - * @return name the name of this panel + * @return name the name of this panel */ @Override public String getName() { @@ -60,32 +59,33 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener{ /** * Gets the case name that the user types on the case name text field. * - * @return caseName the case name from the case name text field + * @return caseName the case name from the case name text field */ - public String getCaseName(){ + public String getCaseName() { return this.caseNameTextField.getText(); } /** - * Gets the base directory that the user typed on the base directory text field. - * Will add file separator if it was not added. + * Gets the base directory that the user typed on the base directory text + * field. Will add file separator if it was not added. * - * @return baseDirectory the base directory from the case dir text field + * @return baseDirectory the base directory from the case dir text field */ - public String getCaseParentDir(){ + public String getCaseParentDir() { String parentDir = this.caseParentDirTextField.getText(); - + if (parentDir.endsWith(File.separator) == false) { parentDir = parentDir + File.separator; } return parentDir; } - - public JTextField getCaseParentDirTextField(){ + + public JTextField getCaseParentDirTextField() { return this.caseParentDirTextField; } - /** This method is called from within the constructor to initialize the form. + /** + * 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. */ @@ -173,27 +173,27 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener{ /** * The action when the Browse button is pressed. The browse button will pop - * up the file chooser window to choose where the user wants to save the + * up the file chooser window to choose where the user wants to save the * case directory. * - * @param evt the action event + * @param evt the action event */ private void caseDirBrowseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_caseDirBrowseButtonActionPerformed // show the directory chooser where the case directory will be created fc.setDragEnabled(false); - if(!caseParentDirTextField.getText().trim().equals("")){ + if (!caseParentDirTextField.getText().trim().equals("")) { fc.setCurrentDirectory(new File(caseParentDirTextField.getText())); } fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); //fc.setSelectedFile(new File("C:\\Program Files\\")); //disableTextField(fc); // disable all the text field on the file chooser - int returnValue = fc.showDialog((Component)evt.getSource(), NbBundle.getMessage(this.getClass(), - "NewCaseVisualPanel1.caseDirBrowse.selectButton.text")); - if(returnValue == JFileChooser.APPROVE_OPTION){ + int returnValue = fc.showDialog((Component) evt.getSource(), NbBundle.getMessage(this.getClass(), + "NewCaseVisualPanel1.caseDirBrowse.selectButton.text")); + if (returnValue == JFileChooser.APPROVE_OPTION) { String path = fc.getSelectedFile().getPath(); caseParentDirTextField.setText(path); // put the path to the textfield - } + } }//GEN-LAST:event_caseDirBrowseButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables @@ -208,10 +208,10 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener{ // End of variables declaration//GEN-END:variables /** - * Gives notification that there was an insert into the document. The - * range given by the DocumentEvent bounds the freshly inserted region. + * Gives notification that there was an insert into the document. The range + * given by the DocumentEvent bounds the freshly inserted region. * - * @param e the document event + * @param e the document event */ @Override public void insertUpdate(DocumentEvent e) { @@ -220,11 +220,11 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener{ } /** - * Gives notification that a portion of the document has been - * removed. The range is given in terms of what the view last - * saw (that is, before updating sticky positions). + * Gives notification that a portion of the document has been removed. The + * range is given in terms of what the view last saw (that is, before + * updating sticky positions). * - * @param e the document event + * @param e the document event */ @Override public void removeUpdate(DocumentEvent e) { @@ -235,7 +235,7 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener{ /** * Gives notification that an attribute or set of attributes changed. * - * @param e the document event + * @param e the document event */ @Override public void changedUpdate(DocumentEvent e) { @@ -245,20 +245,20 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener{ /** * The "listener" that listens when the fields in this form are updated. - * This method is used to determine when to enable / disable the "Finish" button. + * This method is used to determine when to enable / disable the "Finish" + * button. * - * @param e the document event + * @param e the document event */ public void updateUI(DocumentEvent e) { String caseName = getCaseName(); String parentDir = getCaseParentDir(); - if(!caseName.equals("") && !parentDir.equals("")){ - caseDirTextField.setText( parentDir + caseName); + if (!caseName.equals("") && !parentDir.equals("")) { + caseDirTextField.setText(parentDir + caseName); wizPanel.setIsFinish(true); - } - else{ + } else { caseDirTextField.setText(""); wizPanel.setIsFinish(false); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel2.java b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel2.java index 44a2cc8757..65ea37b79c 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel2.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel2.java @@ -32,28 +32,30 @@ import java.awt.*; * * @author dfickling */ - class NewCaseVisualPanel2 extends javax.swing.JPanel { +class NewCaseVisualPanel2 extends javax.swing.JPanel { - /** Creates new form NewCaseVisualPanel2 */ + /** + * Creates new form NewCaseVisualPanel2 + */ public NewCaseVisualPanel2() { initComponents(); } - + /** * Returns the name of the this panel. This name will be shown on the left * panel of the "New Case" wizard panel. * - * @return name the name of this panel + * @return name the name of this panel */ @Override public String getName() { return NbBundle.getMessage(this.getClass(), "NewCaseVisualPanel2.getName.text"); } - /** 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. + /** + * 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") // //GEN-BEGIN:initComponents @@ -126,6 +128,4 @@ import java.awt.*; return examinerTextField.getText(); } - - } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardAction.java index 6008a0e5be..0891ce74ed 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardAction.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.casemodule; import java.awt.Component; @@ -38,10 +37,10 @@ import org.sleuthkit.autopsy.coreutils.Logger; /** * Action to open the New Case wizard. */ - final class NewCaseWizardAction extends CallableSystemAction { +final class NewCaseWizardAction extends CallableSystemAction { private WizardDescriptor.Panel[] panels; - + private static final Logger logger = Logger.getLogger(NewCaseWizardAction.class.getName()); @Override @@ -52,9 +51,9 @@ import org.sleuthkit.autopsy.coreutils.Logger; String closeCurrentCase = NbBundle .getMessage(this.getClass(), "NewCaseWizardAction.closeCurCase.confMsg.msg"); NotifyDescriptor d = new NotifyDescriptor.Confirmation(closeCurrentCase, - NbBundle.getMessage(this.getClass(), - "NewCaseWizardAction.closeCurCase.confMsg.title"), - NotifyDescriptor.YES_NO_OPTION, NotifyDescriptor.WARNING_MESSAGE); + NbBundle.getMessage(this.getClass(), + "NewCaseWizardAction.closeCurCase.confMsg.title"), + NotifyDescriptor.YES_NO_OPTION, NotifyDescriptor.WARNING_MESSAGE); d.setValue(NotifyDescriptor.NO_OPTION); Object res = DialogDisplayer.getDefault().notify(d); @@ -83,7 +82,6 @@ import org.sleuthkit.autopsy.coreutils.Logger; dialog.setVisible(true); dialog.toFront(); - boolean finished = wizardDescriptor.getValue() == WizardDescriptor.FINISH_OPTION; // check if it finishes (it's not cancelled) boolean isCancelled = wizardDescriptor.getValue() == WizardDescriptor.CANCEL_OPTION; // check if the "Cancel" button is pressed @@ -98,7 +96,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; // if Cancel button is pressed if (isCancelled) { String createdDirectory = (String) wizardDescriptor.getProperty("createdDirectory"); //NON-NLS - if(createdDirectory != null) { + if (createdDirectory != null) { logger.log(Level.INFO, "Deleting a created case directory due to isCancelled set, dir: " + createdDirectory); //NON-NLS Case.deleteCaseDirectory(new File(createdDirectory)); } @@ -113,16 +111,16 @@ import org.sleuthkit.autopsy.coreutils.Logger; } /** - * Initialize panels representing individual wizard's steps and sets - * various properties for them influencing wizard appearance. + * Initialize panels representing individual wizard's steps and sets various + * properties for them influencing wizard appearance. */ @SuppressWarnings({"unchecked", "rawtypes"}) private WizardDescriptor.Panel[] getPanels() { if (panels == null) { panels = new WizardDescriptor.Panel[]{ - new NewCaseWizardPanel1(), - new NewCaseWizardPanel2() - }; + new NewCaseWizardPanel1(), + new NewCaseWizardPanel2() + }; String[] steps = new String[panels.length]; for (int i = 0; i < panels.length; i++) { Component c = panels[i].getComponent(); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel1.java b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel1.java index 3bc8b33a51..d368bef209 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel1.java @@ -89,7 +89,7 @@ class NewCaseWizardPanel1 implements WizardDescriptor.ValidatingPanel it; @@ -146,8 +146,8 @@ class NewCaseWizardPanel2 implements WizardDescriptor.ValidatingPanel recentCases; // newest case is last case - /** * Gets the instance of the RecentCases singleton. * - * - * @return INSTANCE the RecentCases singleton + * + * @return INSTANCE the RecentCases singleton */ static public RecentCases getInstance() { INSTANCE.refreshRecentCases(); return INSTANCE; } - /** the constructor */ + /** + * the constructor + */ private RecentCases() { - + for (int i = 0; i < LENGTH; i++) { - try{ - if(ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, nameKey(i)) == null) - ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, nameKey(i), ""); - if(ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, pathKey(i)) == null) - ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, pathKey(i), ""); - } - catch(Exception e ){ - + try { + if (ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, nameKey(i)) == null) { + ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, nameKey(i), ""); + } + if (ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, pathKey(i)) == null) { + ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, pathKey(i), ""); + } + } catch (Exception e) { + } } - + // Load recentCases from properties recentCases = new LinkedList(); @@ -90,7 +92,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; recentCases.add(rc); } } - + refreshRecentCases(); } @@ -112,19 +114,17 @@ import org.sleuthkit.autopsy.coreutils.Logger; } private String getName(int i) { - try{ - return ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, nameKey(i)); - } - catch(Exception e){ + try { + return ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, nameKey(i)); + } catch (Exception e) { return null; } } private String getPath(int i) { - try{ - return ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, pathKey(i)); - } - catch(Exception e){ + try { + return ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, pathKey(i)); + } catch (Exception e) { return null; } } @@ -145,29 +145,33 @@ import org.sleuthkit.autopsy.coreutils.Logger; private static final class RecentCase { String name, path; - + /** * @param name The case name or "" if a blank placeholder case - * @param path A normalized path (via FileUtil.normalizePath(path)) or "" if a blank placeholder case + * @param path A normalized path (via FileUtil.normalizePath(path)) or + * "" if a blank placeholder case */ private RecentCase(String name, String path) { this.name = name; this.path = path; } - + /** - * Used when creating RecentCases with external data. The path must be + * Used when creating RecentCases with external data. The path must be * normalized so that duplicate cases always have the same path. - * @param name The case name. + * + * @param name The case name. * @param unsafePath The (potentially un-normalized) case path. + * * @return The created RecentCase.s */ static RecentCase createSafe(String name, String unsafePath) { return new RecentCase(name, FileUtil.normalizePath(unsafePath)); } - + /** * Does this case exist or was it manually deleted or moved? + * * @return true if the case exists, false otherwise */ boolean exists() { @@ -201,15 +205,15 @@ import org.sleuthkit.autopsy.coreutils.Logger; return true; } } - + /** - * Refresh the current list of cases, removing any cases that - * no longer exist. + * Refresh the current list of cases, removing any cases that no longer + * exist. */ private void refreshRecentCases() { List toDelete = new ArrayList(); for (RecentCase rc : recentCases) { - if(!rc.exists()) { + if (!rc.exists()) { toDelete.add(rc); } } @@ -238,7 +242,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; /** * Gets a menu item that can present this action in a JMenu. * - * @return menuItem the representation menu item for this action + * @return menuItem the representation menu item for this action */ @Override public JMenuItem getMenuPresenter() { @@ -248,7 +252,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; /** * This action is used to clear all the recent cases menu options. * - * @param e the action event + * @param e the action event */ @Override public void actionPerformed(ActionEvent e) { @@ -267,20 +271,22 @@ import org.sleuthkit.autopsy.coreutils.Logger; private void addRecentCase(RecentCase rc) { // remove the case if it's already in the list recentCases.remove(rc); - + // make space if it's needed - if (recentCases.size() == LENGTH) recentCases.remove(); + if (recentCases.size() == LENGTH) { + recentCases.remove(); + } recentCases.add(rc); } /** * Adds a recent case to the top of the list. If the case is already in the - * list, it will be removed before the new entry is added. + * list, it will be removed before the new entry is added. * - * @param name the name of the recent case to be added - * @param unsafePath the (potentially un-normalized) path of the case - * config file + * @param name the name of the recent case to be added + * @param unsafePath the (potentially un-normalized) path of the case config + * file */ public void addRecentCase(String name, String unsafePath) { RecentCase rc = RecentCase.createSafe(name, unsafePath); @@ -299,10 +305,11 @@ import org.sleuthkit.autopsy.coreutils.Logger; /** * This method is used to update the name and path of a RecentCase. * - * @param oldName the old recent case name - * @param oldPath the old recent case config file path - * @param newName the new recent case name - * @param newPath the new recent case config file path + * @param oldName the old recent case name + * @param oldPath the old recent case config file path + * @param newName the new recent case name + * @param newPath the new recent case config file path + * * @throws Exception */ public void updateRecentCase(String oldName, String oldPath, String newName, String newPath) throws Exception { @@ -326,17 +333,18 @@ import org.sleuthkit.autopsy.coreutils.Logger; /** * Gets the total number of recent cases * - * @return total total number of recent cases + * @return total total number of recent cases */ public int getTotalRecentCases() { return recentCases.size(); } /** - * This method is used to remove the selected name and path of the RecentCase + * This method is used to remove the selected name and path of the + * RecentCase * - * @param name the case name to be removed from the recent case - * @param path the config file path to be removed from the recent case + * @param name the case name to be removed from the recent case + * @param path the config file path to be removed from the recent case */ public void removeRecentCase(String name, String path) { RecentCase rc = RecentCase.createSafe(name, path); @@ -344,7 +352,6 @@ import org.sleuthkit.autopsy.coreutils.Logger; // remove all instances of the old recent case recentCases.removeAll(Arrays.asList(rc)); - this.getMenuPresenter().setVisible(true); // invoke the contructor again // write the properties file @@ -358,7 +365,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; /** * Gets the recent case names. * - * @return caseNames An array String[LENGTH], newest case first, with any + * @return caseNames An array String[LENGTH - 1], newest case first, with any * extra spots filled with "" */ public String[] getRecentCaseNames() { @@ -366,9 +373,20 @@ import org.sleuthkit.autopsy.coreutils.Logger; Iterator mostRecentFirst = recentCases.descendingIterator(); int i = 0; + String currentCaseName = null; + try { + currentCaseName = Case.getCurrentCase().getName(); + } catch (IllegalStateException ex) { + // in case there is no current case. + } + while (mostRecentFirst.hasNext()) { - caseNames[i] = mostRecentFirst.next().name; - i++; + String name = mostRecentFirst.next().name; + if ((currentCaseName != null && !name.equals(currentCaseName)) || currentCaseName == null) { + // exclude currentCaseName from the caseNames[] + caseNames[i] = name; + i++; + } } while (i < caseNames.length) { @@ -376,23 +394,34 @@ import org.sleuthkit.autopsy.coreutils.Logger; i++; } - return caseNames; + // return last 5 case names + return (String[]) ArrayUtils.subarray(caseNames, 0, LENGTH - 1); } /** * Gets the recent case paths. * - * @return casePaths An array String[LENGTH], newest case first, with any + * @return casePaths An array String[LENGTH - 1], newest case first, with any * extra spots filled with "" */ public String[] getRecentCasePaths() { String[] casePaths = new String[LENGTH]; + String currentCasePath = null; + try { + currentCasePath = Case.getCurrentCase().getConfigFilePath(); + } catch (IllegalStateException ex) { + // in case there is no current case. + } Iterator mostRecentFirst = recentCases.descendingIterator(); int i = 0; while (mostRecentFirst.hasNext()) { - casePaths[i] = mostRecentFirst.next().path; - i++; + String path = mostRecentFirst.next().path; + if ((currentCasePath != null && !path.equals(currentCasePath)) || currentCasePath == null) { + // exclude currentCasePath from the casePaths[] + casePaths[i] = path; + i++; + } } while (i < casePaths.length) { @@ -400,7 +429,8 @@ import org.sleuthkit.autopsy.coreutils.Logger; i++; } - return casePaths; + // return last 5 case paths + return (String[]) ArrayUtils.subarray(casePaths, 0, LENGTH - 1); } /** @@ -418,7 +448,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; @Override public String getName() { //return NbBundle.getMessage(RecentCases.class, "CTL_RecentCases"); - return NbBundle.getMessage(this.getClass(), "RecentCases.getName.text"); + return NbBundle.getMessage(RecentCases.class, "RecentCases.getName.text"); } /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/RecentItems.java b/Core/src/org/sleuthkit/autopsy/casemodule/RecentItems.java index f27facd68a..5120f98152 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/RecentItems.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/RecentItems.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.casemodule; import java.awt.EventQueue; @@ -39,8 +38,10 @@ class RecentItems implements ActionListener { String casePath; private JPanel caller; // for error handling - /** the constructor */ - public RecentItems(String caseName, String casePath){ + /** + * the constructor + */ + public RecentItems(String caseName, String casePath) { this.caseName = caseName; this.casePath = casePath; } @@ -48,20 +49,20 @@ class RecentItems implements ActionListener { /** * Opens the recent case. * - * @param e the action event + * @param e the action event */ @Override public void actionPerformed(ActionEvent e) { // check if the file exists - if(caseName.equals("") || casePath.equals("") || (!new File(casePath).exists())){ + if (caseName.equals("") || casePath.equals("") || (!new File(casePath).exists())) { // throw an error here JOptionPane.showMessageDialog(caller, - NbBundle.getMessage(this.getClass(), "RecentItems.openRecentCase.msgDlg.text", - caseName), - NbBundle.getMessage(this.getClass(), "RecentItems.openRecentCase.msgDlg.err"), - JOptionPane.ERROR_MESSAGE); + NbBundle.getMessage(this.getClass(), "RecentItems.openRecentCase.msgDlg.text", + caseName), + NbBundle.getMessage(this.getClass(), "RecentItems.openRecentCase.msgDlg.err"), + JOptionPane.ERROR_MESSAGE); RecentCases.getInstance().removeRecentCase(caseName, casePath); // remove the recent case if it doesn't exist anymore - + //if case is not opened, open the start window if (Case.isCaseOpen() == false) { EventQueue.invokeLater(new Runnable() { @@ -70,12 +71,11 @@ class RecentItems implements ActionListener { public void run() { StartupWindowProvider.getInstance().open(); } - + }); - + } - } - else { + } else { try { Case.open(casePath); // open the case } catch (CaseActionException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindow.java b/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindow.java index caff6ed884..6fff0a1ff4 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindow.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindow.java @@ -16,8 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - - package org.sleuthkit.autopsy.casemodule; import java.awt.Dimension; @@ -34,7 +32,7 @@ import org.openide.windows.WindowManager; /** * The default implementation of the Autopsy startup window */ -@ServiceProvider(service=StartupWindowInterface.class) +@ServiceProvider(service = StartupWindowInterface.class) public final class StartupWindow extends JDialog implements StartupWindowInterface { private static StartupWindow instance; @@ -47,7 +45,6 @@ public final class StartupWindow extends JDialog implements StartupWindowInterfa init(); } - /** * Shows the startup window. */ @@ -62,7 +59,7 @@ public final class StartupWindow extends JDialog implements StartupWindowInterfa // set the location of the popUp Window on the center of the screen setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); - + welcomeWindow = new CueBannerPanel(); // add the command to close the window to the button on the Volume Detail Panel @@ -79,7 +76,7 @@ public final class StartupWindow extends JDialog implements StartupWindowInterfa setResizable(false); } - + @Override public void open() { welcomeWindow.refresh(); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindowProvider.java b/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindowProvider.java index 17daa1830b..195512b183 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindowProvider.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindowProvider.java @@ -27,10 +27,11 @@ import org.sleuthkit.autopsy.coreutils.Logger; /** * Provides the start up window to rest of the application. It may return the * main / default startup window, or a custom one if it has been discovered. - * - * All that is required to create a custom startup window in a module and active it, - * is to implement StartupWindowInterface and register it with lookup as a ServiceProvider. - * The custom startup window is automatically chosen over the default one, given it is the only external module custom startup window. + * + * All that is required to create a custom startup window in a module and active + * it, is to implement StartupWindowInterface and register it with lookup as a + * ServiceProvider. The custom startup window is automatically chosen over the + * default one, given it is the only external module custom startup window. */ public class StartupWindowProvider implements StartupWindowInterface { @@ -54,8 +55,8 @@ public class StartupWindowProvider implements StartupWindowInterface { private void init() { if (startupWindowToUse == null) { //discover the registered windows - Collection startupWindows = - Lookup.getDefault().lookupAll(StartupWindowInterface.class); + Collection startupWindows + = Lookup.getDefault().lookupAll(StartupWindowInterface.class); int windowsCount = startupWindows.size(); if (windowsCount > 2) { @@ -75,14 +76,13 @@ public class StartupWindowProvider implements StartupWindowInterface { } } - + if (startupWindowToUse == null) { logger.log(Level.SEVERE, "Unexpected error, no custom startup window found, using the default"); //NON-NLS startupWindowToUse = new org.sleuthkit.autopsy.casemodule.StartupWindow(); } - - } + } } } @@ -96,8 +96,8 @@ public class StartupWindowProvider implements StartupWindowInterface { @Override public void close() { - if (startupWindowToUse != null) { - startupWindowToUse.close(); - } + if (startupWindowToUse != null) { + startupWindowToUse.close(); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/UpdateRecentCases.java b/Core/src/org/sleuthkit/autopsy/casemodule/UpdateRecentCases.java index 0355fc20fe..147337965b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/UpdateRecentCases.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/UpdateRecentCases.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.casemodule; import javax.swing.JComponent; @@ -29,14 +28,15 @@ import org.openide.util.actions.SystemAction; /** * This class is used to change / update the list of recent cases dynamically. */ - class UpdateRecentCases extends JMenuItem implements DynamicMenuContent { +class UpdateRecentCases extends JMenuItem implements DynamicMenuContent { int length; static boolean hasRecentCase = false; /** the constructor */ UpdateRecentCases(){ - length = RecentCases.LENGTH; + // display last 5 cases. + length = RecentCases.LENGTH - 1; } /** @@ -55,7 +55,7 @@ import org.openide.util.actions.SystemAction; // if it has the recent menus, add them to the component list for (int i = 0; i < length; i++) { - if((!caseName[i].equals(""))){ + if ((!caseName[i].equals(""))) { JMenuItem menuItem = new JMenuItem(caseName[i]); menuItem.setActionCommand(caseName[i].toUpperCase()); menuItem.addActionListener(new RecentItems(caseName[i], casePath[i])); @@ -65,17 +65,16 @@ import org.openide.util.actions.SystemAction; } // if it has recent case, create clear menu - if(hasRecentCase){ + if (hasRecentCase) { comps[length] = new JSeparator(); JMenuItem clearMenu = new JMenuItem( - NbBundle.getMessage(this.getClass(), "UpdateRecentCases.menuItem.clearRecentCases.text")); + NbBundle.getMessage(UpdateRecentCases.class, "UpdateRecentCases.menuItem.clearRecentCases.text")); clearMenu.addActionListener(SystemAction.get(RecentCases.class)); - comps[length+1] = clearMenu; - } - // otherwise, just create a disabled empty menu - else{ + comps[length + 1] = clearMenu; + } // otherwise, just create a disabled empty menu + else { comps = new JComponent[1]; - JMenuItem emptyMenu = new JMenuItem(NbBundle.getMessage(this.getClass(), "UpdateRecentCases.menuItem.empty")); + JMenuItem emptyMenu = new JMenuItem(NbBundle.getMessage(UpdateRecentCases.class, "UpdateRecentCases.menuItem.empty")); emptyMenu.addActionListener(new RecentItems("", "")); comps[0] = emptyMenu; comps[0].setEnabled(false); @@ -84,13 +83,17 @@ import org.openide.util.actions.SystemAction; } /** - * Updates main menu presenters. This method is called only by the main menu processing. + * Updates main menu presenters. This method is called only by the main menu + * processing. * - * @param jcs the previously used menu items returned by previous call to getMenuPresenters() or synchMenuPresenters() - * @return menu a new set of items to show in menu. Can be either an updated old set of instances or a completely new one. + * @param jcs the previously used menu items returned by previous call to + * getMenuPresenters() or synchMenuPresenters() + * + * @return menu a new set of items to show in menu. Can be either an updated + * old set of instances or a completely new one. */ @Override public JComponent[] synchMenuPresenters(JComponent[] jcs) { return getMenuPresenters(); } -} \ No newline at end of file +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/XMLCaseManagement.java b/Core/src/org/sleuthkit/autopsy/casemodule/XMLCaseManagement.java index ca69d93a90..c41269f449 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/XMLCaseManagement.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/XMLCaseManagement.java @@ -46,7 +46,7 @@ import org.xml.sax.SAXException; * * @author jantonius */ - class XMLCaseManagement implements CaseConfigFileInterface { +class XMLCaseManagement implements CaseConfigFileInterface { final static String XSDFILE = "CaseSchema.xsd"; //NON-NLS final static String TOP_ROOT_NAME = "AutopsyCase"; //NON-NLS @@ -323,7 +323,7 @@ import org.xml.sax.SAXException; * Gets the Autopsy Saved Version from the document handler * * @return savedVersion the latest version of autopsy when this case is - * saved + * saved */ protected String getSavedVersion() { if (doc != null) { @@ -437,10 +437,10 @@ import org.xml.sax.SAXException; * Initialize the basic values for a new case management file. Note: this is * the schema version 1.0 * - * @param dirPath case directory path - * @param caseName the name of the config file to be located in the case - * directory - * @param examiner examiner for the case (optional, can be empty string + * @param dirPath case directory path + * @param caseName the name of the config file to be located in the case + * directory + * @param examiner examiner for the case (optional, can be empty string * @param caseNumber case number (optional), can be empty */ protected void create(String dirPath, String caseName, String examiner, String caseNumber) throws CaseActionException { @@ -596,7 +596,6 @@ import org.xml.sax.SAXException; clear(); File file = new File(conFilePath); - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = null; try { @@ -605,18 +604,17 @@ import org.xml.sax.SAXException; } catch (ParserConfigurationException ex) { throw new CaseActionException( NbBundle.getMessage(this.getClass(), "XMLCaseManagement.open.exception.errReadXMLFile.msg", - conFilePath), ex); + conFilePath), ex); } catch (SAXException ex) { throw new CaseActionException( NbBundle.getMessage(this.getClass(), "XMLCaseManagement.open.exception.errReadXMLFile.msg", - conFilePath), ex); + conFilePath), ex); } catch (IOException ex) { throw new CaseActionException( NbBundle.getMessage(this.getClass(), "XMLCaseManagement.open.exception.errReadXMLFile.msg", - conFilePath), ex); + conFilePath), ex); } - doc.getDocumentElement().normalize(); doc.getDocumentElement().normalize(); @@ -632,14 +630,16 @@ import org.xml.sax.SAXException; // throw an error ... clear(); JOptionPane.showMessageDialog(caller, - NbBundle.getMessage(this.getClass(), - "XMLCaseManagement.open.msgDlg.notAutCase.msg", - file.getName(), className), - NbBundle.getMessage(this.getClass(), - "XMLCaseManagement.open.msgDlg.notAutCase.title"), - JOptionPane.ERROR_MESSAGE); + NbBundle.getMessage(this.getClass(), + "XMLCaseManagement.open.msgDlg.notAutCase.msg", + file.getName(), className), + NbBundle.getMessage(this.getClass(), + "XMLCaseManagement.open.msgDlg.notAutCase.title"), + JOptionPane.ERROR_MESSAGE); } else { - /* Autopsy Created Version */ + /* + * Autopsy Created Version + */ String createdVersion = getCreatedVersion(); // get the created version // check if it has the same autopsy version as the current one @@ -648,7 +648,9 @@ import org.xml.sax.SAXException; getRootElement().getElementsByTagName(AUTOPSY_MVERSION_NAME).item(0).setTextContent(autopsySavedVersion); } - /* Schema Version */ + /* + * Schema Version + */ String schemaVer = getSchemaVersion(); // check if it has the same schema version as the current one if (!schemaVer.equals(schemaVersion)) { @@ -664,24 +666,21 @@ import org.xml.sax.SAXException; } } + /** + * When user wants to close the case. This method writes any changes to the + * XML case configuration file, closes it and the document handler, and + * clears all the local variables / fields. + * + */ + @Override + public void close() throws CaseActionException { + writeFile(); // write any changes to xml + clear(); + } - /** - * When user wants to close the case. This method writes any changes to - * the XML case configuration file, closes it and the document handler, - * and clears all the local variables / fields. - * - */ - @Override - public void close() throws CaseActionException { - writeFile(); // write any changes to xml - clear(); - } - - /** - * Clear the internal structures / variables - */ - - + /** + * Clear the internal structures / variables + */ private void clear() { doc = null; caseDirPath = ""; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java index a92fbec990..cea96c6ec0 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java @@ -76,7 +76,6 @@ public class FileManager implements Closeable { logger.log(Level.SEVERE, "Error initializing FileManager and getting number of local file sets"); //NON-NLS } - } /** @@ -198,7 +197,8 @@ public class FileManager implements Closeable { } /** - * Adds a carved file to the VirtualDirectory '$CarvedFiles' in the volume or image given by systemId. + * Adds a carved file to the VirtualDirectory '$CarvedFiles' in the volume + * or image given by systemId. * * @param carvedFileName the name of the carved file (containing appropriate * extension) @@ -221,24 +221,28 @@ public class FileManager implements Closeable { } /** - * Adds a collection of carved files to the VirtualDirectory '$CarvedFiles' in the volume or image given by - * systemId. Creates $CarvedFiles if it does not exist already. + * Adds a collection of carved files to the VirtualDirectory '$CarvedFiles' + * in the volume or image given by systemId. Creates $CarvedFiles if it does + * not exist already. + * + * @param filesToAdd a list of CarvedFileContainer files to add as carved + * files + * + * @return List This is a list of the files added to the + * database * - * @param filesToAdd a list of CarvedFileContainer files to add as carved files - * @return List This is a list of the files added to the database * @throws org.sleuthkit.datamodel.TskCoreException */ public List addCarvedFiles(List filesToAdd) throws TskCoreException { - if (tskCase == null) { - throw new TskCoreException(NbBundle.getMessage(this.getClass(), "FileManager.addCarvedFile.exception.msg")); - } - else { - return tskCase.addCarvedFiles(filesToAdd); - } + if (tskCase == null) { + throw new TskCoreException(NbBundle.getMessage(this.getClass(), "FileManager.addCarvedFile.exception.msg")); + } else { + return tskCase.addCarvedFiles(filesToAdd); + } } /** - * + * * Interface for receiving notifications on folders being added via a * callback */ @@ -277,7 +281,7 @@ public class FileManager implements Closeable { if (!localFile.exists() || !localFile.canRead()) { String msg = NbBundle .getMessage(this.getClass(), "FileManager.addLocalFilesDirs.exception.notReadable.msg", - localFile.getAbsolutePath()); + localFile.getAbsolutePath()); logger.log(Level.SEVERE, msg); throw new TskCoreException(msg); } @@ -296,7 +300,7 @@ public class FileManager implements Closeable { if (localFileAdded == null) { String msg = NbBundle .getMessage(this.getClass(), "FileManager.addLocalFilesDirs.exception.cantAdd.msg", - localRootToAdd.getAbsolutePath()); + localRootToAdd.getAbsolutePath()); logger.log(Level.SEVERE, msg); throw new TskCoreException(msg); } else { @@ -337,7 +341,7 @@ public class FileManager implements Closeable { } catch (TskCoreException ex) { String msg = NbBundle .getMessage(this.getClass(), "FileManager.addLocalFileSetRootDir.exception.errCreateDir.msg", - fileSetName); + fileSetName); logger.log(Level.SEVERE, msg, ex); throw new TskCoreException(msg, ex); } @@ -370,15 +374,14 @@ public class FileManager implements Closeable { if (!localFile.exists()) { throw new TskCoreException( NbBundle.getMessage(this.getClass(), "FileManager.addLocalDirInt.exception.doesntExist.msg", - localFile.getAbsolutePath())); + localFile.getAbsolutePath())); } if (!localFile.canRead()) { throw new TskCoreException( NbBundle.getMessage(this.getClass(), "FileManager.addLocalDirInt.exception.notReadable.msg", - localFile.getAbsolutePath())); + localFile.getAbsolutePath())); } - if (localFile.isDirectory()) { //create virtual folder (we don't have a notion of a 'local folder') final VirtualDirectory childVd = tskCase.addVirtualDirectory(parentVd.getId(), localFile.getName(), trans); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java index fb0f64651c..a163e3d4ca 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java @@ -34,8 +34,8 @@ import org.sleuthkit.datamodel.SleuthkitCase; * A class to manage various services. */ public class Services implements Closeable { - - private final List services = new ArrayList<>(); + + private final List services = new ArrayList<>(); private final FileManager fileManager; private final TagsManager tagsManager; private final KeywordSearchService keywordSearchService; @@ -43,18 +43,18 @@ public class Services implements Closeable { public Services(SleuthkitCase tskCase) { fileManager = new FileManager(tskCase); services.add(fileManager); - + tagsManager = new TagsManager(tskCase); services.add(tagsManager); - + keywordSearchService = Lookup.getDefault().lookup(KeywordSearchService.class); services.add(keywordSearchService); } - + public FileManager getFileManager() { return fileManager; } - + public TagsManager getTagsManager() { return tagsManager; } @@ -62,12 +62,12 @@ public class Services implements Closeable { public KeywordSearchService getKeywordSearchService() { return keywordSearchService; } - + @Override public void close() throws IOException { for (Closeable service : services) { service.close(); } } - + } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java index 83c626f9e1..62ad1d4ab9 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.contentviewers; import java.awt.Component; @@ -31,13 +30,13 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; /** - * Shows file metadata as a list to make it easy to copy and paste. - * Typically shows the same data that can also be found in the ResultViewer table, - * just a different order and allows the full path to be visible in the bottom area. + * Shows file metadata as a list to make it easy to copy and paste. Typically + * shows the same data that can also be found in the ResultViewer table, just a + * different order and allows the full path to be visible in the bottom area. */ @ServiceProvider(service = DataContentViewer.class, position = 3) -public class Metadata extends javax.swing.JPanel implements DataContentViewer -{ +public class Metadata extends javax.swing.JPanel implements DataContentViewer { + /** * Creates new form Metadata */ @@ -79,38 +78,32 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer private javax.swing.JTextPane jTextPane1; // End of variables declaration//GEN-END:variables - private void customizeComponents(){ + private void customizeComponents() { /* - jTextPane1.setComponentPopupMenu(rightClickMenu); - ActionListener actList = new ActionListener(){ - @Override - public void actionPerformed(ActionEvent e){ - JMenuItem jmi = (JMenuItem) e.getSource(); - if(jmi.equals(copyMenuItem)) - outputViewPane.copy(); - else if(jmi.equals(selectAllMenuItem)) - outputViewPane.selectAll(); - } - }; - copyMenuItem.addActionListener(actList); - selectAllMenuItem.addActionListener(actList); - */ - + * jTextPane1.setComponentPopupMenu(rightClickMenu); ActionListener + * actList = new ActionListener(){ @Override public void + * actionPerformed(ActionEvent e){ JMenuItem jmi = (JMenuItem) + * e.getSource(); if(jmi.equals(copyMenuItem)) outputViewPane.copy(); + * else if(jmi.equals(selectAllMenuItem)) outputViewPane.selectAll(); } + * }; copyMenuItem.addActionListener(actList); + * selectAllMenuItem.addActionListener(actList); + */ + Utilities.configureTextPaneAsHtml(jTextPane1); } - + private void setText(String str) { jTextPane1.setText("" + str + ""); //NON-NLS } - + private void startTable(StringBuilder sb) { sb.append(""); //NON-NLS } - + private void endTable(StringBuilder sb) { sb.append("
"); //NON-NLS } - + private void addRow(StringBuilder sb, String key, String value) { sb.append(""); //NON-NLS sb.append(key); @@ -118,7 +111,7 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer sb.append(value); sb.append(""); //NON-NLS } - + @Override public void setNode(Node node) { AbstractFile file = node.getLookup().lookup(AbstractFile.class); @@ -126,40 +119,43 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer setText(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.nonFilePassedIn")); return; } - + StringBuilder sb = new StringBuilder(); startTable(sb); - + try { addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.name"), file.getUniquePath()); } catch (TskCoreException ex) { addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.name"), file.getParentPath() + "/" + file.getName()); } - + addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.type"), file.getType().getName()); - addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.size"), new Long(file.getSize()).toString() ); + addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.size"), new Long(file.getSize()).toString()); addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.fileNameAlloc"), file.getDirFlagAsString()); addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.metadataAlloc"), file.getMetaFlagsAsString()); addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.modified"), ContentUtils.getStringTime(file.getMtime(), file)); addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.accessed"), ContentUtils.getStringTime(file.getAtime(), file)); - addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.created"), ContentUtils.getStringTime(file.getCrtime(), file)); - addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.changed"), ContentUtils.getStringTime(file.getCtime(), file)); - + addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.created"), ContentUtils.getStringTime(file.getCrtime(), file)); + addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.changed"), ContentUtils.getStringTime(file.getCtime(), file)); + String md5 = file.getMd5Hash(); if (md5 == null) { md5 = NbBundle.getMessage(this.getClass(), "Metadata.tableRowContent.md5notCalc"); } addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.md5"), md5); addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.hashLookupResults"), file.getKnown().toString()); - + addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.internalid"), new Long(file.getId()).toString()); if (file.getType().compareTo(TSK_DB_FILES_TYPE_ENUM.LOCAL) == 0) { addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.localPath"), file.getLocalAbsPath()); } - + endTable(sb); - - /* If we have a file system file, grab the more detailed metadata text too */ + + /* + * If we have a file system file, grab the more detailed metadata text + * too + */ try { if (file instanceof FsContent) { FsContent fsFile = (FsContent) file; @@ -175,10 +171,10 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer } catch (TskCoreException ex) { sb.append(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.exceptionNotice.text")).append(ex.getLocalizedMessage()); } - + setText(sb.toString()); jTextPane1.setCaretPosition(0); - this.setCursor(null); + this.setCursor(null); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/core/Installer.java b/Core/src/org/sleuthkit/autopsy/core/Installer.java index 25a71e5988..8f43e21eef 100644 --- a/Core/src/org/sleuthkit/autopsy/core/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/core/Installer.java @@ -45,18 +45,19 @@ public class Installer extends ModuleInstall { static { loadDynLibraries(); } - + private static void loadDynLibraries() { - /* On Windows, we distribute dlls that libtsk_jni depend on. - * If libtsk_jni tries to load them, they will not be found by - * Windows because they are in special NetBeans folders. So, we - * manually load them from within Autopsy so that they are found - * via the NetBeans loading setup. These are copied by the build - * script when making the ZIP file. In a development environment - * they will need to be loaded from standard places in your system. - * + /* + * On Windows, we distribute dlls that libtsk_jni depend on. If + * libtsk_jni tries to load them, they will not be found by Windows + * because they are in special NetBeans folders. So, we manually load + * them from within Autopsy so that they are found via the NetBeans + * loading setup. These are copied by the build script when making the + * ZIP file. In a development environment they will need to be loaded + * from standard places in your system. + * * On non-Windows platforms, we assume the dependncies are all installed - * and loadable (i.e. a 'make install' was done). + * and loadable (i.e. a 'make install' was done). */ if (PlatformUtil.isWindowsOS()) { try { @@ -71,21 +72,21 @@ public class Installer extends ModuleInstall { } try { - System.loadLibrary("zlib"); //NON-NLS - logger.log(Level.INFO, "ZLIB library loaded loaded"); //NON-NLS + System.loadLibrary("zlib"); //NON-NLS + logger.log(Level.INFO, "ZLIB library loaded loaded"); //NON-NLS } catch (UnsatisfiedLinkError e) { - logger.log(Level.SEVERE, "Error loading ZLIB library, ", e); //NON-NLS + logger.log(Level.SEVERE, "Error loading ZLIB library, ", e); //NON-NLS } try { - System.loadLibrary("libewf"); //NON-NLS - logger.log(Level.INFO, "EWF library loaded"); //NON-NLS + System.loadLibrary("libewf"); //NON-NLS + logger.log(Level.INFO, "EWF library loaded"); //NON-NLS } catch (UnsatisfiedLinkError e) { - logger.log(Level.SEVERE, "Error loading EWF library, ", e); //NON-NLS + logger.log(Level.SEVERE, "Error loading EWF library, ", e); //NON-NLS } - } - } - + } + } + public Installer() { logger.log(Level.INFO, "core installer created"); //NON-NLS javaFxInit = false; @@ -98,12 +99,14 @@ public class Installer extends ModuleInstall { /** * Check if JavaFx initialized - * @return false if java fx not initialized (classes coult not load), true if initialized + * + * @return false if java fx not initialized (classes coult not load), true + * if initialized */ public static boolean isJavaFxInited() { return javaFxInit; } - + private static void initJavaFx() { //initialize java fx if exists System.setProperty("javafx.macosx.embedded", "true"); @@ -117,7 +120,7 @@ public class Installer extends ModuleInstall { final String msg = NbBundle.getMessage(Installer.class, "Installer.errorInitJavafx.msg"); final String details = NbBundle.getMessage(Installer.class, "Installer.errorInitJavafx.details"); logger.log(Level.SEVERE, msg - + details, e); + + details, e); WindowManager.getDefault().invokeWhenUIReady(new Runnable() { @Override @@ -132,11 +135,11 @@ public class Installer extends ModuleInstall { File pythonModulesDir = new File(PlatformUtil.getUserPythonModulesPath()); pythonModulesDir.mkdir(); } - + @Override public void restored() { - super.restored(); - ensurePythonModulesFolderExists(); + super.restored(); + ensurePythonModulesFolderExists(); initJavaFx(); for (ModuleInstall mi : packageInstallers) { try { diff --git a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java index 7ce18930a4..5349915871 100755 --- a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java +++ b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java @@ -34,7 +34,7 @@ public final class UserPreferences { public static final String HIDE_KNOWN_FILES_IN_VIEWS_TREE = "HideKnownFilesInViewsTree"; //NON-NLS public static final String DISPLAY_TIMES_IN_LOCAL_TIME = "DisplayTimesInLocalTime"; //NON-NLS public static final String NUMBER_OF_FILE_INGEST_THREADS = "NumberOfFileIngestThreads"; //NON-NLS - + // Prevent instantiation. private UserPreferences() { } @@ -70,21 +70,21 @@ public final class UserPreferences { public static void setHideKnownFilesInViewsTree(boolean value) { preferences.putBoolean(HIDE_KNOWN_FILES_IN_VIEWS_TREE, value); } - + public static boolean displayTimesInLocalTime() { return preferences.getBoolean(DISPLAY_TIMES_IN_LOCAL_TIME, true); } public static void setDisplayTimesInLocalTime(boolean value) { preferences.putBoolean(DISPLAY_TIMES_IN_LOCAL_TIME, value); - } - + } + public static int numberOfFileIngestThreads() { return preferences.getInt(NUMBER_OF_FILE_INGEST_THREADS, 2); } public static void setNumberOfFileIngestThreads(int value) { preferences.putInt(NUMBER_OF_FILE_INGEST_THREADS, value); - } - + } + } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/BlackboardResultViewer.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/BlackboardResultViewer.java index b487e093d5..c196adae4c 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/BlackboardResultViewer.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/BlackboardResultViewer.java @@ -16,39 +16,38 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - - package org.sleuthkit.autopsy.corecomponentinterfaces; import java.beans.PropertyChangeListener; import org.sleuthkit.datamodel.BlackboardArtifact; /** - * Additional functionality of viewers - * supporting black board results - * such as the directory tree + * Additional functionality of viewers supporting black board results such as + * the directory tree */ public interface BlackboardResultViewer { - + public static final String FINISHED_DISPLAY_EVT = "FINISHED_DISPLAY_EVT"; //NON-NLS - - + /** * View artifact in a viewer + * * @param art artifact to view */ - void viewArtifact(BlackboardArtifact art); - - /** + void viewArtifact(BlackboardArtifact art); + + /** * View content associated with the artifact + * * @param art artifact content to view */ - void viewArtifactContent(BlackboardArtifact art); - - /** - * Add listener to fire an action when viewer is done displaying - * @param l - */ - void addOnFinishedListener(PropertyChangeListener l); - + void viewArtifactContent(BlackboardArtifact art); + + /** + * Add listener to fire an action when viewer is done displaying + * + * @param l + */ + void addOnFinishedListener(PropertyChangeListener l); + } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/ContextMenuActionsProvider.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/ContextMenuActionsProvider.java index b6a96eb1aa..5f113519a8 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/ContextMenuActionsProvider.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/ContextMenuActionsProvider.java @@ -26,12 +26,14 @@ import javax.swing.Action; * menus in Autopsy. */ public interface ContextMenuActionsProvider { + /** - * Gets context menu Actions for the currently selected data model objects - * exposed by the NetBeans Lookup of the active TopComponent. Implementers - * should discover the selected objects by calling - * org.openide.util.Utilities.actionsGlobalContext().lookupAll() for the + * Gets context menu Actions for the currently selected data model objects + * exposed by the NetBeans Lookup of the active TopComponent. Implementers + * should discover the selected objects by calling + * org.openide.util.Utilities.actionsGlobalContext().lookupAll() for the * org.sleuthkit.datamodel classes of interest to the provider. + * * @return A list, possibly empty, of Action objects. */ public List getActions(); diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/CoreComponentControl.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/CoreComponentControl.java index ba6e172b7d..0c21932b05 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/CoreComponentControl.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/CoreComponentControl.java @@ -32,7 +32,8 @@ import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.corecomponents.DataContentTopComponent; /** - * Responsible for opening and closing the core windows when a case is opened and closed. + * Responsible for opening and closing the core windows when a case is opened + * and closed. * * @author jantonius */ @@ -40,13 +41,13 @@ public class CoreComponentControl { private static final Logger logger = Logger.getLogger(CoreComponentControl.class.getName()); private static final String DIRECTORY_TREE = NbBundle.getMessage(CoreComponentControl.class, - "CoreComponentControl.CTL_DirectoryTreeTopComponent"); + "CoreComponentControl.CTL_DirectoryTreeTopComponent"); private static final String FAVORITES = NbBundle.getMessage(CoreComponentControl.class, - "CoreComponentControl.CTL_FavoritesTopComponent"); + "CoreComponentControl.CTL_FavoritesTopComponent"); /** - * Opens all TopComponent windows that are needed ({@link DataExplorer}, {@link DataResult}, and - * {@link DataContent}) + * Opens all TopComponent windows that are needed + * ({@link DataExplorer}, {@link DataResult}, and {@link DataContent}) */ public static void openCoreWindows() { // TODO: there has to be a better way to do this. @@ -77,19 +78,18 @@ public class CoreComponentControl { } /** - * Closes all TopComponent windows that needed ({@link DataExplorer}, {@link DataResult}, and - * {@link DataContent}). - * - * Note: The DataContent Top Component must be closed before the Directory Tree - * and Favorites Top Components. Otherwise a NullPointerException will be thrown - * from JFXPanel. + * Closes all TopComponent windows that needed + * ({@link DataExplorer}, {@link DataResult}, and {@link DataContent}). + * + * Note: The DataContent Top Component must be closed before the Directory + * Tree and Favorites Top Components. Otherwise a NullPointerException will + * be thrown from JFXPanel. */ public static void closeCoreWindows() { WindowManager wm = WindowManager.getDefault(); Set modes = wm.getModes(); Iterator iter = wm.getModes().iterator(); - TopComponent directoryTree = null; TopComponent favorites = null; String tcName = ""; @@ -111,7 +111,7 @@ public class CoreComponentControl { } } } - + if (directoryTree != null) { directoryTree.close(); } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataContent.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataContent.java index e0d5716a72..92d0e39547 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataContent.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataContent.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.corecomponentinterfaces; import java.beans.PropertyChangeListener; @@ -32,6 +31,7 @@ public interface DataContent extends PropertyChangeListener { /** * Sets the "selected" node in this class + * * @param selectedNode node to use */ void setNode(Node selectedNode); diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataContentViewer.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataContentViewer.java index 7126f0e912..f4fe2e0a8f 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataContentViewer.java @@ -16,52 +16,51 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.corecomponentinterfaces; import java.awt.Component; import org.openide.nodes.Node; /** - * Interface that DataContentViewer modules must implement. - * These modules analyze an individual file that the user has selected and display - * results in some form of JPanel. We find it easiest to use the NetBeans IDE to first - * make a "JPanel Form" class and then have it implement DataContentViewer. This allows - * you to easily use the UI builder for the layout. + * Interface that DataContentViewer modules must implement. These modules + * analyze an individual file that the user has selected and display results in + * some form of JPanel. We find it easiest to use the NetBeans IDE to first make + * a "JPanel Form" class and then have it implement DataContentViewer. This + * allows you to easily use the UI builder for the layout. */ public interface DataContentViewer { + /** - * Autopsy will call this when this panel is focused with the file that - * should be analyzed. When called with null, must - * clear all references to previous nodes. + * Autopsy will call this when this panel is focused with the file that + * should be analyzed. When called with null, must clear all references to + * previous nodes. */ public void setNode(Node selectedNode); - + /** - * Returns the title of this viewer to display in the tab. + * Returns the title of this viewer to display in the tab. */ public String getTitle(); - + /** - * Returns a short description of this viewer to use as a tool tip for - * its tab. + * Returns a short description of this viewer to use as a tool tip for its + * tab. */ public String getToolTip(); /** - * Create and return a new instance of your viewer. - * The reason that this is needed is because the specific - * viewer modules will be found via NetBeans Lookup and - * the type will only be DataContentViewer. This method is - * used to get an instance of your specific type. + * Create and return a new instance of your viewer. The reason that this is + * needed is because the specific viewer modules will be found via NetBeans + * Lookup and the type will only be DataContentViewer. This method is used + * to get an instance of your specific type. + * * @returns A new instance of the viewer */ public DataContentViewer createInstance(); - + /** - * Return the Swing Component to display. - * Implementations of this method that extend JPanel - * and do a 'return this;'. Otherwise return an internal + * Return the Swing Component to display. Implementations of this method + * that extend JPanel and do a 'return this;'. Otherwise return an internal * instance of the JPanel. */ public Component getComponent(); @@ -72,26 +71,29 @@ public interface DataContentViewer { public void resetComponent(); /** - * Checks whether the given node is supported by the viewer. - * This will be used to enable or disable the tab for the viewer. + * Checks whether the given node is supported by the viewer. This will be + * used to enable or disable the tab for the viewer. + * * @param node Node to check for support + * * @return True if the node can be displayed / processed, else false */ public boolean isSupported(Node node); - - /** - * Checks whether the given viewer is preferred for the Node. - * This is a bit subjective, but the idea is that Autopsy wants to display - * the most relevant tab. The more generic the viewer, the lower - * the return value should be. This will only be called on viewers that - * support the given node. - * + + /** + * Checks whether the given viewer is preferred for the Node. This is a bit + * subjective, but the idea is that Autopsy wants to display the most + * relevant tab. The more generic the viewer, the lower the return value + * should be. This will only be called on viewers that support the given + * node. + * * @param node Node to check for preference + * * @return an int (0-10) higher return means the viewer has higher priority - * 0 means not supported - * 1 to 2 means the module will display all file types (such as the hex viewer) - * 3-10 are prioritized by Content viewer developer. Modules that operate on very - * few file types should be towards 10. + * 0 means not supported 1 to 2 means the module will display all + * file types (such as the hex viewer) 3-10 are prioritized by + * Content viewer developer. Modules that operate on very few file + * types should be towards 10. */ public int isPreferred(Node node); } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResult.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResult.java index 96e2750a94..191a851b9a 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResult.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResult.java @@ -35,20 +35,20 @@ public interface DataResult { /** * Gets the unique TopComponent ID of this class. * - * @return preferredID the unique ID + * @return preferredID the unique ID */ public String getPreferredID(); /** * Sets the title of this TopComponent - * - * @param title the given title (String) + * + * @param title the given title (String) */ public void setTitle(String title); - - + /** * Sets the descriptive context text at the top of the pane. + * * @param pathText Descriptive text giving context for the current results */ public void setPath(String pathText); @@ -59,10 +59,11 @@ public interface DataResult { * @return true if it is the main instance, otherwise false */ public boolean isMain(); - + /** * Get child viewers within this DataResult - * @return + * + * @return */ public List getViewers(); } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResultViewer.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResultViewer.java index 8a4b55e893..f838e693d5 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResultViewer.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResultViewer.java @@ -16,19 +16,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - - package org.sleuthkit.autopsy.corecomponentinterfaces; 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. - * + * Interface for the different viewers that show a set of nodes in the + * DataResult area. AbstractDataResultViewer has default implementations for the + * action handlers. + * */ public interface DataResultViewer { + /** * Set the root node to display in this viewer. When called with null, must * clear all references to previous nodes. @@ -44,7 +44,7 @@ public interface DataResultViewer { * Get a new instance of DataResultViewer */ public DataResultViewer createInstance(); - + /** * Get the Swing component (i.e. JPanel) for this viewer */ @@ -56,34 +56,39 @@ public interface DataResultViewer { public void resetComponent(); /** - * Frees the objects that have been allocated by this viewer, in - * preparation for permanently disposing of it. + * Frees the objects that have been allocated by this viewer, in preparation + * for permanently disposing of it. */ public void clearComponent(); - + /** * Expand node, if supported by the viewed + * * @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 + * Checks whether the currently selected root node is supported by this + * viewer + * * @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 user - * @param contentViewer content viewer to respond to selection events from this viewer + * Set a custom content viewer to respond to selection events from this + * result viewer. If not set, the default content viewer is user + * + * @param contentViewer content viewer to respond to selection events from + * this viewer */ public void setContentViewer(DataContent contentViewer); } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessor.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessor.java index f76f6b29a1..f3fedd6be2 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessor.java @@ -18,73 +18,71 @@ */ package org.sleuthkit.autopsy.corecomponentinterfaces; - import javax.swing.JPanel; /** - * Interface used by the Add DataSource wizard to allow different - * types of data sources to be added to a case. Examples of data - * sources include disk images, local files, etc. - * - * The interface provides a uniform mechanism for the Autopsy UI - * to: - * - Collect details from the user about the data source to be processed. - * - Process the data source in the background and add data to the database - * - Provides progress feedback to the user / UI. + * Interface used by the Add DataSource wizard to allow different types of data + * sources to be added to a case. Examples of data sources include disk images, + * local files, etc. + * + * The interface provides a uniform mechanism for the Autopsy UI to: - Collect + * details from the user about the data source to be processed. - Process the + * data source in the background and add data to the database - Provides + * progress feedback to the user / UI. */ public interface DataSourceProcessor { - + /** - * The DSP Panel may fire Property change events - * The caller must enure to add itself as a listener and - * then react appropriately to the events + * The DSP Panel may fire Property change events The caller must enure to + * add itself as a listener and then react appropriately to the events */ enum DSP_PANEL_EVENT { - UPDATE_UI, ///< the content of JPanel has changed that MAY warrant updates to the caller UI + + UPDATE_UI, ///< the content of JPanel has changed that MAY warrant updates to the caller UI FOCUS_NEXT ///< the caller UI may move focus the the next UI element, following the panel. }; - - - /** - * Returns the type of Data Source it handles. - * This name gets displayed in the drop-down listbox - */ + + /** + * Returns the type of Data Source it handles. This name gets displayed in + * the drop-down listbox + */ String getDataSourceType(); - - /** - * Returns the picker panel to be displayed along with any other - * runtime options supported by the data source handler. The - * DSP is responsible for storing the settings so that a later - * call to run() will have the user-specified settings. - * - * Should be less than 544 pixels wide and 173 pixels high. - */ + + /** + * Returns the picker panel to be displayed along with any other runtime + * options supported by the data source handler. The DSP is responsible for + * storing the settings so that a later call to run() will have the + * user-specified settings. + * + * Should be less than 544 pixels wide and 173 pixels high. + */ JPanel getPanel(); - - /** - * Called to validate the input data in the panel. - * Returns true if no errors, or - * Returns false if there is an error. - */ + + /** + * Called to validate the input data in the panel. Returns true if no + * errors, or Returns false if there is an error. + */ boolean isPanelValid(); - - /** - * Called to invoke the handling of data source in the background. - * Returns after starting the background thread. - * - * @param progressPanel progress panel to be updated while processing - * @param dspCallback Contains the callback method DataSourceProcessorCallback.done() that the DSP must call when the background thread finishes with errors and status. - */ + + /** + * Called to invoke the handling of data source in the background. Returns + * after starting the background thread. + * + * @param progressPanel progress panel to be updated while processing + * @param dspCallback Contains the callback method + * DataSourceProcessorCallback.done() that the DSP must + * call when the background thread finishes with errors + * and status. + */ void run(DataSourceProcessorProgressMonitor progressPanel, DataSourceProcessorCallback dspCallback); - - - /** - * Called to cancel the background processing. - */ + + /** + * Called to cancel the background processing. + */ void cancel(); - - /** - * Called to reset/reinitialize the DSP. - */ + + /** + * Called to reset/reinitialize the DSP. + */ void reset(); } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessorCallback.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessorCallback.java index 76acfd2efc..5c0f649d74 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessorCallback.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessorCallback.java @@ -32,20 +32,22 @@ import org.sleuthkit.datamodel.Content; public abstract class DataSourceProcessorCallback { public enum DataSourceProcessorResult { - NO_ERRORS, ///< No errors were encountered while ading the data source + + NO_ERRORS, ///< No errors were encountered while ading the data source CRITICAL_ERRORS, ///< No data was added to the database. There were fundamental errors processing the data (such as no data or system failure). NONCRITICAL_ERRORS, ///< There was data added to the database, but there were errors from data corruption or a small number of minor issues. }; - /** - * Called by a DSP implementation when it is done adding a data source - * to the database. Users of the DSP can override this method if they do - * not want to be notified on the EDT. Otherwise, this method will call - * doneEDT() with the same arguments. - * @param result Code for status - * @param errList List of error strings - * @param newContents List of root Content objects that were added to database. Typically only one is given. + * Called by a DSP implementation when it is done adding a data source to + * the database. Users of the DSP can override this method if they do not + * want to be notified on the EDT. Otherwise, this method will call + * doneEDT() with the same arguments. + * + * @param result Code for status + * @param errList List of error strings + * @param newContents List of root Content objects that were added to + * database. Typically only one is given. */ public void done(DataSourceProcessorResult result, List errList, List newContents) { @@ -63,13 +65,14 @@ public abstract class DataSourceProcessorCallback { } /** - * Called by done() if the default implementation is used. Users of DSPs + * Called by done() if the default implementation is used. Users of DSPs * that have UI updates to do after the DSP is finished adding the DS can * implement this method to receive the updates on the EDT. * - * @param result Code for status - * @param errList List of error strings - * @param newContents List of root Content objects that were added to database. Typically only one is given. - */ + * @param result Code for status + * @param errList List of error strings + * @param newContents List of root Content objects that were added to + * database. Typically only one is given. + */ public abstract void doneEDT(DataSourceProcessorResult result, List errList, List newContents); }; diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessorProgressMonitor.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessorProgressMonitor.java index 28001a9d62..31797c6664 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessorProgressMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessorProgressMonitor.java @@ -19,15 +19,15 @@ package org.sleuthkit.autopsy.corecomponentinterfaces; /** - * An GUI agnostic DataSourceProcessorProgressMonitor interface for DataSourceProcesssors to - * indicate progress. - * It models after a JProgressbar though it could use any underlying implementation (or NoOps) + * An GUI agnostic DataSourceProcessorProgressMonitor interface for + * DataSourceProcesssors to indicate progress. It models after a JProgressbar + * though it could use any underlying implementation (or NoOps) */ public interface DataSourceProcessorProgressMonitor { - + void setIndeterminate(boolean indeterminate); - + void setProgress(int progress); - - void setProgressText(String text); + + void setProgressText(String text); } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AboutWindowAction.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AboutWindowAction.java index 73d36c81f8..4a02720d5a 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AboutWindowAction.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AboutWindowAction.java @@ -28,7 +28,8 @@ import org.openide.awt.ActionRegistration; import org.openide.util.NbBundle; /** - * Action to open custom implementation of the "About" window from the Help menu. + * Action to open custom implementation of the "About" window from the Help + * menu. */ @ActionID(id = "org.sleuthkit.autopsy.corecomponents.AboutWindowAction", category = "Help") @ActionRegistration(displayName = "#CTL_CustomAboutAction", iconInMenu = true, lazy = false) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AboutWindowPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AboutWindowPanel.java index a92c5f70c6..abba7ce94b 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AboutWindowPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AboutWindowPanel.java @@ -63,8 +63,8 @@ public final class AboutWindowPanel extends JPanel implements HyperlinkListener initComponents(); logoLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); description.setText(org.openide.util.NbBundle.getMessage(AboutWindowPanel.class, - "LBL_Description", new Object[]{getProductVersionValue(), getJavaValue(), getVMValue(), - getOperatingSystemValue(), getEncodingValue(), getSystemLocaleValue(), getUserDirValue(), getSleuthKitVersionValue(), Version.getNetbeansBuild(), Version.getBuildType().toString()})); + "LBL_Description", new Object[]{getProductVersionValue(), getJavaValue(), getVMValue(), + getOperatingSystemValue(), getEncodingValue(), getSystemLocaleValue(), getUserDirValue(), getSleuthKitVersionValue(), Version.getNetbeansBuild(), Version.getBuildType().toString()})); description.addHyperlinkListener(this); copyright.addHyperlinkListener(this); copyright.setBackground(getBackground()); @@ -74,7 +74,6 @@ public final class AboutWindowPanel extends JPanel implements HyperlinkListener } - // //GEN-BEGIN:initComponents private void initComponents() { @@ -228,30 +227,30 @@ private void logoLabelMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:e private static String getOperatingSystemValue() { return NbBundle.getMessage(AboutWindowPanel.class, "Format_OperatingSystem_Value", - System.getProperty("os.name", //NON-NLS - NbBundle.getMessage(AboutWindowPanel.class, - "ProductInformationPanel.propertyUnknown.text")), - System.getProperty("os.version", //NON-NLS - NbBundle.getMessage(AboutWindowPanel.class, - "ProductInformationPanel.propertyUnknown.text")), - System.getProperty("os.arch", //NON-NLS - NbBundle.getMessage(AboutWindowPanel.class, - "ProductInformationPanel.propertyUnknown.text"))); + System.getProperty("os.name", //NON-NLS + NbBundle.getMessage(AboutWindowPanel.class, + "ProductInformationPanel.propertyUnknown.text")), + System.getProperty("os.version", //NON-NLS + NbBundle.getMessage(AboutWindowPanel.class, + "ProductInformationPanel.propertyUnknown.text")), + System.getProperty("os.arch", //NON-NLS + NbBundle.getMessage(AboutWindowPanel.class, + "ProductInformationPanel.propertyUnknown.text"))); } private static String getJavaValue() { return System.getProperty("java.version", //NON-NLS - NbBundle.getMessage(AboutWindowPanel.class, - "ProductInformationPanel.propertyUnknown.text")); + NbBundle.getMessage(AboutWindowPanel.class, + "ProductInformationPanel.propertyUnknown.text")); } private static String getVMValue() { return NbBundle.getMessage(AboutWindowPanel.class, - "ProductInformationPanel.getVMValue.text", - System.getProperty("java.vm.name", //NON-NLS - NbBundle.getMessage(AboutWindowPanel.class, - "ProductInformationPanel.propertyUnknown.text")), - System.getProperty("java.vm.version", "")); //NON-NLS + "ProductInformationPanel.getVMValue.text", + System.getProperty("java.vm.name", //NON-NLS + NbBundle.getMessage(AboutWindowPanel.class, + "ProductInformationPanel.propertyUnknown.text")), + System.getProperty("java.vm.version", "")); //NON-NLS } private static String getSystemLocaleValue() { @@ -265,7 +264,7 @@ private void logoLabelMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:e private static String getEncodingValue() { return System.getProperty("file.encoding", //NON-NLS - NbBundle.getMessage(AboutWindowPanel.class, "ProductInformationPanel.propertyUnknown.text")); + NbBundle.getMessage(AboutWindowPanel.class, "ProductInformationPanel.propertyUnknown.text")); } public void setCopyright(String text) { diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AbstractDataResultViewer.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AbstractDataResultViewer.java index 782f38ec5e..13fda58c20 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AbstractDataResultViewer.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AbstractDataResultViewer.java @@ -31,12 +31,12 @@ 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. + * 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. */ - abstract class AbstractDataResultViewer extends JPanel implements DataResultViewer, Provider { +abstract class AbstractDataResultViewer extends JPanel implements DataResultViewer, Provider { private static final Logger logger = Logger.getLogger(AbstractDataResultViewer.class.getName()); protected transient ExplorerManager em; @@ -49,19 +49,19 @@ import org.sleuthkit.autopsy.coreutils.Logger; /** * 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 + * 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. + * the ExplorerManager.find() method. */ public AbstractDataResultViewer(ExplorerManager explorerManager) { this.em = explorerManager; initialize(); } - + /** * This constructor can be used by AbstractDataResultViewers that do not - * need to make Node selections available to Actions via the action global + * need to make Node selections available to Actions via the action global * context lookup. */ public AbstractDataResultViewer() { @@ -72,9 +72,9 @@ import org.sleuthkit.autopsy.coreutils.Logger; private void initialize() { //DataContent is designed to return only the default viewer from lookup //use the default one unless set otherwise - contentViewer = Lookup.getDefault().lookup(DataContent.class); + contentViewer = Lookup.getDefault().lookup(DataContent.class); } - + @Override public void clearComponent() { } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.java index 41ff7988b8..9dd6ab12ba 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.java @@ -11,38 +11,43 @@ import javax.swing.JFrame; import javax.swing.JPanel; /** - * Displays a panel in a new clean dialog. A clean dialog contains nothing - * but the panel given to it. No additional buttons or features, except - * the default close operation, which is set to dispose. + * Displays a panel in a new clean dialog. A clean dialog contains nothing but + * the panel given to it. No additional buttons or features, except the default + * close operation, which is set to dispose. */ - public class AdvancedConfigurationCleanDialog extends javax.swing.JDialog { +public class AdvancedConfigurationCleanDialog extends javax.swing.JDialog { - /** Creates new form AdvancedConfigurationDialog */ + /** + * Creates new form AdvancedConfigurationDialog + */ public AdvancedConfigurationCleanDialog() { this(false); } - - /** Creates new form AdvancedConfigurationDialog */ + + /** + * Creates new form AdvancedConfigurationDialog + */ public AdvancedConfigurationCleanDialog(boolean resizable) { super(new JFrame(), true); setResizable(resizable); - if(resizable) { + if (resizable) { this.setIconImage(null); } initComponents(); } - + /** * Display the given panel on a clean dialog. + * * @param panel the panel to display */ public void display(JPanel panel) { this.setTitle(panel.getName()); - + panel.setAlignmentX(Component.CENTER_ALIGNMENT); this.add(panel, 0); this.pack(); - + Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); // set the popUp window / JFrame int w = this.getSize().width; @@ -50,10 +55,10 @@ import javax.swing.JPanel; // set the location of the popUp Window on the center of the screen setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); - + this.setVisible(true); } - + /** * Close the dialog. */ diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationDialog.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationDialog.java index e2a787a37a..f050d05c5b 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationDialog.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationDialog.java @@ -37,30 +37,33 @@ import javax.swing.JPanel; */ public class AdvancedConfigurationDialog extends javax.swing.JDialog { - /** Creates new form AdvancedConfigurationDialog */ + /** + * Creates new form AdvancedConfigurationDialog + */ public AdvancedConfigurationDialog() { this(false); } - - /** Creates new form AdvancedConfigurationDialog */ + + /** + * Creates new form AdvancedConfigurationDialog + */ public AdvancedConfigurationDialog(boolean resizable) { super(new JFrame(), true); setResizable(resizable); - if(resizable) { + if (resizable) { this.setIconImage(null); } initComponents(); } - + public void display(JPanel panel) { this.setTitle(panel.getName()); - panel.setAlignmentX(Component.CENTER_ALIGNMENT); //applyButton.setAlignmentX(Component.CENTER_ALIGNMENT); this.add(panel, 0); this.pack(); - + Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); // set the popUp window / JFrame int w = this.getSize().width; @@ -68,14 +71,14 @@ public class AdvancedConfigurationDialog extends javax.swing.JDialog { // set the location of the popUp Window on the center of the screen setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); - + this.setVisible(true); } - /** 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. + /** + * 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") // //GEN-BEGIN:initComponents diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java index 5dc357fbc7..e683de4c0d 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java @@ -67,7 +67,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { recommendedFileIngestThreadCount = 1; } numberOfFileIngestThreadsComboBox.setModel(new DefaultComboBoxModel<>(fileIngestThreadCountChoices)); - restartRequiredLabel.setText(NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.restartRequiredLabel.text", recommendedFileIngestThreadCount)); + restartRequiredLabel.setText(NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.restartRequiredLabel.text", recommendedFileIngestThreadCount)); // TODO listen to changes in form fields and call controller.changed() } @@ -80,7 +80,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { boolean useLocalTime = UserPreferences.displayTimesInLocalTime(); useLocalTimeRB.setSelected(useLocalTime); useGMTTimeRB.setSelected(!useLocalTime); - numberOfFileIngestThreadsComboBox.setSelectedItem(UserPreferences.numberOfFileIngestThreads()); + numberOfFileIngestThreadsComboBox.setSelectedItem(UserPreferences.numberOfFileIngestThreads()); } void store() { diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentPanel.java index 7e5a235c0c..0e6be17369 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentPanel.java @@ -40,60 +40,60 @@ import org.sleuthkit.datamodel.TskCoreException; /** * */ - public class DataContentPanel extends javax.swing.JPanel implements DataContent, ChangeListener { - +public class DataContentPanel extends javax.swing.JPanel implements DataContent, ChangeListener { + private static Logger logger = Logger.getLogger(DataContentPanel.class.getName()); - private final List viewers = new ArrayList<>();; + private final List viewers = new ArrayList<>(); + ; private Node currentNode; private final boolean isMain; - private boolean listeningToTabbedPane = false; - + private boolean listeningToTabbedPane = false; + /** - * Creates new DataContentPanel panel - * The main data content panel can only be created by the data content top component, - * thus this constructor is not public. - * - * Use the createInstance factory method to create an external viewer data content panel. - * + * Creates new DataContentPanel panel The main data content panel can only + * be created by the data content top component, thus this constructor is + * not public. + * + * Use the createInstance factory method to create an external viewer data + * content panel. + * */ DataContentPanel(boolean isMain) { this.isMain = isMain; initComponents(); - + // add all implementors of DataContentViewer and put them in the tabbed pane Collection dcvs = Lookup.getDefault().lookupAll(DataContentViewer.class); for (DataContentViewer factory : dcvs) { DataContentViewer dcv; if (isMain) { //use the instance from Lookup for the main viewer - dcv = factory; - } - else { - dcv = factory.createInstance(); + dcv = factory; + } else { + dcv = factory.createInstance(); } viewers.add(new UpdateWrapper(dcv)); jTabbedPane1.addTab(dcv.getTitle(), null, dcv.getComponent(), dcv.getToolTip()); } - + // disable the tabs int numTabs = jTabbedPane1.getTabCount(); for (int tab = 0; tab < numTabs; ++tab) { jTabbedPane1.setEnabledAt(tab, false); } } - - + /** * Factory method to create an external (not main window) data content panel * to be used in an external window - * + * * @return a new instance of a data content panel */ public static DataContentPanel createInstance() { return new DataContentPanel(false); } - + public JTabbedPane getTabPanels() { return jTabbedPane1; } @@ -131,8 +131,7 @@ import org.sleuthkit.datamodel.TskCoreException; // change the cursor to "waiting cursor" for this operation this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); try { - - + String defaultName = NbBundle.getMessage(DataContentTopComponent.class, "CTL_DataContentTopComponent"); // set the file path if (selectedNode == null) { @@ -160,21 +159,21 @@ import org.sleuthkit.datamodel.TskCoreException; this.setCursor(null); } } - + /** * 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 + * @param selectedNode the selected content Node */ public void setupTabs(Node selectedNode) { // Deferring becoming a listener to the tabbed pane until this point // eliminates handling a superfluous stateChanged event during construction. if (listeningToTabbedPane == false) { - jTabbedPane1.addChangeListener(this); + jTabbedPane1.addChangeListener(this); listeningToTabbedPane = true; } - + int currTabIndex = jTabbedPane1.getSelectedIndex(); int totalTabs = jTabbedPane1.getTabCount(); int maxPreferred = 0; @@ -188,7 +187,7 @@ import org.sleuthkit.datamodel.TskCoreException; jTabbedPane1.setEnabledAt(i, false); } else { jTabbedPane1.setEnabledAt(i, true); - + // remember the viewer with the highest preference value int currentPreferred = dcv.isPreferred(selectedNode); if (currentPreferred > maxPreferred) { @@ -197,19 +196,18 @@ import org.sleuthkit.datamodel.TskCoreException; } } } - + // let the user decide if we should stay with the current viewer int tabIndex = UserPreferences.keepPreferredContentViewer() ? currTabIndex : preferredViewerIndex; - + UpdateWrapper dcv = viewers.get(tabIndex); // this is really only needed if no tabs were enabled if (jTabbedPane1.isEnabledAt(tabIndex) == false) { dcv.resetComponent(); - } - else { + } else { dcv.setNode(selectedNode); } - + // set the tab to the one the user wants, then set that viewer's node. jTabbedPane1.setSelectedIndex(tabIndex); } @@ -265,10 +263,10 @@ import org.sleuthkit.datamodel.TskCoreException; boolean isSupported(Node node) { return this.wrapped.isSupported(node); } - + int isPreferred(Node node) { return this.wrapped.isPreferred(node); } } - + } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentTopComponent.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentTopComponent.java index 5a65cf4b62..b68f38204f 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentTopComponent.java @@ -32,15 +32,16 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent; /** - * Top component that organizes all of the data content viewers. Doing a lookup on this class will - * always return the default instance (which is created at startup). + * Top component that organizes all of the data content viewers. Doing a lookup + * on this class will always return the default instance (which is created at + * startup). */ // Registered as a service provider in layer.xml //@TopComponent.Description(preferredID = "DataContentTopComponent") //@TopComponent.Registration(mode = "output", openAtStartup = true) //@TopComponent.OpenActionRegistration(displayName = "#CTL_DataContentAction", preferredID = "DataContentTopComponent") public final class DataContentTopComponent extends TopComponent implements DataContent { - + private static Logger logger = Logger.getLogger(DataContentTopComponent.class.getName()); // reference to the "default" TC that always stays open @@ -55,26 +56,28 @@ public final class DataContentTopComponent extends TopComponent implements DataC private static final String PREFERRED_ID = "DataContentTopComponent"; //NON-NLS private static final String DEFAULT_NAME = NbBundle.getMessage(DataContentTopComponent.class, "CTL_DataContentTopComponent"); private static final String TOOLTIP_TEXT = NbBundle.getMessage(DataContentTopComponent.class, "HINT_DataContentTopComponent"); - + private DataContentTopComponent(boolean isDefault, String name) { initComponents(); setName(name); setToolTipText(TOOLTIP_TEXT); this.isDefault = isDefault; - + dataContentPanel = new DataContentPanel(isDefault); add(dataContentPanel); - + putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.valueOf(isDefault)); // prevent option to close compoment in GUI logger.log(Level.INFO, "Created DataContentTopComponent instance: " + this); //NON-NLS } /** - * This createInstance method is used to create an undocked instance - * for the "View in New Window" feature. - * @param filePath path of given file node + * This createInstance method is used to create an undocked instance for the + * "View in New Window" feature. + * + * @param filePath path of given file node * @param givenNode node to view content of + * * @return newly undocked instance */ public static DataContentTopComponent createUndocked(String filePath, Node givenNode) { @@ -88,10 +91,10 @@ public final class DataContentTopComponent extends TopComponent implements DataC return dctc; } - /** 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. + /** + * 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. */ // //GEN-BEGIN:initComponents private void initComponents() { @@ -102,9 +105,10 @@ public final class DataContentTopComponent extends TopComponent implements DataC // End of variables declaration//GEN-END:variables /** - * Gets default instance. Do not use directly: reserved for *.settings files only, - * i.e. deserialization routines; otherwise you could get a non-deserialized defaultInstance. - * To obtain the singleton instance, use {@link #findInstance}. + * Gets default instance. Do not use directly: reserved for *.settings files + * only, i.e. deserialization routines; otherwise you could get a + * non-deserialized defaultInstance. To obtain the singleton instance, use + * {@link #findInstance}. */ public static synchronized DataContentTopComponent getDefault() { if (defaultInstance == null) { @@ -114,7 +118,8 @@ public final class DataContentTopComponent extends TopComponent implements DataC } /** - * Obtain the default DataContentTopComponent defaultInstance. Never call {@link #getDefault} directly! + * Obtain the default DataContentTopComponent defaultInstance. Never call + * {@link #getDefault} directly! */ public static synchronized DataContentTopComponent findInstance() { TopComponent win = WindowManager.getDefault().findTopComponent(PREFERRED_ID); @@ -144,7 +149,7 @@ public final class DataContentTopComponent extends TopComponent implements DataC public void componentClosed() { dataContentPanel.setNode(null); - + if (!this.isDefault) { newWindowList.remove(this); } @@ -175,6 +180,7 @@ public final class DataContentTopComponent extends TopComponent implements DataC /** * Get the tab pane + * * @return tab pane with individual DataContentViewers */ public JTabbedPane getTabPanels() { @@ -183,6 +189,7 @@ public final class DataContentTopComponent extends TopComponent implements DataC /** * Returns a list of the non-default (main) TopComponents + * * @return */ public static List getNewWindowList() { diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java index 4415a3522e..635a8b0e37 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.corecomponents; import java.awt.*; @@ -47,12 +46,13 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskException; /** - * Instances of this class display the BlackboardArtifacts associated with the Content represented by a Node. - * Each BlackboardArtifact is rendered as an HTML representation of its BlackboardAttributes. + * Instances of this class display the BlackboardArtifacts associated with the + * Content represented by a Node. Each BlackboardArtifact is rendered as an HTML + * representation of its BlackboardAttributes. */ -@ServiceProvider(service = DataContentViewer.class, position=3) -public class DataContentViewerArtifact extends javax.swing.JPanel implements DataContentViewer{ - +@ServiceProvider(service = DataContentViewer.class, position = 3) +public class DataContentViewerArtifact extends javax.swing.JPanel implements DataContentViewer { + private final static Logger logger = Logger.getLogger(DataContentViewerArtifact.class.getName()); private final static String WAIT_TEXT = NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.waitText"); private final static String ERROR_TEXT = NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.errorText"); @@ -61,17 +61,17 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat private final Object lock = new Object(); private List artifactContentStrings; // Accessed by multiple threads, use getArtifactContentStrings() and setArtifactContentStrings() SwingWorker currentTask; // Accessed by multiple threads, use startNewTask() - + public DataContentViewerArtifact() { initComponents(); customizeComponents(); resetComponents(); } - /** 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. + /** + * 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") // //GEN-BEGIN:initComponents @@ -207,13 +207,13 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed currentPage = currentPage + 1; - currentPageLabel.setText(Integer.toString(currentPage)); + currentPageLabel.setText(Integer.toString(currentPage)); startNewTask(new SelectedArtifactChangedTask(currentPage)); }//GEN-LAST:event_nextPageButtonActionPerformed private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevPageButtonActionPerformed currentPage = currentPage - 1; - currentPageLabel.setText(Integer.toString(currentPage)); + currentPageLabel.setText(Integer.toString(currentPage)); startNewTask(new SelectedArtifactChangedTask(currentPage)); }//GEN-LAST:event_prevPageButtonActionPerformed @@ -233,21 +233,22 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat private javax.swing.JLabel totalPageLabel; // End of variables declaration//GEN-END:variables - private void customizeComponents(){ + private void customizeComponents() { outputViewPane.setComponentPopupMenu(rightClickMenu); - ActionListener actList = new ActionListener(){ + ActionListener actList = new ActionListener() { @Override - public void actionPerformed(ActionEvent e){ + public void actionPerformed(ActionEvent e) { JMenuItem jmi = (JMenuItem) e.getSource(); - if(jmi.equals(copyMenuItem)) + if (jmi.equals(copyMenuItem)) { outputViewPane.copy(); - else if(jmi.equals(selectAllMenuItem)) + } else if (jmi.equals(selectAllMenuItem)) { outputViewPane.selectAll(); + } } }; copyMenuItem.addActionListener(actList); selectAllMenuItem.addActionListener(actList); - + Utilities.configureTextPaneAsHtml(outputViewPane); } @@ -263,26 +264,26 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat nextPageButton.setEnabled(false); currentNode = null; } - + @Override public void setNode(Node selectedNode) { if (currentNode == selectedNode) { return; } currentNode = selectedNode; - + // Make sure there is a node. Null might be passed to reset the viewer. if (selectedNode == null) { return; } - + // Make sure the node is of the correct type. Lookup lookup = selectedNode.getLookup(); Content content = lookup.lookup(Content.class); if (content == null) { - return; + return; } - + startNewTask(new SelectedNodeChangedTask(selectedNode)); } @@ -310,19 +311,18 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat public void resetComponent() { resetComponents(); } - + @Override public boolean isSupported(Node node) { if (node == null) { return false; } - Content content = node.getLookup().lookup(Content.class); - if(content != null) { + Content content = node.getLookup().lookup(Content.class); + if (content != null) { try { return content.getAllArtifactsCount() > 0; - } - catch (TskException ex) { + } catch (TskException ex) { logger.log(Level.WARNING, "Couldn't get count of BlackboardArtifacts for content", ex); //NON-NLS } } @@ -335,69 +335,75 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat // low priority if node doesn't have an artifact (meaning it was found from normal directory // browsing, or if the artifact is something that means the user really wants to see the original // file and not more details about the artifact - if ((artifact == null) || - (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) || - (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID())) { + if ((artifact == null) + || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) + || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID())) { return 3; - } - else { + } else { return 5; } } /** - * Instances of this class are simple containers for view update information generated by a background thread. + * Instances of this class are simple containers for view update information + * generated by a background thread. */ private class ViewUpdate { + int numberOfPages; int currentPage; String text; - + ViewUpdate(int numberOfPages, int currentPage, String text) { this.currentPage = currentPage; this.numberOfPages = numberOfPages; this.text = text; } } - + /** - * Called from queued SwingWorker done() methods on the EDT thread, so doesn't need to be synchronized. - * @param viewUpdate A simple container for display update information from a background thread. + * Called from queued SwingWorker done() methods on the EDT thread, so + * doesn't need to be synchronized. + * + * @param viewUpdate A simple container for display update information from + * a background thread. */ - private void updateView(ViewUpdate viewUpdate) { + private void updateView(ViewUpdate viewUpdate) { this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - + nextPageButton.setEnabled(viewUpdate.currentPage < viewUpdate.numberOfPages); prevPageButton.setEnabled(viewUpdate.currentPage > 1); currentPage = viewUpdate.currentPage; totalPageLabel.setText(Integer.toString(viewUpdate.numberOfPages)); - currentPageLabel.setText(Integer.toString(currentPage)); - + currentPageLabel.setText(Integer.toString(currentPage)); + // @@@ This can take a long time. Perhaps a faster HTML renderer can be found. // Note that the rendering appears to be done on a background thread, since the // wait cursor reset below happens before the new text hits the JTextPane. On the // other hand, the UI is unresponsive... - outputViewPane.setText(viewUpdate.text); + outputViewPane.setText(viewUpdate.text); outputViewPane.moveCaretPosition(0); - + this.setCursor(null); - } - + } + /** - * Start a new task on its own background thread, canceling the previous task. - * @param task A new SwingWorker object to execute as a background thread. + * Start a new task on its own background thread, canceling the previous + * task. + * + * @param task A new SwingWorker object to execute as a background thread. */ - private synchronized void startNewTask(SwingWorker task) { - outputViewPane.setText(WAIT_TEXT); + private synchronized void startNewTask(SwingWorker task) { + outputViewPane.setText(WAIT_TEXT); outputViewPane.moveCaretPosition(0); - + // The output of the previous task is no longer relevant. if (currentTask != null) { // This call sets a cancellation flag. It does not terminate the background thread running the task. // The task must check the cancellation flag and react appropriately. currentTask.cancel(false); } - + // Start the new task. currentTask = task; currentTask.execute(); @@ -405,6 +411,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat /** * Populate the cache of artifact represented as strings. + * * @param artifactStrings A list of string representations of artifacts. */ private void setArtifactContentStrings(List artifactStrings) { @@ -412,9 +419,10 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat this.artifactContentStrings = artifactStrings; } } - + /** * Retrieve the cache of artifact represented as strings. + * * @return A list of string representations of artifacts. */ private List getArtifactContentStrings() { @@ -422,45 +430,46 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat return artifactContentStrings; } } - + /** - * Instances of this class use a background thread to generate a ViewUpdate when a node is selected, - * changing the set of blackboard artifacts ("results") to be displayed. + * Instances of this class use a background thread to generate a ViewUpdate + * when a node is selected, changing the set of blackboard artifacts + * ("results") to be displayed. */ private class SelectedNodeChangedTask extends SwingWorker { + private final Node selectedNode; - + SelectedNodeChangedTask(Node selectedNode) { this.selectedNode = selectedNode; } - + @Override - protected ViewUpdate doInBackground() { + protected ViewUpdate doInBackground() { // Get the lookup for the node for access to its underlying content and // blackboard artifact, if any. Lookup lookup = selectedNode.getLookup(); - + // Get the content. Content content = lookup.lookup(Content.class); if (content == null) { - return new ViewUpdate(getArtifactContentStrings().size(), currentPage, ERROR_TEXT); + return new ViewUpdate(getArtifactContentStrings().size(), currentPage, ERROR_TEXT); } - + // Get all of the blackboard artifacts associated with the content. These are what this // viewer displays. ArrayList artifacts; try { artifacts = content.getAllArtifacts(); - } - catch (TskException ex) { + } catch (TskException ex) { logger.log(Level.WARNING, "Couldn't get artifacts", ex); //NON-NLS - return new ViewUpdate(getArtifactContentStrings().size(), currentPage, ERROR_TEXT); + return new ViewUpdate(getArtifactContentStrings().size(), currentPage, ERROR_TEXT); } - + if (isCancelled()) { return null; } - + // Build the new artifact strings cache. ArrayList artifactStrings = new ArrayList<>(); for (BlackboardArtifact artifact : artifacts) { @@ -479,37 +488,36 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat // if the artifact has an ASSOCIATED ARTIFACT, then we display the associated artifact instead try { for (BlackboardAttribute attr : artifact.getAttributes()) { - if (attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) { - long assocArtifactId = attr.getValueLong(); - int assocArtifactIndex = -1; - for (BlackboardArtifact art: artifacts) { - if (assocArtifactId == art.getArtifactID()) { - assocArtifactIndex = artifacts.indexOf(art); - break; - } - } - if (assocArtifactIndex >= 0) { + if (attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) { + long assocArtifactId = attr.getValueLong(); + int assocArtifactIndex = -1; + for (BlackboardArtifact art : artifacts) { + if (assocArtifactId == art.getArtifactID()) { + assocArtifactIndex = artifacts.indexOf(art); + break; + } + } + if (assocArtifactIndex >= 0) { index = assocArtifactIndex; } - break; - } + break; + } } - } - catch (TskCoreException ex) { + } catch (TskCoreException ex) { logger.log(Level.WARNING, "Couldn't get associated artifact to display in Content Viewer.", ex); //NON-NLS } - } - - } + } + + } if (isCancelled()) { return null; } - + // Add one to the index of the artifact string for the corresponding page index. Note that the getString() method // of ArtifactStringContent does a lazy fetch of the attributes of the correspoding artifact and represents them as // HTML. - ViewUpdate viewUpdate = new ViewUpdate(artifactStrings.size(), index + 1, artifactStrings.get(index).getString()); + ViewUpdate viewUpdate = new ViewUpdate(artifactStrings.size(), index + 1, artifactStrings.get(index).getString()); // It may take a considerable amount of time to fetch the attributes of the selected artifact and render them // as HTML, so check for cancellation. @@ -519,10 +527,10 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat // Update the artifact strings cache. setArtifactContentStrings(artifactStrings); - + return viewUpdate; } - + @Override protected void done() { if (!isCancelled()) { @@ -531,25 +539,26 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat if (viewUpdate != null) { updateView(viewUpdate); } - } - catch (InterruptedException | ExecutionException ex) { + } catch (InterruptedException | ExecutionException ex) { logger.log(Level.WARNING, "Artifact display task unexpectedly interrupted or failed", ex); //NON-NLS - } + } } - } + } } - + /** - * Instances of this class use a background thread to generate a ViewUpdate when the user pages the view - * to look at another blackboard artifact ("result"). + * Instances of this class use a background thread to generate a ViewUpdate + * when the user pages the view to look at another blackboard artifact + * ("result"). */ private class SelectedArtifactChangedTask extends SwingWorker { + private final int pageIndex; - + SelectedArtifactChangedTask(final int pageIndex) { this.pageIndex = pageIndex; } - + @Override protected ViewUpdate doInBackground() { // Get the artifact string to display from the cache. Note that one must be subtracted from the @@ -560,16 +569,16 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat // The getString() method of ArtifactStringContent does a lazy fetch of the attributes of the // correspoding artifact and represents them as HTML. String artifactString = artifactStringContent.getString(); - + // It may take a considerable amount of time to fetch the attributes of the selected artifact and render them // as HTML, so check for cancellation. if (isCancelled()) { return null; } - + return new ViewUpdate(artifactStrings.size(), pageIndex, artifactString); } - + @Override protected void done() { if (!isCancelled()) { @@ -578,11 +587,10 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat if (viewUpdate != null) { updateView(viewUpdate); } - } - catch (InterruptedException | ExecutionException ex) { + } catch (InterruptedException | ExecutionException ex) { logger.log(Level.WARNING, "Artifact display task unexpectedly interrupted or failed", ex); //NON-NLS - } + } } } - } + } } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java index 11cee38ab4..512cf6393c 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java @@ -42,6 +42,7 @@ import org.sleuthkit.datamodel.TskException; */ @ServiceProvider(service = DataContentViewer.class, position = 1) public class DataContentViewerHex extends javax.swing.JPanel implements DataContentViewer { + private static final long pageLength = 16384; private final byte[] data = new byte[(int) pageLength]; private static int currentPage = 1; @@ -275,7 +276,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont private void goToPageTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_goToPageTextFieldActionPerformed String pageNumberStr = goToPageTextField.getText(); int pageNumber = 0; - + try { pageNumber = Integer.parseInt(pageNumberStr); } catch (NumberFormatException ex) { @@ -283,22 +284,26 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont } if (pageNumber > totalPages || pageNumber < 1) { JOptionPane.showMessageDialog(this, - NbBundle.getMessage(this.getClass(), - "DataContentViewerHex.goToPageTextField.msgDlg", - totalPages), - NbBundle.getMessage(this.getClass(), - "DataContentViewerHex.goToPageTextField.err"), - JOptionPane.WARNING_MESSAGE); + NbBundle.getMessage(this.getClass(), + "DataContentViewerHex.goToPageTextField.msgDlg", + totalPages), + NbBundle.getMessage(this.getClass(), + "DataContentViewerHex.goToPageTextField.err"), + JOptionPane.WARNING_MESSAGE); return; } setDataViewByPageNumber(pageNumber); }//GEN-LAST:event_goToPageTextFieldActionPerformed - /*** + /** + * * * Calculates the offset relative to the current caret position. + * * @param userInput the user provided signed offset value. + * * @return returns the resultant offset value relative to the current caret - * position. -1L is returned if the resultant offset cannot be calculated. + * position. -1L is returned if the resultant offset cannot be + * calculated. */ private long getOffsetRelativeToCaretPosition(Long userInput) { String userSelectedLine; @@ -359,7 +364,6 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont private javax.swing.JLabel totalPageLabel; // End of variables declaration//GEN-END:variables - /** * Sets the DataView (The tabbed panel) by page number * @@ -377,6 +381,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont setDataView(offset); goToOffsetTextField.setText(Long.toString(offset)); } + /** * Sets the DataView (The tabbed panel) by offset * @@ -448,20 +453,20 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont resetComponent(); return; } - + Content content = (selectedNode).getLookup().lookup(Content.class); if (content == null) { resetComponent(); return; } - + dataSource = content; totalPages = 0; if (dataSource.getSize() > 0) { totalPages = Math.round((dataSource.getSize() - 1) / pageLength) + 1; } totalPageLabel.setText(Integer.toString(totalPages)); - + this.setDataViewByPageNumber(1); } @@ -519,7 +524,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont if (content != null && content.getSize() > 0) { return true; } - + return false; } @@ -533,7 +538,9 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont return this; } - /* Show the right click menu only if evt is the correct mouse event */ + /* + * Show the right click menu only if evt is the correct mouse event + */ private void maybeShowPopup(java.awt.event.MouseEvent evt) { if (evt.isPopupTrigger()) { rightClickMenu.setLocation(evt.getLocationOnScreen()); diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java index 920cfb95cf..c3749660bf 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2014 Basis Technology Corp. + * Copyright 2011-2015 Basis Technology Corp. * Contact: carrier sleuthkit org *s * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,9 +21,7 @@ package org.sleuthkit.autopsy.corecomponents; import java.awt.CardLayout; import java.awt.Component; import java.awt.Dimension; -import java.util.Arrays; -import static java.util.Objects.nonNull; -import java.util.Set; +import java.util.List; import java.util.SortedSet; import java.util.TreeSet; import java.util.logging.Level; @@ -32,12 +30,8 @@ import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProviders; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; -import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.AbstractFile.MimeMatchEnum; -import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; /** @@ -48,18 +42,15 @@ import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; }) public class DataContentViewerMedia extends javax.swing.JPanel implements DataContentViewer { - private static final Set AUDIO_EXTENSIONS = new TreeSet<>(Arrays.asList(".mp3", ".wav", ".wma")); //NON-NLS private static final Logger logger = Logger.getLogger(DataContentViewerMedia.class.getName()); private AbstractFile lastFile; //UI private final MediaViewVideoPanel videoPanel; + private final boolean videoPanelInited; private final SortedSet videoExtensions; // get them from the panel - private final SortedSet imageExtensions; - private final SortedSet videoMimes; - private final SortedSet imageMimes; private final MediaViewImagePanel imagePanel; - private boolean videoPanelInited; - private boolean imagePanelInited; + private final boolean imagePanelInited; + private static final String IMAGE_VIEWER_LAYER = "IMAGE"; //NON-NLS private static final String VIDEO_VIEWER_LAYER = "VIDEO"; //NON-NLS @@ -73,16 +64,13 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo // get the right panel for our platform videoPanel = MediaViewVideoPanel.createVideoPanel(); videoPanelInited = videoPanel.isInited(); - videoExtensions = new TreeSet<>(Arrays.asList(videoPanel.getExtensions())); - videoMimes = new TreeSet<>(videoPanel.getMimeTypes()); + videoExtensions = new TreeSet<>(videoPanel.getExtensionsList()); imagePanel = new MediaViewImagePanel(); imagePanelInited = imagePanel.isInited(); - imageMimes = new TreeSet<>(imagePanel.getMimeTypes()); - imageExtensions = new TreeSet<>(imagePanel.getExtensions()); customizeComponents(); - logger.log(Level.INFO, "Created MediaView instance: " + this); //NON-NLS + logger.log(Level.INFO, "Created MediaView instance: {0}", this); //NON-NLS } private void customizeComponents() { @@ -129,12 +117,12 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo final Dimension dims = DataContentViewerMedia.this.getSize(); //logger.info("setting node on media viewer"); //NON-NLS - if (imagePanelInited && isImageSupported(file)) { - imagePanel.showImageFx(file, dims); - this.showVideoPanel(false); - } else if (videoPanelInited && isVideoSupported(file)) { + if (videoPanelInited && videoPanel.isSupported(file)) { videoPanel.setupVideo(file, dims); this.showVideoPanel(true); + } else if (imagePanelInited && imagePanel.isSupported(file)) { + imagePanel.showImageFx(file, dims); + this.showVideoPanel(false); } } catch (Exception e) { logger.log(Level.SEVERE, "Exception while setting node", e); //NON-NLS @@ -190,23 +178,10 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo * @return True if a video file that can be displayed */ private boolean isVideoSupported(AbstractFile file) { - String name = file.getName().toLowerCase(); - - //TODO: is this what we want, to require both extension and mimetype support? - if (AUDIO_EXTENSIONS.contains("." + name) || videoExtensions.contains("." + name)) { - try { - String mimeType = new FileTypeDetector().detect(file); - if (nonNull(mimeType) && videoMimes.contains(mimeType)) { - return true; - } - } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { - logger.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex); - if (!videoMimes.isEmpty() && file.isMimeType(videoMimes) == MimeMatchEnum.TRUE) { - return true; - } - } + if (null == file || file.getSize() == 0) { + return false; } - return false; + return videoPanel.isSupported(file); } /** @@ -217,36 +192,12 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo * @return True if an image file that can be displayed */ private boolean isImageSupported(AbstractFile file) { - String name = file.getName().toLowerCase(); - // blackboard - try { - String mimeType = new FileTypeDetector().detect(file); - if (nonNull(mimeType) && imageMimes.contains(mimeType)) { - return true; - } - } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { - logger.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex); - if (!imageMimes.isEmpty()) { - MimeMatchEnum mimeMatch = file.isMimeType(imageMimes); - if (mimeMatch == MimeMatchEnum.TRUE) { - return true; - } else if (mimeMatch == MimeMatchEnum.FALSE) { - return false; - } - } + if (null == file || file.getSize() == 0) { + return false; } - // extension - if (imageExtensions.contains("." + name)) { - return true; - } - - // our own signature checks for important types - if (ImageUtils.isJpegFileHeader(file)) { - return true; - } - return ImageUtils.isPngFileHeader(file); + return imagePanel.isSupported(file); } @Override @@ -264,19 +215,11 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo return false; } - if (imagePanelInited) { - if (isImageSupported(file)) { - return true; - } + if (imagePanelInited && isImageSupported(file)) { + return true; } - if (videoPanelInited && videoPanel.isInited()) { - if (isVideoSupported(file)) { - return true; - } - } - - return false; + return videoPanelInited && isVideoSupported(file); } @Override @@ -286,13 +229,29 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo if (file == null) { return 0; } - String extension = file.getNameExtension(); boolean deleted = file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC); - if (videoExtensions.contains("." + extension) && deleted) { + if (videoPanel.isSupported(file) && deleted) { return 0; } else { return 7; } } + + interface MediaViewPanel { + + /** + * @return supported mime types + */ + List getMimeTypes(); + + /** + * returns supported extensions (each starting with .) + * + * @return + */ + List getExtensionsList(); + + boolean isSupported(AbstractFile file); + } } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerString.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerString.java index 48ed46c8cc..3714894f40 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerString.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerString.java @@ -288,12 +288,12 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC } if (pageNumber > maxPage || pageNumber < 1) { JOptionPane.showMessageDialog(this, - NbBundle.getMessage(this.getClass(), - "DataContentViewerString.goToPageTextField.msgDlg", - maxPage), - NbBundle.getMessage(this.getClass(), - "DataContentViewerString.goToPageTextField.err"), - JOptionPane.WARNING_MESSAGE); + NbBundle.getMessage(this.getClass(), + "DataContentViewerString.goToPageTextField.msgDlg", + maxPage), + NbBundle.getMessage(this.getClass(), + "DataContentViewerString.goToPageTextField.err"), + JOptionPane.WARNING_MESSAGE); return; } currentOffset = (pageNumber - 1) * pageLength; @@ -328,18 +328,17 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC private javax.swing.JLabel totalPageLabel; // End of variables declaration//GEN-END:variables - /** * Sets the DataView (The tabbed panel) * * @param dataSource the content that want to be shown - * @param offset the starting offset + * @param offset the starting offset */ private void setDataView(Content dataSource, long offset) { if (dataSource == null) { return; } - + // change the cursor to "waiting cursor" for this operation this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); @@ -353,8 +352,8 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC bytesRead = dataSource.read(data, offset, pageLength); // read the data } catch (TskException ex) { text = NbBundle.getMessage(this.getClass(), - "DataContentViewerString.setDataView.errorText", currentOffset, - currentOffset + pageLength); + "DataContentViewerString.setDataView.errorText", currentOffset, + currentOffset + pageLength); logger.log(Level.WARNING, "Error while trying to show the String content.", ex); //NON-NLS } } @@ -367,12 +366,12 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC text = res.getText(); if (text.trim().isEmpty()) { text = NbBundle.getMessage(this.getClass(), - "DataContentViewerString.setDataView.errorNoText", currentOffset, - currentOffset + pageLength); + "DataContentViewerString.setDataView.errorNoText", currentOffset, + currentOffset + pageLength); } } else { text = NbBundle.getMessage(this.getClass(), "DataContentViewerString.setDataView.errorText", currentOffset, - currentOffset + pageLength); + currentOffset + pageLength); } // disable or enable the next button @@ -389,7 +388,6 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC prevPageButton.setEnabled(true); } - int totalPage = Math.round((dataSource.getSize() - 1) / pageLength) + 1; totalPageLabel.setText(Integer.toString(totalPage)); currentPageLabel.setText(Integer.toString(currentPage)); @@ -399,7 +397,7 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC this.setCursor(null); } - + private void setDataView(StringContent dataSource) { this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); try { @@ -518,7 +516,9 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC } - /* Show the right click menu only if evt is the correct mouse event */ + /* + * Show the right click menu only if evt is the correct mouse event + */ private void maybeShowPopup(java.awt.event.MouseEvent evt) { if (evt.isPopupTrigger()) { rightClickMenu.setLocation(evt.getLocationOnScreen()); diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java index 88d8706e71..3c5091bd50 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java @@ -48,39 +48,40 @@ import org.sleuthkit.autopsy.coreutils.Logger; * * The component is a generic JPanel and it can be reused in other swing * components or in a TopComponent. - * + * * Use the static factory methods to instantiate and customize the component. * One option is to link a custom data content viewer to link to this viewer. - * + * */ public class DataResultPanel extends javax.swing.JPanel implements DataResult, ChangeListener { private ExplorerManager explorerManager; private Node rootNode; private PropertyChangeSupport pcs; - + // Different DataResultsViewers private final List viewers = new ArrayList<>(); //custom content viewer to send selections to, or null if the main one 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 final RootNodeListener rootNodeListener = new RootNodeListener(); + + private static final Logger logger = Logger.getLogger(DataResultPanel.class.getName()); private boolean listeningToTabbedPane = false; private static final String DUMMY_NODE_DISPLAY_NAME = NbBundle.getMessage(DataResultPanel.class, - "DataResultPanel.dummyNodeDisplayName"); + "DataResultPanel.dummyNodeDisplayName"); + /** - * Creates new DataResultPanel - * Default constructor, needed mostly for the palette/UI builder - * Use overrides or factory methods for more customization. + * Creates new DataResultPanel Default constructor, needed mostly for the + * palette/UI builder Use overrides or factory methods for more + * customization. */ private DataResultPanel() { this.isMain = true; pcs = new PropertyChangeSupport(this); initComponents(); - + setName(title); this.title = ""; @@ -88,14 +89,14 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C /** * Creates data result panel - * - * @param isMain whether it is the main panel associated with the main window, - * clients will almost always use false - * @param title title string to be displayed + * + * @param isMain whether it is the main panel associated with the main + * window, clients will almost always use false + * @param title title string to be displayed */ DataResultPanel(boolean isMain, String title) { this(); - + setName(title); this.isMain = isMain; @@ -106,26 +107,31 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C * Create a new, custom data result panel, in addition to the application * main one and links with a custom data content panel. * - * @param name unique name of the data result window, also used as title + * @param name unique name of the data result window, also + * used as title * @param customContentViewer custom content viewer to send selection events - * to + * to */ DataResultPanel(String title, DataContent customContentViewer) { this(false, title); setName(title); //custom content viewer tc to setup for every result viewer - this.customContentViewer = customContentViewer; + this.customContentViewer = customContentViewer; } - + /** - * Factory method to create, customize and open a new custom data result panel. + * Factory method to create, customize and open a new custom data result + * panel. * - * @param title Title of the result panel - * @param pathText Descriptive text about the source of the nodes displayed - * @param givenNode The new root node + * @param title Title of the result panel + * @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 DataResultPanel instance representing a custom data result viewer + * + * @return a new DataResultPanel instance representing a custom data result + * viewer */ public static DataResultPanel createInstance(String title, String pathText, Node givenNode, int totalMatches) { DataResultPanel newDataResult = new DataResultPanel(false, title); @@ -136,14 +142,18 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C } /** - * Factory method to create, customize and open a new custom data result panel. + * Factory method to create, customize and open a new custom data result + * panel. * - * @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 title Title of the component window + * @param pathText Descriptive text about the source of the nodes + * displayed + * @param givenNode The new root node * @param totalMatches Cardinality of root node's children - * @param dataContent a handle to data content to send selection events to - * @return a new DataResultPanel instance representing a custom data result viewer + * @param dataContent a handle to data content to send selection events to + * + * @return a new DataResultPanel instance representing a custom data result + * viewer */ public static DataResultPanel createInstance(String title, String pathText, Node givenNode, int totalMatches, DataContent dataContent) { DataResultPanel newDataResult = new DataResultPanel(title, dataContent); @@ -153,17 +163,20 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C return newDataResult; } - /** - * Factory method to create, customize and open a new custom data result panel. - * Does NOT call open(). Client must manually initialize by calling open(). + * Factory method to create, customize and open a new custom data result + * panel. Does NOT call open(). Client must manually initialize by calling + * open(). * - * @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 title Title of the component window + * @param pathText Descriptive text about the source of the nodes + * displayed + * @param givenNode The new root node * @param totalMatches Cardinality of root node's children - * @param dataContent a handle to data content to send selection events to - * @return a new DataResultPanel instance representing a custom data result viewer + * @param dataContent a handle to data content to send selection events to + * + * @return a new DataResultPanel instance representing a custom data result + * viewer */ public static DataResultPanel createInstanceUninitialized(String title, String pathText, Node givenNode, int totalMatches, DataContent dataContent) { DataResultPanel newDataResult = new DataResultPanel(title, dataContent); @@ -171,14 +184,14 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C createInstanceCommon(pathText, givenNode, totalMatches, newDataResult); return newDataResult; } - - + /** * Common code for factory helper methods + * * @param pathText * @param givenNode * @param totalMatches - * @param newDataResult + * @param newDataResult */ private static void createInstanceCommon(String pathText, Node givenNode, int totalMatches, DataResultPanel newDataResult) { newDataResult.numberMatchLabel.setText(Integer.toString(totalMatches)); @@ -189,18 +202,19 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C } /** - * Sets content viewer to the custom one. - * Needs to be done before the first call to open() - * @param customContentViewer + * Sets content viewer to the custom one. Needs to be done before the first + * call to open() + * + * @param customContentViewer */ public void setContentViewer(DataContent customContentViewer) { this.customContentViewer = customContentViewer; } - + /** - * Initializes the panel internals and activates it. - * Call it within your top component when it is opened. - * Do not use if used one of the factory methods to create and open the component. + * Initializes the panel internals and activates it. Call it within your top + * component when it is opened. Do not use if used one of the factory + * methods to create and open the component. */ public void open() { if (null == explorerManager) { @@ -220,7 +234,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C // and is the parent of a DataContentPanel that hosts a set of DataContentViewers. explorerManager.addPropertyChangeListener(new ExplorerManagerNodeSelectionListener()); } - + // Add all the DataContentViewer to the tabbed pannel. // (Only when the it's opened at the first time: tabCount = 0) int totalTabs = this.dataResultTabbedPanel.getTabCount(); @@ -229,9 +243,9 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C // as DataResultViewer service providers when DataResultViewers are updated // to better handle the ExplorerManager sharing implemented to support actions that operate on // multiple selected nodes. - addDataResultViewer(new DataResultViewerTable(this.explorerManager)); + addDataResultViewer(new DataResultViewerTable(this.explorerManager)); addDataResultViewer(new DataResultViewerThumbnail(this.explorerManager)); - + // Find all DataResultViewer service providers and add them to the tabbed pane. for (DataResultViewer factory : Lookup.getDefault().lookupAll(DataResultViewer.class)) { // @@@ Revist this isMain condition, it may be obsolete. If not, @@ -240,9 +254,8 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C DataResultViewer drv; if (isMain) { //for main window, use the instance in the lookup - drv = factory; - } - else { + drv = factory; + } else { //create a new instance of the viewer for non-main window drv = factory.createInstance(); } @@ -259,8 +272,9 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C this.setVisible(true); } - + private class ExplorerManagerNodeSelectionListener implements PropertyChangeListener { + @Override public void propertyChange(PropertyChangeEvent evt) { if (!Case.isCaseOpen()) { @@ -271,7 +285,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) { setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - + // If a custom DataContent object has not been specified, get the default instance. DataContent contentViewer = customContentViewer; if (contentViewer == null) { @@ -279,19 +293,18 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C } try { - if (contentViewer != null) { + if (contentViewer != null) { Node[] selectedNodes = explorerManager.getSelectedNodes(); for (UpdateWrapper drv : viewers) { drv.setSelectedNodes(selectedNodes); - } + } // Passing null signals that either multiple nodes are selected, or no nodes are selected. // This is important to the DataContent object, since the content mode (area) of the app is designed // to show only the content underlying a single Node. if (selectedNodes.length == 1) { contentViewer.setNode(selectedNodes[0]); - } - else { + } else { contentViewer.setNode(null); } } @@ -301,20 +314,20 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C } } } - + private void addDataResultViewer(DataResultViewer dataResultViewer) { UpdateWrapper viewerWrapper = new UpdateWrapper(dataResultViewer); if (null != this.customContentViewer) { viewerWrapper.setContentViewer(this.customContentViewer); } this.viewers.add(viewerWrapper); - this.dataResultTabbedPanel.addTab(dataResultViewer.getTitle(), dataResultViewer.getComponent()); + this.dataResultTabbedPanel.addTab(dataResultViewer.getTitle(), dataResultViewer.getComponent()); } - + /** - * Tears down the component. - * Use within your outer container (such as a top component) when it goes away to tear - * down this component and detach its listeners. + * Tears down the component. Use within your outer container (such as a top + * component) when it goes away to tear down this component and detach its + * listeners. */ void close() { // try to remove any references to this class @@ -349,9 +362,8 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C public synchronized void addPropertyChangeListener(PropertyChangeListener listener) { if (pcs == null) { logger.log(Level.WARNING, "Could not add listener to DataResultPanel, " //NON-NLS - + "listener support not fully initialized yet, listener: " + listener.toString() ); //NON-NLS - } - else { + + "listener support not fully initialized yet, listener: " + listener.toString()); //NON-NLS + } else { this.pcs.addPropertyChangeListener(listener); } } @@ -369,31 +381,31 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C @Override public void setNode(Node selectedNode) { if (this.rootNode != null) { - this.rootNode.removeNodeListener(dummyNodeListener); + this.rootNode.removeNodeListener(rootNodeListener); } // 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); + dataResultTabbedPanel.addChangeListener(this); listeningToTabbedPane = true; } - + this.rootNode = selectedNode; if (this.rootNode != null) { - dummyNodeListener.reset(); - this.rootNode.addNodeListener(dummyNodeListener); + rootNodeListener.reset(); + this.rootNode.addNodeListener(rootNodeListener); } - + resetTabs(selectedNode); setupTabs(selectedNode); - + if (selectedNode != null) { int childrenCount = selectedNode.getChildren().getNodesCount(); this.numberMatchLabel.setText(Integer.toString(childrenCount)); } this.numberMatchLabel.setVisible(true); } - + private void setupTabs(Node selectedNode) { //update/disable tabs based on if supported for this node int drvC = 0; @@ -433,7 +445,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C @Override public void setTitle(String title) { setName(title); - + } @Override @@ -452,10 +464,10 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C for (UpdateWrapper w : viewers) { ret.add(w.getViewer()); } - + return ret; } - + public boolean canClose() { return (!this.isMain) || !Case.existsCurrentCase() || Case.getCurrentCase().hasData() == false; // only allow this window to be closed when there's no case opened or no image in this case } @@ -472,22 +484,22 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C // to better handle the ExplorerManager sharing implemented to support actions that operate on // multiple selected nodes. //if (drv.isOutdated()) { - // change the cursor to "waiting cursor" for this operation - this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - try { - drv.setNode(rootNode); - } finally { - this.setCursor(null); - } + // change the cursor to "waiting cursor" for this operation + this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + try { + drv.setNode(rootNode); + } finally { + this.setCursor(null); + } //} } } /** * why does this take a Node as parameter and then ignore it? - * - * - * + * + * + * * Resets the tabs based on the selected Node. If the selected node is null * or not supported, disable that tab as well. * @@ -573,7 +585,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C this.wrapped = wrapped; this.outdated = true; } - + DataResultViewer getViewer() { return wrapped; } @@ -612,6 +624,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C /** * Set number of matches to be displayed in the top right + * * @param numMatches */ public void setNumMatches(Integer numMatches) { @@ -619,35 +632,41 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C this.numberMatchLabel.setText(Integer.toString(numMatches)); } } - - private class DummyNodeListener implements NodeListener { - private volatile boolean load = true; - + private class RootNodeListener implements NodeListener { + + private volatile boolean waitingForData = true; + public void reset() { - load = true; + waitingForData = true; } - + @Override public void childrenAdded(final NodeMemberEvent nme) { Node[] delta = nme.getDelta(); - if (load && containsReal(delta)) { - load = false; + updateMatches(); + + /* + * There is a known issue in this code whereby we will only call + * setupTabs() once even though childrenAdded could be called + * multiple times. That means that each panel may not have access to + * all of the children when they decide if they support the content + */ + if (waitingForData && containsReal(delta)) { + waitingForData = false; if (SwingUtilities.isEventDispatchThread()) { setupTabs(nme.getNode()); - updateMatches(); } else { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { setupTabs(nme.getNode()); - updateMatches(); } }); } } } - + private boolean containsReal(Node[] delta) { for (Node n : delta) { if (!n.getDisplayName().equals(DUMMY_NODE_DISPLAY_NAME)) { @@ -656,13 +675,13 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C } return false; } - + /** * Updates the Number of Matches label on the DataResultPanel. - * + * */ private void updateMatches() { - if (rootNode != null && rootNode.getChildren() != null) { + if (rootNode != null && rootNode.getChildren() != null) { setNumMatches(rootNode.getChildren().getNodesCount()); } } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java index e11c13586e..1a388cebb0 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java @@ -36,20 +36,22 @@ import org.sleuthkit.autopsy.coreutils.Logger; /** * Top component which displays results (top-right editor mode by default). - * + * * 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: - * - * - 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. - * - * For embedding custom data result in other top components window, use DataResultPanel component instead, - * since we cannot nest top components. - * + * Others can also create an additional result viewer tc using one of the + * factory methods, that can be: + * + * - 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. + * + * 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. + * + * Implements DataResult interface by delegating to the encapsulated + * DataResultPanel. */ public class DataResultTopComponent extends TopComponent implements DataResult, ExplorerManager.Provider { @@ -58,7 +60,7 @@ public class DataResultTopComponent extends TopComponent implements DataResult, private 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 activeComponentIds = Collections.synchronizedList(new ArrayList()); @@ -66,8 +68,8 @@ public class DataResultTopComponent extends TopComponent implements DataResult, * Create a new data result top component * * @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 + * there can be only 1 main result viewer + * @param title title of the data result window */ public DataResultTopComponent(boolean isMain, String title) { associateLookup(ExplorerUtils.createLookup(explorerManager, getActionMap())); @@ -80,19 +82,20 @@ public class DataResultTopComponent extends TopComponent implements DataResult, * Create a new, custom data result top component, in addition to the * application main one * - * @param name unique name of the data result window, also used as title - * @param customModeName custom mode to dock into + * @param name unique name of the data result window, also + * used as title + * @param customModeName custom mode to dock into * @param customContentViewer custom content viewer to send selection events - * to + * to */ DataResultTopComponent(String name, String mode, DataContentTopComponent customContentViewer) { associateLookup(ExplorerUtils.createLookup(explorerManager, getActionMap())); this.customModeName = mode; dataResultPanel = new DataResultPanel(name, customContentViewer); initComponents(); - customizeComponent(isMain, name); + customizeComponent(isMain, name); } - + private void customizeComponent(boolean isMain, String title) { this.isMain = isMain; this.customModeName = null; @@ -111,10 +114,12 @@ public class DataResultTopComponent extends TopComponent implements DataResult, /** * Initialize previously created tc instance with additional data + * * @param pathText * @param givenNode * @param totalMatches - * @param newDataResult previously created with createInstance() uninitialized instance + * @param newDataResult previously created with createInstance() + * uninitialized instance */ public static void initInstance(String pathText, Node givenNode, int totalMatches, DataResultTopComponent newDataResult) { newDataResult.setNumMatches(totalMatches); @@ -124,17 +129,19 @@ public class DataResultTopComponent extends TopComponent implements DataResult, // 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 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) { @@ -146,16 +153,19 @@ public class DataResultTopComponent extends TopComponent implements DataResult, } /** - * Creates a new non-default DataResult component linked with a custom data content, and initializes it. - * + * 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 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 + * + * @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); @@ -163,13 +173,15 @@ public class DataResultTopComponent extends TopComponent implements DataResult, initInstance(pathText, givenNode, totalMatches, newDataResult); return newDataResult; } - + /** - * Creates a new non-default DataResult component. - * You probably want to use initInstance after it - * + * 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 + * + * @return a new, not default, not fully initialized DataResultTopComponent + * instance */ public static DataResultTopComponent createInstance(String title) { final DataResultTopComponent newDataResult = new DataResultTopComponent(false, title); @@ -181,15 +193,16 @@ public class DataResultTopComponent extends TopComponent implements DataResult, public ExplorerManager getExplorerManager() { return explorerManager; } - + /** * Get a list with names of active windows ids, e.g. for the menus - * @return + * + * @return */ public static List 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 @@ -233,7 +246,7 @@ public class DataResultTopComponent extends TopComponent implements DataResult, public List getViewers() { return dataResultPanel.getViewers(); } - + private void setCustomMode() { if (customModeName != null) { //putClientProperty("TopComponentAllowDockAnywhere", Boolean.TRUE); @@ -256,14 +269,14 @@ public class DataResultTopComponent extends TopComponent implements DataResult, @Override public void componentOpened() { super.componentOpened(); - this.dataResultPanel.open(); + this.dataResultPanel.open(); } - + @Override public void componentClosed() { super.componentClosed(); activeComponentIds.remove(this.getName()); - dataResultPanel.close(); + dataResultPanel.close(); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java index a5abcb1c23..912cd249e5 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java @@ -147,6 +147,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { * Gets regular Bean property set properties from first child of Node. * * @param parent Node with at least one child to get properties from + * * @return Properties, */ private Node.Property[] getChildPropertyHeaders(Node parent) { @@ -173,6 +174,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { * load - you need to set all children props for the parent by hand * * @param parent Node with at least one child to get properties from + * * @return Properties, */ @SuppressWarnings("rawtypes") @@ -213,8 +215,8 @@ public class DataResultViewerTable extends AbstractDataResultViewer { * load - you need to set all children props for the parent by hand * * @param parent Node with at least one child to get properties from - * @param rows max number of rows to retrieve properties for (can be used - * for memory optimization) + * @param rows max number of rows to retrieve properties for (can be used + * for memory optimization) */ private void getAllChildPropertyHeadersRec(Node parent, int rows) { Children children = parent.getChildren(); @@ -296,7 +298,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer { em.setRootContext(root); - final OutlineView ov = ((OutlineView) DataResultViewerTable.this.tableScrollPanel); if (ov == null) { @@ -307,21 +308,23 @@ public class DataResultViewerTable extends AbstractDataResultViewer { DataResultViewerTable.this.getAllChildPropertyHeadersRec(root, 100); List> props = new ArrayList<>(propertiesAcc); - - /* 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 - * use its display name as the header for the column so that the header can change depending on the - * type of data being displayed. + + /* + * 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 + * use its display name as the header for the column so that the header + * can change depending on the type of data being displayed. * - * NOTE: This assumes that the first property is always the one tha duplicates getDisplayName(). This - * seems like a big assumption and could be made more robust. + * NOTE: This assumes that the first property is always the one tha + * duplicates getDisplayName(). This seems like a big assumption and + * could be made more robust. */ if (props.size() > 0) { Node.Property prop = props.remove(0); ((DefaultOutlineModel) ov.getOutline().getOutlineModel()).setNodesColumnLabel(prop.getDisplayName()); } - // 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++) { @@ -344,10 +347,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { // try { // this.getExplorerManager().setSelectedNodes(new Node[]{firstEntryNode}); // } catch (PropertyVetoException ex) {} - - // show the horizontal scroll panel and show all the content & header - int totalColumns = props.size(); //int scrollWidth = ttv.getWidth(); @@ -358,13 +358,10 @@ public class DataResultViewerTable extends AbstractDataResultViewer { // Just let the table resize itself. ov.getOutline().setAutoResizeMode((props.size() > 0) ? JTable.AUTO_RESIZE_OFF : JTable.AUTO_RESIZE_ALL_COLUMNS); - - // get first 100 rows values for the table Object[][] content = null; content = getRowValues(root, 100); - if (content != null) { // get the fontmetrics final Graphics graphics = ov.getGraphics(); @@ -438,12 +435,13 @@ public class DataResultViewerTable extends AbstractDataResultViewer { /** * Gets the max width of the column from the given index, header, and table. * - * @param index the index of the column on the table / header + * @param index the index of the column on the table / header * @param metrics the font metrics that this component use - * @param margin the left/right margin of the column + * @param margin the left/right margin of the column * @param padding the left/right padding of the column - * @param header the property headers of the table - * @param table the object table + * @param header the property headers of the table + * @param table the object table + * * @return max the maximum width of the column */ @SuppressWarnings("rawtypes") @@ -457,12 +455,13 @@ public class DataResultViewerTable extends AbstractDataResultViewer { /** * Gets the max width of the column from the given index, header, and table. * - * @param index the index of the column on the table / header + * @param index the index of the column on the table / header * @param metrics the font metrics that this component use - * @param margin the left/right margin of the column + * @param margin the left/right margin of the column * @param padding the left/right padding of the column - * @param header the column header for the comparison - * @param table the object table + * @param header the column header for the comparison + * @param table the object table + * * @return max the maximum width of the column */ private synchronized int getMaxColumnWidth(int index, FontMetrics metrics, int margin, int padding, String header, Object[][] table) { diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.form index 0f9063922e..e86a2a5daf 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.form @@ -16,34 +16,42 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + - + @@ -66,8 +74,8 @@ - - + + @@ -75,18 +83,6 @@ - - - - - - - - - - - - @@ -213,5 +209,7 @@ + + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java index 37468a169d..f1e790f0f8 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java @@ -27,9 +27,6 @@ import java.util.Arrays; import java.util.concurrent.ExecutionException; import java.util.logging.Level; import javax.swing.JOptionPane; - -import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.ListSelectionModel; import javax.swing.SwingWorker; import org.netbeans.api.progress.ProgressHandle; @@ -37,7 +34,6 @@ import org.netbeans.api.progress.ProgressHandleFactory; import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.explorer.ExplorerManager; -import org.openide.explorer.view.IconView; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; import org.openide.nodes.Node; @@ -45,9 +41,10 @@ import org.openide.nodes.NodeEvent; import org.openide.nodes.NodeListener; import org.openide.nodes.NodeMemberEvent; import org.openide.nodes.NodeReorderEvent; -import org.openide.util.Exceptions; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer; import org.sleuthkit.autopsy.coreutils.ImageUtils; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; @@ -63,18 +60,18 @@ import org.sleuthkit.datamodel.TskCoreException; // service provider when DataResultViewers can be made compatible with node // multi-selection actions. //@ServiceProvider(service = DataResultViewer.class) - final class DataResultViewerThumbnail extends AbstractDataResultViewer { +final class DataResultViewerThumbnail extends AbstractDataResultViewer { private static final Logger logger = Logger.getLogger(DataResultViewerThumbnail.class.getName()); //flag to keep track if images are being loaded private int curPage; private int totalPages; private int curPageImages; - private int iconSize = ImageUtils.ICON_SIZE_MEDIUM; + private int iconSize = ImageUtils.ICON_SIZE_MEDIUM; private final PageUpdater pageUpdater = new PageUpdater(); /** - * Creates a DataResultViewerThumbnail object that is compatible with node + * Creates a DataResultViewerThumbnail object that is compatible with node * multiple selection actions. */ public DataResultViewerThumbnail(ExplorerManager explorerManager) { @@ -83,24 +80,24 @@ import org.sleuthkit.datamodel.TskCoreException; } /** - * Creates a DataResultViewerThumbnail object that is NOT compatible with + * Creates a DataResultViewerThumbnail object that is NOT compatible with * node multiple selection actions. */ public DataResultViewerThumbnail() { initialize(); - } - + } + private void initialize() { initComponents(); - ((IconView) thumbnailScrollPanel).setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + iconView.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); em.addPropertyChangeListener(new ExplorerManagerNodeSelectionListener()); curPage = -1; totalPages = 0; curPageImages = 0; - } - + } + /** * 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 @@ -110,7 +107,6 @@ import org.sleuthkit.datamodel.TskCoreException; // //GEN-BEGIN:initComponents private void initComponents() { - thumbnailScrollPanel = new IconView(); pageLabel = new javax.swing.JLabel(); pagesLabel = new javax.swing.JLabel(); pagePrevButton = new javax.swing.JButton(); @@ -122,32 +118,31 @@ import org.sleuthkit.datamodel.TskCoreException; goToPageLabel = new javax.swing.JLabel(); goToPageField = new javax.swing.JTextField(); thumbnailSizeComboBox = new javax.swing.JComboBox<>(); - - thumbnailScrollPanel.setPreferredSize(new java.awt.Dimension(582, 348)); + iconView = new org.openide.explorer.view.IconView(); pageLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pageLabel.text")); // NOI18N pagesLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pagesLabel.text")); // NOI18N - pagePrevButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); // NOI18N NON-NLS + pagePrevButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); // NOI18N pagePrevButton.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pagePrevButton.text")); // NOI18N - pagePrevButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); // NOI18N NON-NLS + pagePrevButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); // NOI18N pagePrevButton.setMargin(new java.awt.Insets(2, 0, 2, 0)); pagePrevButton.setPreferredSize(new java.awt.Dimension(55, 23)); - pagePrevButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"))); // NOI18N NON-NLS + pagePrevButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"))); // NOI18N pagePrevButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { pagePrevButtonActionPerformed(evt); } }); - pageNextButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"))); // NOI18N NON-NLS + pageNextButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"))); // NOI18N pageNextButton.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pageNextButton.text")); // NOI18N - pageNextButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); // NOI18N NON-NLS + pageNextButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); // NOI18N pageNextButton.setMargin(new java.awt.Insets(2, 0, 2, 0)); pageNextButton.setMaximumSize(new java.awt.Dimension(27, 23)); pageNextButton.setMinimumSize(new java.awt.Dimension(27, 23)); - pageNextButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"))); // NOI18N NON-NLS + pageNextButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"))); // NOI18N pageNextButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { pageNextButtonActionPerformed(evt); @@ -171,10 +166,7 @@ import org.sleuthkit.datamodel.TskCoreException; } }); - thumbnailSizeComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { - NbBundle.getMessage(this.getClass(), "DataResultViewerThumbnail.comboBox.smallThumbnails"), - NbBundle.getMessage(this.getClass(), "DataResultViewerThumbnail.comboBox.mediumThumbnails"), - NbBundle.getMessage(this.getClass(), "DataResultViewerThumbnail.comboBox.largeThumbnails") })); + thumbnailSizeComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Small Thumbnails", "Medium Thumbnails", "Large Thumbnails" })); thumbnailSizeComboBox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { thumbnailSizeComboBoxActionPerformed(evt); @@ -185,32 +177,37 @@ import org.sleuthkit.datamodel.TskCoreException; this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(thumbnailScrollPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 642, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() - .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(filePathLabel) .addGroup(layout.createSequentialGroup() - .addComponent(pageLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(pageNumLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 95, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(pagesLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(pagePrevButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(filePathLabel) + .addGroup(layout.createSequentialGroup() + .addComponent(pageLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(pageNumLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 95, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(pagesLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(pagePrevButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(pageNextButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(goToPageLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(goToPageField, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(12, 12, 12) + .addComponent(imagesLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(imagesRangeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(thumbnailSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))) + .addGroup(layout.createSequentialGroup() .addGap(0, 0, 0) - .addComponent(pageNextButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(goToPageLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(goToPageField, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(12, 12, 12) - .addComponent(imagesLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(imagesRangeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(thumbnailSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(iconView, javax.swing.GroupLayout.DEFAULT_SIZE, 563, Short.MAX_VALUE) + .addGap(0, 0, 0))) + .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -228,8 +225,8 @@ import org.sleuthkit.datamodel.TskCoreException; .addComponent(goToPageLabel) .addComponent(goToPageField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(thumbnailSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGap(0, 0, 0) - .addComponent(thumbnailScrollPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(iconView, javax.swing.GroupLayout.DEFAULT_SIZE, 330, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(filePathLabel)) ); @@ -248,28 +245,28 @@ import org.sleuthkit.datamodel.TskCoreException; }//GEN-LAST:event_goToPageFieldActionPerformed private void thumbnailSizeComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_thumbnailSizeComboBoxActionPerformed - + iconSize = ImageUtils.ICON_SIZE_MEDIUM; //default size - switch(thumbnailSizeComboBox.getSelectedIndex()) { + switch (thumbnailSizeComboBox.getSelectedIndex()) { case 0: iconSize = ImageUtils.ICON_SIZE_SMALL; break; case 2: iconSize = ImageUtils.ICON_SIZE_LARGE; break; - } + } Node root = em.getRootContext(); - for (Children c : Arrays.asList(root.getChildren()) ) { - ((ThumbnailViewChildren)c).setIconSize(iconSize); + for (Children c : Arrays.asList(root.getChildren())) { + ((ThumbnailViewChildren) c).setIconSize(iconSize); } - + for (Node page : root.getChildren().getNodes()) { for (Node node : page.getChildren().getNodes()) { - ((ThumbnailViewNode)node).setIconSize(iconSize); + ((ThumbnailViewNode) node).setIconSize(iconSize); } - } - + } + // 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 @@ -283,6 +280,7 @@ import org.sleuthkit.datamodel.TskCoreException; private javax.swing.JLabel filePathLabel; private javax.swing.JTextField goToPageField; private javax.swing.JLabel goToPageLabel; + private org.openide.explorer.view.IconView iconView; private javax.swing.JLabel imagesLabel; private javax.swing.JLabel imagesRangeLabel; private javax.swing.JLabel pageLabel; @@ -290,7 +288,6 @@ import org.sleuthkit.datamodel.TskCoreException; private javax.swing.JLabel pageNumLabel; private javax.swing.JButton pagePrevButton; private javax.swing.JLabel pagesLabel; - private javax.swing.JScrollPane thumbnailScrollPanel; private javax.swing.JComboBox thumbnailSizeComboBox; // End of variables declaration//GEN-END:variables @@ -299,7 +296,7 @@ import org.sleuthkit.datamodel.TskCoreException; if (selectedNode == null) { return false; } - return true; + return true; } @Override @@ -309,7 +306,7 @@ import org.sleuthkit.datamodel.TskCoreException; try { if (givenNode != null) { ThumbnailViewChildren childNode = new ThumbnailViewChildren(givenNode, iconSize); - + final Node root = new AbstractNode(childNode); pageUpdater.setRoot(root); root.addNodeListener(pageUpdater); @@ -318,14 +315,13 @@ import org.sleuthkit.datamodel.TskCoreException; Node emptyNode = new AbstractNode(Children.LEAF); em.setRootContext(emptyNode); // make empty node - IconView iv = ((IconView) this.thumbnailScrollPanel); - iv.setBackground(Color.BLACK); + iconView.setBackground(Color.BLACK); } } finally { this.setCursor(null); } } - + @Override public String getTitle() { return NbBundle.getMessage(this.getClass(), "DataResultViewerThumbnail.title"); @@ -348,8 +344,8 @@ import org.sleuthkit.datamodel.TskCoreException; @Override public void clearComponent() { - this.thumbnailScrollPanel.removeAll(); - this.thumbnailScrollPanel = null; + this.iconView.removeAll(); + this.iconView = null; super.clearComponent(); } @@ -369,28 +365,27 @@ import org.sleuthkit.datamodel.TskCoreException; switchPage(); } } - + private void goToPage(String pageNumText) { int newPage; try { newPage = Integer.parseInt(pageNumText); - } - catch (NumberFormatException e) { + } catch (NumberFormatException e) { //ignore input return; } - + if (newPage > totalPages || newPage < 1) { JOptionPane.showMessageDialog(this, - NbBundle.getMessage(this.getClass(), - "DataResultViewerThumbnail.goToPageTextField.msgDlg", - totalPages), - NbBundle.getMessage(this.getClass(), - "DataResultViewerThumbnail.goToPageTextField.err"), - JOptionPane.WARNING_MESSAGE); + NbBundle.getMessage(this.getClass(), + "DataResultViewerThumbnail.goToPageTextField.msgDlg", + totalPages), + NbBundle.getMessage(this.getClass(), + "DataResultViewerThumbnail.goToPageTextField.err"), + JOptionPane.WARNING_MESSAGE); return; } - + curPage = newPage; switchPage(); } @@ -418,7 +413,7 @@ import org.sleuthkit.datamodel.TskCoreException; progress.start(); progress.switchToIndeterminate(); Node root = em.getRootContext(); - Node pageNode = root.getChildren().getNodeAt(curPage - 1); + Node pageNode = root.getChildren().getNodeAt(curPage - 1); em.setExploredContext(pageNode); curPageImages = pageNode.getChildren().getNodesCount(); return null; @@ -428,16 +423,16 @@ import org.sleuthkit.datamodel.TskCoreException; protected void done() { progress.finish(); setCursor(null); - updateControls(); + updateControls(); // see if any exceptions were thrown try { get(); } catch (InterruptedException | ExecutionException ex) { - NotifyDescriptor d = - new NotifyDescriptor.Message( - NbBundle.getMessage(this.getClass(), "DataResultViewerThumbnail.switchPage.done.errMsg", - ex.getMessage()), - NotifyDescriptor.ERROR_MESSAGE); + NotifyDescriptor d + = new NotifyDescriptor.Message( + NbBundle.getMessage(this.getClass(), "DataResultViewerThumbnail.switchPage.done.errMsg", + ex.getMessage()), + NotifyDescriptor.ERROR_MESSAGE); DialogDisplayer.getDefault().notify(d); logger.log(Level.SEVERE, "Error making thumbnails: " + ex.getMessage()); //NON-NLS } // catch and ignore if we were cancelled @@ -458,14 +453,14 @@ import org.sleuthkit.datamodel.TskCoreException; } else { pageNumLabel.setText( NbBundle.getMessage(this.getClass(), "DataResultViewerThumbnail.pageNumbers.curOfTotal", - Integer.toString(curPage), Integer.toString(totalPages))); + 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; imagesRangeLabel.setText(imagesFrom + "-" + imagesTo); pageNextButton.setEnabled(!(curPage == totalPages)); pagePrevButton.setEnabled(!(curPage == 1)); - goToPageField.setEnabled(totalPages>1); + goToPageField.setEnabled(totalPages > 1); } @@ -534,7 +529,6 @@ import org.sleuthkit.datamodel.TskCoreException; em.setExploredContext(pageNode); } - updateControls(); } @@ -554,8 +548,9 @@ import org.sleuthkit.datamodel.TskCoreException; public void nodeDestroyed(NodeEvent ne) { } } - + private class ExplorerManagerNodeSelectionListener implements PropertyChangeListener { + @Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) { @@ -566,26 +561,23 @@ import org.sleuthkit.datamodel.TskCoreException; AbstractFile af = selectedNodes[0].getLookup().lookup(AbstractFile.class); if (af == null) { filePathLabel.setText(""); - } - else { + } else { try { String uPath = af.getUniquePath(); filePathLabel.setText(uPath); filePathLabel.setToolTipText(uPath); - } - catch (TskCoreException e){ + } catch (TskCoreException e) { logger.log(Level.WARNING, "Could not get unique path for content: {0}", af.getName()); //NON-NLS } - } + } + } else { + filePathLabel.setText(""); } - else { - filePathLabel.setText(""); - } - } - finally { + } finally { setCursor(null); } - } + } } - } + + } } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/FXVideoPanel.form b/Core/src/org/sleuthkit/autopsy/corecomponents/FXVideoPanel.form index 5143a19b43..d618556924 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/FXVideoPanel.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/FXVideoPanel.form @@ -16,8 +16,35 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/FXVideoPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/FXVideoPanel.java index 728749ccf6..0723e73f16 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/FXVideoPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/FXVideoPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,9 @@ */ package org.sleuthkit.autopsy.corecomponents; +import com.google.common.io.Files; import java.awt.Dimension; +import java.io.File; import java.io.IOException; import java.nio.file.Paths; import java.util.Arrays; @@ -26,11 +28,8 @@ import java.util.List; import java.util.concurrent.CancellationException; import java.util.logging.Level; import javafx.application.Platform; -import javafx.beans.InvalidationListener; import javafx.beans.Observable; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.embed.swing.JFXPanel; +import javafx.concurrent.Task; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; @@ -55,17 +54,15 @@ import static javafx.scene.media.MediaPlayer.Status.STOPPED; import javafx.scene.media.MediaView; import javafx.util.Duration; import javax.swing.JPanel; -import javax.swing.SwingUtilities; -import javax.swing.SwingWorker; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; -import org.openide.util.Cancellable; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProviders; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.core.Installer; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.VideoUtils; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; @@ -78,58 +75,37 @@ import org.sleuthkit.datamodel.TskData; @ServiceProvider(service = FrameCapture.class) }) public class FXVideoPanel extends MediaViewVideoPanel { - + // Refer to https://docs.oracle.com/javafx/2/api/javafx/scene/media/package-summary.html // for Javafx supported formats private static final String[] EXTENSIONS = new String[]{".m4v", ".fxm", ".flv", ".m3u8", ".mp4", ".aif", ".aiff", ".mp3", "m4a", ".wav"}; //NON-NLS private static final List MIMETYPES = Arrays.asList("audio/x-aiff", "video/x-javafx", "video/x-flv", "application/vnd.apple.mpegurl", " audio/mpegurl", "audio/mpeg", "video/mp4", "audio/x-m4a", "video/x-m4v", "audio/x-wav"); //NON-NLS - private static final Logger logger = Logger.getLogger(MediaViewVideoPanel.class.getName()); + private static final Logger logger = Logger.getLogger(FXVideoPanel.class.getName()); private boolean fxInited = false; - // FX Components private MediaPane mediaPane; - // Current media content representations private AbstractFile currentFile; - // FX UI Components - private JFXPanel videoComponent; - - /** - * Creates new form MediaViewVideoPanel - */ public FXVideoPanel() { fxInited = Installer.isJavaFxInited(); initComponents(); if (fxInited) { - setupFx(); + Platform.runLater(() -> { + + mediaPane = new MediaPane(); + Scene fxScene = new Scene(mediaPane); + jFXPanel.setScene(fxScene); + }); } } + @Deprecated public JPanel getVideoPanel() { return this; } - private void setupFx() { - Platform.runLater(new Runnable() { - @Override - public void run() { - videoComponent = new JFXPanel(); - mediaPane = new MediaPane(); - Scene fxScene = new Scene(mediaPane); - videoComponent.setScene(fxScene); - - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - add(videoComponent); - } - }); - } - }); - } - @Override void setupVideo(final AbstractFile file, final Dimension dims) { if (file.equals(currentFile)) { @@ -148,50 +124,33 @@ public class FXVideoPanel extends MediaViewVideoPanel { removeAll(); return; } + mediaPane.setFit(dims); String path = ""; try { path = file.getUniquePath(); } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Cannot get unique path of video file"); //NON-NLS + logger.log(Level.SEVERE, "Cannot get unique path of video file", ex); //NON-NLS } mediaPane.setInfoLabelText(path); mediaPane.setInfoLabelToolTipText(path); - ExtractMedia em = new ExtractMedia(currentFile, getJFile(currentFile)); - em.execute(); + final File tempFile = VideoUtils.getTempVideoFile(currentFile); + + new Thread(mediaPane.new ExtractMedia(currentFile, tempFile)).start(); - mediaPane.setFit(dims); } @Override void reset() { - Platform.runLater(new Runnable() { - @Override - public void run() { - if (mediaPane != null) { - mediaPane.reset(); - } + Platform.runLater(() -> { + if (mediaPane != null) { + mediaPane.reset(); } }); currentFile = null; } - private java.io.File getJFile(AbstractFile file) { - // Get the temp folder path of the case - String tempPath = Case.getCurrentCase().getTempDirectory(); - String name = file.getName(); - int extStart = name.lastIndexOf("."); - String ext = ""; - if (extStart != -1) { - ext = name.substring(extStart, name.length()).toLowerCase(); - } - tempPath = tempPath + java.io.File.separator + file.getId() + ext; - - java.io.File tempFile = new java.io.File(tempPath); - return tempFile; - } - /** * 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 @@ -201,10 +160,34 @@ public class FXVideoPanel extends MediaViewVideoPanel { // //GEN-BEGIN:initComponents private void initComponents() { + jFXPanel = new javafx.embed.swing.JFXPanel(); + setBackground(new java.awt.Color(0, 0, 0)); - setLayout(new javax.swing.BoxLayout(this, javax.swing.BoxLayout.LINE_AXIS)); + + javax.swing.GroupLayout jFXPanelLayout = new javax.swing.GroupLayout(jFXPanel); + jFXPanel.setLayout(jFXPanelLayout); + jFXPanelLayout.setHorizontalGroup( + jFXPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 400, Short.MAX_VALUE) + ); + jFXPanelLayout.setVerticalGroup( + jFXPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 300, Short.MAX_VALUE) + ); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jFXPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jFXPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables + private javafx.embed.swing.JFXPanel jFXPanel; // End of variables declaration//GEN-END:variables @Override @@ -212,134 +195,38 @@ public class FXVideoPanel extends MediaViewVideoPanel { return fxInited; } - /** - * Thread that extracts Media from a Sleuthkit file representation to a - * Java file representation that the Media Player can take as input. - */ - private class ExtractMedia extends SwingWorker { - - private ProgressHandle progress; - - boolean success = false; - - private AbstractFile sFile; - - private java.io.File jFile; - - private long extractedBytes; - - ExtractMedia(org.sleuthkit.datamodel.AbstractFile sFile, java.io.File jFile) { - this.sFile = sFile; - this.jFile = jFile; - } - - public long getExtractedBytes() { - return extractedBytes; - } - - /** - * Get the URI of the media file. - * - * @return the URI of the media file. - */ - public String getMediaUri() { - return Paths.get(jFile.getAbsolutePath()).toUri().toString(); - } - - @Override - protected Object doInBackground() throws Exception { - success = false; - progress = ProgressHandleFactory.createHandle( - NbBundle.getMessage(this.getClass(), "FXVideoPanel.progress.bufferingFile", sFile.getName()), - new Cancellable() { - @Override - public boolean cancel() { - return ExtractMedia.this.cancel(true); - } - }); - mediaPane.setProgressLabelText(NbBundle.getMessage(this.getClass(), "FXVideoPanel.progressLabel.buffering")); - progress.start(); - progress.switchToDeterminate(100); - try { - extractedBytes = ContentUtils.writeToFile(sFile, jFile, progress, this, true); - } catch (IOException ex) { - logger.log(Level.WARNING, "Error buffering file", ex); //NON-NLS - } - logger.log(Level.INFO, "Done buffering: " + jFile.getName()); //NON-NLS - success = true; - return null; - } - - /* clean up or start the worker threads */ - @Override - protected void done() { - mediaPane.setProgressLabelText(""); - try { - super.get(); //block and get all exceptions thrown while doInBackground() - } catch (CancellationException ex) { - logger.log(Level.INFO, "Media buffering was canceled."); //NON-NLS - mediaPane.setProgressLabelText( - NbBundle.getMessage(this.getClass(), "FXVideoPanel.progress.bufferingCancelled")); - } catch (InterruptedException ex) { - logger.log(Level.INFO, "Media buffering was interrupted."); //NON-NLS - mediaPane.setProgressLabelText( - NbBundle.getMessage(this.getClass(), "FXVideoPanel.progress.bufferingInterrupted")); - } catch (Exception ex) { - logger.log(Level.SEVERE, "Fatal error during media buffering.", ex); //NON-NLS - mediaPane.setProgressLabelText( - NbBundle.getMessage(this.getClass(), "FXVideoPanel.progress.errorWritingVideoToDisk")); - } finally { - progress.finish(); - if (!this.isCancelled()) { - logger.log(Level.INFO, "ExtractMedia in done: " + jFile.getName()); //NON-NLS - try { - Platform.runLater(new Runnable() { - @Override - public void run() { - mediaPane.prepareMedia(getMediaUri()); - } - }); - } catch (MediaException e) { - logger.log(Level.WARNING, "something went wrong with javafx", e); //NON-NLS - reset(); - mediaPane.setInfoLabelText(e.getMessage()); - return; - } - } - } - } - } - - /** - * The JavaFX Component that contains the Media and it's Controls. - * - */ private class MediaPane extends BorderPane { private MediaPlayer mediaPlayer; - private MediaView mediaView; + private final MediaView mediaView; - /** The Duration of the media. * */ + /** + * The Duration of the media. * + */ private Duration duration; - /** The container for the media controls. * */ - private HBox mediaTools; + /** + * The container for the media controls. * + */ + private final HBox mediaTools; - /** The container for the media video output. * */ - private HBox mediaViewPane; + /** + * The container for the media video output. * + */ + private final HBox mediaViewPane; - private VBox controlPanel; + private final VBox controlPanel; - private Slider progressSlider; + private final Slider progressSlider; - private Button pauseButton; + private final Button pauseButton; - private Button stopButton; + private final Button stopButton; - private Label progressLabel; + private final Label progressLabel; - private Label infoLabel; + private final Label infoLabel; private int totalHours; @@ -347,22 +234,7 @@ public class FXVideoPanel extends MediaViewVideoPanel { private int totalSeconds; - private String durationFormat = "%02d:%02d:%02d/%02d:%02d:%02d "; //NON-NLS - - /** The EventHandler for MediaPlayer.onReady(). * */ - private final ReadyListener READY_LISTENER = new ReadyListener(); - - /** The EventHandler for MediaPlayer.onEndOfMedia(). * */ - private final EndOfMediaListener END_LISTENER = new EndOfMediaListener(); - - /** The EventHandler for the CurrentTime property of the MediaPlayer. * */ - private final TimeListener TIME_LISTENER = new TimeListener(); - - /** The EventHandler for MediaPlayer.onPause and MediaPlayer.onStop. * */ - private final NotPlayListener NOT_PLAY_LISTENER = new NotPlayListener(); - - /** The EventHandler for MediaPlayer.onPlay. * */ - private final PlayListener PLAY_LISTENER = new PlayListener(); + private final String durationFormat = "%02d:%02d:%02d/%02d:%02d:%02d "; //NON-NLS private static final String PLAY_TEXT = "â–º"; @@ -409,22 +281,6 @@ public class FXVideoPanel extends MediaViewVideoPanel { setProgressActionListeners(); } - /** - * Setup the MediaPane for media playback. Run on the JavaFx Thread. - * - * - * @param mediaUri the URI of the media - */ - public void prepareMedia(String mediaUri) { - try { - mediaPlayer = createMediaPlayer(mediaUri); - mediaView.setMediaPlayer(mediaPlayer); - } catch (MediaException ex) { - this.setProgressLabelText(""); - this.setInfoLabelText(NbBundle.getMessage(this.getClass(), "FXVideoPanel.media.unsupportedFormat")); - } - } - /** * Reset this MediaPane. * @@ -447,12 +303,9 @@ public class FXVideoPanel extends MediaViewVideoPanel { * @param text */ public void setInfoLabelText(final String text) { - logger.log(Level.INFO, "Setting Info Label Text: " + text); //NON-NLS - Platform.runLater(new Runnable() { - @Override - public void run() { - infoLabel.setText(text); - } + logger.log(Level.INFO, "Setting Info Label Text: {0}", text); //NON-NLS + Platform.runLater(() -> { + infoLabel.setText(text); }); } @@ -462,14 +315,11 @@ public class FXVideoPanel extends MediaViewVideoPanel { * @param dims the current dimensions of the DataContentViewer */ public void setFit(final Dimension dims) { - Platform.runLater(new Runnable() { - @Override - public void run() { - setPrefSize(dims.getWidth(), dims.getHeight()); - // Set the Video output to fit the size allocated for it. give an - // extra few px to ensure the info label will be shown - mediaView.setFitHeight(dims.getHeight() - controlPanel.getHeight()); - } + Platform.runLater(() -> { + setPrefSize(dims.getWidth(), dims.getHeight()); + // Set the Video output to fit the size allocated for it. give an + // extra few px to ensure the info label will be shown + mediaView.setFitHeight(dims.getHeight() - controlPanel.getHeight()); }); } @@ -498,7 +348,7 @@ public class FXVideoPanel extends MediaViewVideoPanel { mediaPlayer.play(); break; default: - logger.log(Level.INFO, "MediaPlayer in unexpected state: " + status.toString()); //NON-NLS + logger.log(Level.INFO, "MediaPlayer in unexpected state: {0}", status.toString()); //NON-NLS // If the MediaPlayer is in an unexpected state, stop playback. mediaPlayer.stop(); setInfoLabelText(NbBundle.getMessage(this.getClass(), @@ -508,27 +358,21 @@ public class FXVideoPanel extends MediaViewVideoPanel { } }); - stopButton.setOnAction(new EventHandler() { - @Override - public void handle(ActionEvent e) { - if (mediaPlayer == null) { - return; - } - - mediaPlayer.stop(); + stopButton.setOnAction((ActionEvent e) -> { + if (mediaPlayer == null) { + return; } + + mediaPlayer.stop(); }); - progressSlider.valueProperty().addListener(new InvalidationListener() { - @Override - public void invalidated(Observable o) { - if (mediaPlayer == null) { - return; - } + progressSlider.valueProperty().addListener((Observable o) -> { + if (mediaPlayer == null) { + return; + } - if (progressSlider.isValueChanging()) { - mediaPlayer.seek(duration.multiply(progressSlider.getValue() / 100.0)); - } + if (progressSlider.isValueChanging()) { + mediaPlayer.seek(duration.multiply(progressSlider.getValue() / 100.0)); } }); } @@ -557,13 +401,21 @@ public class FXVideoPanel extends MediaViewVideoPanel { Media media = new Media(mediaUri); MediaPlayer player = new MediaPlayer(media); - player.setOnReady(READY_LISTENER); - player.setOnPaused(NOT_PLAY_LISTENER); - player.setOnStopped(NOT_PLAY_LISTENER); - player.setOnPlaying(PLAY_LISTENER); - player.setOnEndOfMedia(END_LISTENER); + player.setOnReady(new ReadyListener()); + final Runnable pauseListener = () -> { + pauseButton.setText(PLAY_TEXT); + }; + player.setOnPaused(pauseListener); + player.setOnStopped(pauseListener); + player.setOnPlaying(() -> { + pauseButton.setText(PAUSE_TEXT); + }); + player.setOnEndOfMedia(new EndOfMediaListener()); - player.currentTimeProperty().addListener(TIME_LISTENER); + player.currentTimeProperty().addListener((observable, oldTime, newTime) -> { + updateSlider(newTime); + updateTime(newTime); + }); return player; } @@ -614,31 +466,16 @@ public class FXVideoPanel extends MediaViewVideoPanel { elapsedSeconds = (int) secondsElapsed; String durationStr = String.format(durationFormat, - elapsedHours, elapsedMinutes, elapsedSeconds, - totalHours, totalMinutes, totalSeconds); - setProgressLabelText(durationStr); - } - - /** - * Update the progress label to show the text. - * - * @param text - */ - private void setProgressLabelText(final String text) { - Platform.runLater(new Runnable() { - @Override - public void run() { - progressLabel.setText(text); - } + elapsedHours, elapsedMinutes, elapsedSeconds, + totalHours, totalMinutes, totalSeconds); + Platform.runLater(() -> { + progressLabel.setText(durationStr); }); } private void setInfoLabelToolTipText(final String text) { - Platform.runLater(new Runnable() { - @Override - public void run() { - infoLabel.setTooltip(new Tooltip(text)); - } + Platform.runLater(() -> { + infoLabel.setTooltip(new Tooltip(text)); }); } @@ -654,7 +491,7 @@ public class FXVideoPanel extends MediaViewVideoPanel { if (mediaPlayer == null) { return; } - + duration = mediaPlayer.getMedia().getDuration(); long durationInMillis = (long) mediaPlayer.getMedia().getDuration().toMillis(); @@ -692,38 +529,105 @@ public class FXVideoPanel extends MediaViewVideoPanel { } /** - * Responds to changes in the MediaPlayer currentTime property. - * - * Updates the progress slider and label with the current Time. + * Thread that extracts Media from a Sleuthkit file representation to a + * Java file representation that the Media Player can take as input. */ - private class TimeListener implements ChangeListener { + private class ExtractMedia extends Task { - @Override - public void changed(ObservableValue observable, Duration oldValue, Duration newValue) { - updateSlider(newValue); - updateTime(newValue); + private ProgressHandle progress; + + private final AbstractFile sourceFile; + + private final java.io.File tempFile; + + ExtractMedia(AbstractFile sFile, java.io.File jFile) { + this.sourceFile = sFile; + this.tempFile = jFile; } - } - /** - * Triggered when MediaPlayer State changes to PAUSED or Stopped. - */ - private class NotPlayListener implements Runnable { - - @Override - public void run() { - pauseButton.setText(PLAY_TEXT); + /** + * Get the URI of the media file. + * + * @return the URI of the media file. + */ + public String getMediaUri() { + return Paths.get(tempFile.getAbsolutePath()).toUri().toString(); } - } - - /** - * Triggered when MediaPlayer State changes to PLAYING. - */ - private class PlayListener implements Runnable { @Override - public void run() { - pauseButton.setText(PAUSE_TEXT); + protected Long call() throws Exception { + if (tempFile.exists() == false || tempFile.length() < sourceFile.getSize()) { + progress = ProgressHandleFactory.createHandle( + NbBundle.getMessage(this.getClass(), + "FXVideoPanel.progress.bufferingFile", + sourceFile.getName() + ), + () -> ExtractMedia.this.cancel(true)); + + Platform.runLater(() -> { + progressLabel.setText(NbBundle.getMessage(this.getClass(), "FXVideoPanel.progressLabel.buffering")); + }); + + progress.start(100); + try { + Files.createParentDirs(tempFile); + return ContentUtils.writeToFile(sourceFile, tempFile, progress, this, true); + } catch (IOException ex) { + logger.log(Level.WARNING, "Error buffering file", ex); //NON-NLS + return 0L; + } finally { + logger.log(Level.INFO, "Done buffering: {0}", tempFile.getName()); //NON-NLS + } + } + return 0L; + } + + @Override + protected void failed() { + super.failed(); + onDone(); + } + + @Override + protected void succeeded() { + super.succeeded(); + onDone(); + } + + @Override + protected void cancelled() { + super.cancelled(); + onDone(); + } + + private void onDone() { + progressLabel.setText(""); + try { + super.get(); //block and get all exceptions thrown while doInBackground() + } catch (CancellationException ex) { + logger.log(Level.INFO, "Media buffering was canceled."); //NON-NLS + progressLabel.setText(NbBundle.getMessage(this.getClass(), "FXVideoPanel.progress.bufferingCancelled")); + } catch (InterruptedException ex) { + logger.log(Level.INFO, "Media buffering was interrupted."); //NON-NLS + progressLabel.setText(NbBundle.getMessage(this.getClass(), "FXVideoPanel.progress.bufferingInterrupted")); + } catch (Exception ex) { + logger.log(Level.SEVERE, "Fatal error during media buffering.", ex); //NON-NLS + progressLabel.setText(NbBundle.getMessage(this.getClass(), "FXVideoPanel.progress.errorWritingVideoToDisk")); + } finally { + if (null != progress) { + progress.finish(); + } + if (!this.isCancelled()) { + logger.log(Level.INFO, "ExtractMedia is done: {0}", tempFile.getName()); //NON-NLS + try { + mediaPane.mediaPlayer = mediaPane.createMediaPlayer(getMediaUri()); + mediaView.setMediaPlayer(mediaPane.mediaPlayer); + } catch (MediaException ex) { + progressLabel.setText(""); + mediaPane.setInfoLabelText(NbBundle.getMessage(this.getClass(), "FXVideoPanel.media.unsupportedFormat")); + } + } + } } } } @@ -731,122 +635,22 @@ public class FXVideoPanel extends MediaViewVideoPanel { /** * @param file a video file from which to capture frames * @param numFrames the number of frames to capture. These frames will be - * captured at successive intervals given by durationOfVideo/numFrames. If - * this frame interval is less than MIN_FRAME_INTERVAL_MILLIS, then only one - * frame will be captured and returned. + * captured at successive intervals given by + * durationOfVideo/numFrames. If this frame interval is + * less than MIN_FRAME_INTERVAL_MILLIS, then only one frame + * will be captured and returned. * * @return a List of VideoFrames representing the captured frames. */ @Override public List captureFrames(java.io.File file, int numFrames) throws Exception { -// -// try { -// List frames = new ArrayList<>(); -// -// FrameCapturer fc = new FrameCapturer(file); -// logger.log(Level.INFO, "Fc is null? " + (fc == null)); -// frames = fc.getFrames(numFrames); -// -// return frames; -// } -// catch (NullPointerException e) { -// e.printStackTrace(); -// return null; -// } + //What is/was the point of this method /interface. return null; } -// private class FrameCapturer { -// -// private MediaPlayer mediaPlayer; -// private JFXPanel panel; -// private boolean isReady = false; -// -// FrameCapturer(java.io.File file) { -// initFx(file); -// } -// -// boolean isReady() { -// return isReady; -// } -// -// private void initFx(final java.io.File file) { -// Platform.runAndWait(new Runnable() { -// @Override -// public void run() { -// logger.log(Level.INFO, "In initFX."); -// // Create Media Player with no video output -// Media media = new Media(Paths.get(file.getAbsolutePath()).toUri().toString()); -// mediaPlayer = new MediaPlayer(media); -// MediaView mediaView = new MediaView(mediaPlayer); -// mediaView.setStyle("-fx-background-color: black"); -// Pane mediaViewPane = new Pane(); -// mediaViewPane.getChildren().add(mediaView); -// Scene scene = new Scene(mediaViewPane); -// panel = new JFXPanel(); -// panel.setScene(scene); -// isReady = true; -// } -// }); -// } -// -// List getFrames(int numFrames) { -// logger.log(Level.INFO, "in get frames"); -// List frames = new ArrayList(0); -// -// if (mediaPlayer.getStatus() != Status.READY) { -// try { -// Thread.sleep(500); -// } catch (InterruptedException e) { -// return frames; -// } -// } -// -// // get the duration of the video -// long myDurationMillis = (long) mediaPlayer.getMedia().getDuration().toMillis(); -// if (myDurationMillis <= 0) { -// return frames; -// } -// -// // calculate the frame interval -// int numFramesToGet = numFrames; -// long frameInterval = (myDurationMillis - INTER_FRAME_PERIOD_MS) / numFrames; -// if (frameInterval < MIN_FRAME_INTERVAL_MILLIS) { -// numFramesToGet = 1; -// } -// -// final Object frameLock = new Object(); -// BufferedImage frame; -// final int width = (int) panel.getSize().getWidth(); -// final int height = (int) panel.getSize().getHeight(); -// // for each timeStamp, grap a frame -// for (int i = 0; i < numFramesToGet; ++i) { -// frame = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); -// logger.log(Level.INFO, "Grabbing a frame..."); -// final long timeStamp = i * frameInterval + INTER_FRAME_PERIOD_MS; -// -// // Platform.runLater(new Runnable() { -// // @Override -// // public void run() { -// // synchronized (frameLock) { -// logger.log(Level.INFO, "seeking."); -// mediaPlayer.seek(new Duration(timeStamp)); -// // } -// // } -// // }); -// -// synchronized (frameLock) { -// panel.paint(frame.createGraphics()); -// logger.log(Level.INFO, "Adding image to frames"); -// } -// frames.add(new VideoFrame(frame, timeStamp)); -// } -// return frames; -// } -// } @Override public String[] getExtensions() { - return EXTENSIONS; + return EXTENSIONS.clone(); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/FrameCapture.java b/Core/src/org/sleuthkit/autopsy/corecomponents/FrameCapture.java index 084300be67..419bbabbb9 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/FrameCapture.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/FrameCapture.java @@ -24,13 +24,15 @@ import java.util.List; /** * Interface used to capture frames from a video file. */ - public interface FrameCapture { - +public interface FrameCapture { + /** - * @param file the video file to use + * @param file the video file to use * @param numFrames the number of frames to capture. Note that the actual - * number of frames returned may be less than this number. Specifically, this - * may happen if the video is very short. + * number of frames returned may be less than this number. + * Specifically, this may happen if the video is very + * short. + * * @return a list of VideoFrames representing the captured frames */ List captureFrames(File file, int numFrames) throws Exception; diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/GstVideoPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/GstVideoPanel.java index db5f97b40f..49862754d1 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/GstVideoPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/GstVideoPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.corecomponents; import java.awt.Dimension; import java.awt.Image; import java.awt.image.BufferedImage; +import java.io.File; import java.io.IOException; import java.nio.IntBuffer; import java.util.ArrayList; @@ -41,7 +42,6 @@ import javax.swing.JSlider; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; import org.gstreamer.ClockTime; import org.gstreamer.Gst; import org.gstreamer.GstException; @@ -52,26 +52,25 @@ import org.gstreamer.elements.RGBDataSink; import org.gstreamer.swing.VideoComponent; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; -import org.openide.util.Cancellable; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProviders; -import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.coreutils.VideoUtils; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; - @ServiceProviders(value = { @ServiceProvider(service = FrameCapture.class) }) public class GstVideoPanel extends MediaViewVideoPanel { - private static final String[] EXTENSIONS = new String[]{".mov", ".m4v", ".flv", ".mp4", ".3gp", ".avi", ".mpg", ".mpeg", ".wmv"}; //NON-NLS + + private static final String[] EXTENSIONS = new String[]{".mov", ".m4v", ".flv", ".mp4", ".3gp", ".avi", ".mpg", ".mpeg", ".wmv"}; //NON-NLS private static final List MIMETYPES = Arrays.asList("video/quicktime", "audio/mpeg", "audio/x-mpeg", "video/mpeg", "video/x-mpeg", "audio/mpeg3", "audio/x-mpeg-3", "video/x-flv", "video/mp4", "audio/x-m4a", "video/x-m4v", "audio/x-wav"); //NON-NLS - + private static final Logger logger = Logger.getLogger(GstVideoPanel.class.getName()); private boolean gstInited; private static final long MIN_FRAME_INTERVAL_MILLIS = 500; @@ -87,7 +86,7 @@ public class GstVideoPanel extends MediaViewVideoPanel { private final Object playbinLock = new Object(); // lock for synchronization of gstPlaybin2 player private AbstractFile currentFile; private final Set badVideoFiles = Collections.synchronizedSet(new HashSet()); - + /** * Creates new form MediaViewVideoPanel */ @@ -129,30 +128,27 @@ public class GstVideoPanel extends MediaViewVideoPanel { progressSlider.setEnabled(false); // disable slider; enable after user plays vid progressSlider.setValue(0); - progressSlider.addChangeListener(new ChangeListener() { + progressSlider.addChangeListener((ChangeEvent e) -> { /** * Should always try to synchronize any call to - * progressSlider.setValue() to avoid a different thread - * changing playbin while stateChanged() is processing + * progressSlider.setValue() to avoid a different thread changing + * playbin while stateChanged() is processing */ - @Override - public void stateChanged(ChangeEvent e) { - int time = progressSlider.getValue(); - synchronized (playbinLock) { - if (gstPlaybin2 != null && !autoTracking) { - State orig = gstPlaybin2.getState(); - if (gstPlaybin2.pause() == StateChangeReturn.FAILURE) { - logger.log(Level.WARNING, "Attempt to call PlayBin2.pause() failed."); //NON-NLS - infoLabel.setText(MEDIA_PLAYER_ERROR_STRING); - return; - } - if (gstPlaybin2.seek(ClockTime.fromMillis(time)) == false) { - logger.log(Level.WARNING, "Attempt to call PlayBin2.seek() failed."); //NON-NLS - infoLabel.setText(MEDIA_PLAYER_ERROR_STRING); - return; - } - gstPlaybin2.setState(orig); + int time = progressSlider.getValue(); + synchronized (playbinLock) { + if (gstPlaybin2 != null && !autoTracking) { + State orig = gstPlaybin2.getState(); + if (gstPlaybin2.pause() == StateChangeReturn.FAILURE) { + logger.log(Level.WARNING, "Attempt to call PlayBin2.pause() failed."); //NON-NLS + infoLabel.setText(MEDIA_PLAYER_ERROR_STRING); + return; } + if (gstPlaybin2.seek(ClockTime.fromMillis(time)) == false) { + logger.log(Level.WARNING, "Attempt to call PlayBin2.seek() failed."); //NON-NLS + infoLabel.setText(MEDIA_PLAYER_ERROR_STRING); + return; + } + gstPlaybin2.setState(orig); } } }); @@ -195,7 +191,7 @@ public class GstVideoPanel extends MediaViewVideoPanel { progressSlider.setEnabled(false); return; } - + String path = ""; try { path = file.getUniquePath(); @@ -207,7 +203,7 @@ public class GstVideoPanel extends MediaViewVideoPanel { pauseButton.setEnabled(true); progressSlider.setEnabled(true); - java.io.File ioFile = getJFile(file); + java.io.File ioFile = VideoUtils.getTempVideoFile(file); gstVideoComponent = new VideoComponent(); synchronized (playbinLock) { @@ -219,14 +215,13 @@ public class GstVideoPanel extends MediaViewVideoPanel { videoPanel.removeAll(); - videoPanel.setLayout(new BoxLayout(videoPanel, BoxLayout.Y_AXIS)); videoPanel.add(gstVideoComponent); videoPanel.setVisible(true); gstPlaybin2.setInputFile(ioFile); - + if (gstPlaybin2.setState(State.READY) == StateChangeReturn.FAILURE) { logger.log(Level.WARNING, "Attempt to call PlayBin2.setState(State.READY) failed."); //NON-NLS infoLabel.setText(MEDIA_PLAYER_ERROR_STRING); @@ -239,11 +234,8 @@ public class GstVideoPanel extends MediaViewVideoPanel { void reset() { // reset the progress label text on the event dispatch thread - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - progressLabel.setText(""); - } + SwingUtilities.invokeLater(() -> { + progressLabel.setText(""); }); if (!isInited()) { @@ -281,41 +273,28 @@ public class GstVideoPanel extends MediaViewVideoPanel { currentFile = null; } - private java.io.File getJFile(AbstractFile file) { - // Get the temp folder path of the case - String tempPath = Case.getCurrentCase().getTempDirectory(); - String name = file.getName(); - int extStart = name.lastIndexOf("."); - String ext = ""; - if (extStart != -1) { - ext = name.substring(extStart, name.length()).toLowerCase(); - } - tempPath = tempPath + java.io.File.separator + file.getId() + ext; - - java.io.File tempFile = new java.io.File(tempPath); - return tempFile; - } - /** - * @param file a video file from which to capture frames + * @param file a video file from which to capture frames * @param numFrames the number of frames to capture. These frames will be - * captured at successive intervals given by durationOfVideo/numFrames. If - * this frame interval is less than MIN_FRAME_INTERVAL_MILLIS, then only one - * frame will be captured and returned. + * captured at successive intervals given by + * durationOfVideo/numFrames. If this frame interval is + * less than MIN_FRAME_INTERVAL_MILLIS, then only one frame + * will be captured and returned. + * * @return a List of VideoFrames representing the captured frames. */ @Override public List captureFrames(java.io.File file, int numFrames) throws Exception { List frames = new ArrayList<>(); - + Object lock = new Object(); FrameCaptureRGBListener rgbListener = new FrameCaptureRGBListener(lock); - + if (!isInited()) { return frames; } - + // throw exception if this file is known to be problematic if (badVideoFiles.contains(file.getName())) { throw new Exception( @@ -374,7 +353,7 @@ public class GstVideoPanel extends MediaViewVideoPanel { if (!playbin.seek(timeStamp, unit)) { logger.log(Level.INFO, "There was a problem seeking to " + timeStamp + " " + unit.name().toLowerCase()); //NON-NLS } - + ret = playbin.play(); if (ret == StateChangeReturn.FAILURE) { // add this file to the set of known bad ones @@ -384,7 +363,7 @@ public class GstVideoPanel extends MediaViewVideoPanel { } // wait for FrameCaptureRGBListener to finish - synchronized(lock) { + synchronized (lock) { try { lock.wait(FRAME_CAPTURE_TIMEOUT_MILLIS); } catch (InterruptedException e) { @@ -400,7 +379,7 @@ public class GstVideoPanel extends MediaViewVideoPanel { throw new Exception( NbBundle.getMessage(this.getClass(), "GstVideoPanel.exception.problemStopCaptFrame.msg")); } - + if (image == null) { logger.log(Level.WARNING, "There was a problem while trying to capture a frame from file " + file.getName()); //NON-NLS badVideoFiles.add(file.getName()); @@ -412,13 +391,13 @@ public class GstVideoPanel extends MediaViewVideoPanel { return frames; } - + private class FrameCaptureRGBListener implements RGBDataSink.Listener { public FrameCaptureRGBListener(Object waiter) { this.waiter = waiter; } - + private BufferedImage bi; private final Object waiter; @@ -438,7 +417,7 @@ public class GstVideoPanel extends MediaViewVideoPanel { return image; } } - + } /** @@ -460,12 +439,12 @@ public class GstVideoPanel extends MediaViewVideoPanel { javax.swing.GroupLayout videoPanelLayout = new javax.swing.GroupLayout(videoPanel); videoPanel.setLayout(videoPanelLayout); videoPanelLayout.setHorizontalGroup( - videoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 0, Short.MAX_VALUE) + videoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 0, Short.MAX_VALUE) ); videoPanelLayout.setVerticalGroup( - videoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 231, Short.MAX_VALUE) + videoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 231, Short.MAX_VALUE) ); org.openide.awt.Mnemonics.setLocalizedText(pauseButton, org.openide.util.NbBundle.getMessage(GstVideoPanel.class, "MediaViewVideoPanel.pauseButton.text")); // NOI18N @@ -482,48 +461,48 @@ public class GstVideoPanel extends MediaViewVideoPanel { javax.swing.GroupLayout controlPanelLayout = new javax.swing.GroupLayout(controlPanel); controlPanel.setLayout(controlPanelLayout); controlPanelLayout.setHorizontalGroup( - controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(controlPanelLayout.createSequentialGroup() - .addContainerGap() - .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(controlPanelLayout.createSequentialGroup() - .addGap(6, 6, 6) - .addComponent(infoLabel) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGroup(controlPanelLayout.createSequentialGroup() - .addComponent(pauseButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(progressSlider, javax.swing.GroupLayout.DEFAULT_SIZE, 265, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(progressLabel) - .addContainerGap()))) + controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(controlPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(controlPanelLayout.createSequentialGroup() + .addGap(6, 6, 6) + .addComponent(infoLabel) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(controlPanelLayout.createSequentialGroup() + .addComponent(pauseButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(progressSlider, javax.swing.GroupLayout.DEFAULT_SIZE, 265, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(progressLabel) + .addContainerGap()))) ); controlPanelLayout.setVerticalGroup( - controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(controlPanelLayout.createSequentialGroup() - .addContainerGap() - .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(progressSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(pauseButton) - .addComponent(progressLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 29, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(infoLabel) - .addContainerGap()) + controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(controlPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(progressSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(pauseButton) + .addComponent(progressLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 29, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(infoLabel) + .addContainerGap()) ); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(controlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(videoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(controlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(videoPanel, 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() - .addComponent(videoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(controlPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(videoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(controlPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) ); }// @@ -557,9 +536,10 @@ public class GstVideoPanel extends MediaViewVideoPanel { return; } } else if (state.equals(State.READY)) { - ExtractMedia em = new ExtractMedia(currentFile, getJFile(currentFile)); - em.execute(); - em.getExtractedBytes(); + final File tempVideoFile = VideoUtils.getTempVideoFile(currentFile); + + new ExtractMedia(currentFile, tempVideoFile).execute(); + } } }//GEN-LAST:event_pauseButtonActionPerformed @@ -572,14 +552,13 @@ public class GstVideoPanel extends MediaViewVideoPanel { private javax.swing.JSlider progressSlider; private javax.swing.JPanel videoPanel; // End of variables declaration//GEN-END:variables - + private class VideoProgressWorker extends SwingWorker { - private String durationFormat = "%02d:%02d:%02d/%02d:%02d:%02d "; //NON-NLS + private final String durationFormat = "%02d:%02d:%02d/%02d:%02d:%02d "; //NON-NLS private long millisElapsed = 0; private final long INTER_FRAME_PERIOD_MS = 20; private final long END_TIME_MARGIN_MS = 50; - private boolean hadError = false; private boolean isPlayBinReady() { synchronized (playbinLock) { @@ -612,9 +591,9 @@ public class GstVideoPanel extends MediaViewVideoPanel { /** * @return true while millisElapsed is greater than END_TIME_MARGIN_MS - * from durationMillis. This is used to indicate when the video has - * ended because for some videos the time elapsed never becomes equal to - * the reported duration of the video. + * from durationMillis. This is used to indicate when the video + * has ended because for some videos the time elapsed never + * becomes equal to the reported duration of the video. */ private boolean hasNotEnded() { return (durationMillis - millisElapsed) > END_TIME_MARGIN_MS; @@ -626,8 +605,7 @@ public class GstVideoPanel extends MediaViewVideoPanel { // enable the slider progressSlider.setEnabled(true); - int elapsedHours = -1, elapsedMinutes = -1, elapsedSeconds = -1; - ClockTime pos = null; + ClockTime pos; while (hasNotEnded() && isPlayBinReady() && !isCancelled()) { synchronized (playbinLock) { @@ -637,11 +615,11 @@ public class GstVideoPanel extends MediaViewVideoPanel { // pick out the elapsed hours, minutes, seconds long secondsElapsed = millisElapsed / 1000; - elapsedHours = (int) secondsElapsed / 3600; + int elapsedHours = (int) secondsElapsed / 3600; secondsElapsed -= elapsedHours * 3600; - elapsedMinutes = (int) secondsElapsed / 60; + int elapsedMinutes = (int) secondsElapsed / 60; secondsElapsed -= elapsedMinutes * 60; - elapsedSeconds = (int) secondsElapsed; + int elapsedSeconds = (int) secondsElapsed; String durationStr = String.format(durationFormat, elapsedHours, elapsedMinutes, elapsedSeconds, @@ -666,8 +644,7 @@ public class GstVideoPanel extends MediaViewVideoPanel { return null; } - - + @Override protected void done() { // see if any exceptions were thrown @@ -676,57 +653,46 @@ public class GstVideoPanel extends MediaViewVideoPanel { } catch (InterruptedException | ExecutionException ex) { logger.log(Level.WARNING, "Error updating video progress: " + ex.getMessage()); //NON-NLS infoLabel.setText(NbBundle.getMessage(this.getClass(), "GstVideoPanel.progress.infoLabel.updateErr", - ex.getMessage())); + ex.getMessage())); + } // catch and ignore if we were cancelled + catch (java.util.concurrent.CancellationException ex) { } - // catch and ignore if we were cancelled - catch (java.util.concurrent.CancellationException ex ) { } } } //end class progress worker - /* Thread that extracts and plays a file */ - private class ExtractMedia extends SwingWorker { + /* + * Thread that extracts and plays a file + */ + private class ExtractMedia extends SwingWorker { private ProgressHandle progress; - boolean success = false; - private AbstractFile sFile; - private java.io.File jFile; - private String duration; - private String position; - private long extractedBytes; + private final AbstractFile sourceFile; + private final java.io.File tempFile; - ExtractMedia(org.sleuthkit.datamodel.AbstractFile sFile, java.io.File jFile) { - this.sFile = sFile; - this.jFile = jFile; - } - - public long getExtractedBytes() { - return extractedBytes; + ExtractMedia(AbstractFile sFile, java.io.File jFile) { + this.sourceFile = sFile; + this.tempFile = jFile; } @Override - protected Object doInBackground() throws Exception { - success = false; - progress = ProgressHandleFactory.createHandle( - NbBundle.getMessage(GstVideoPanel.class, "GstVideoPanel.ExtractMedia.progress.buffering", sFile.getName()), - new Cancellable() { - @Override - public boolean cancel() { - return ExtractMedia.this.cancel(true); + protected Long doInBackground() throws Exception { + if (tempFile.exists() == false || tempFile.length() < sourceFile.getSize()) { + progress = ProgressHandleFactory.createHandle(NbBundle.getMessage(GstVideoPanel.class, "GstVideoPanel.ExtractMedia.progress.buffering", sourceFile.getName()), () -> ExtractMedia.this.cancel(true)); + progressLabel.setText(NbBundle.getMessage(this.getClass(), "GstVideoPanel.progress.buffering")); + progress.start(100); + try { + return ContentUtils.writeToFile(sourceFile, tempFile, progress, this, true); + } catch (IOException ex) { + logger.log(Level.WARNING, "Error buffering file", ex); //NON-NLS + return 0L; } - }); - progressLabel.setText(NbBundle.getMessage(this.getClass(), "GstVideoPanel.progress.buffering")); - progress.start(); - progress.switchToDeterminate(100); - try { - extractedBytes = ContentUtils.writeToFile(sFile, jFile, progress, this, true); - } catch (IOException ex) { - logger.log(Level.WARNING, "Error buffering file", ex); //NON-NLS } - success = true; - return null; + return 0L; } - /* clean up or start the worker threads */ + /* + * clean up or start the worker threads + */ @Override protected void done() { try { @@ -738,7 +704,9 @@ public class GstVideoPanel extends MediaViewVideoPanel { } catch (Exception ex) { logger.log(Level.SEVERE, "Fatal error during media buffering.", ex); //NON-NLS } finally { - progress.finish(); + if (progress != null) { + progress.finish(); + } if (!this.isCancelled()) { playMedia(); } @@ -746,11 +714,11 @@ public class GstVideoPanel extends MediaViewVideoPanel { } void playMedia() { - if (jFile == null || !jFile.exists()) { + if (tempFile == null || !tempFile.exists()) { progressLabel.setText(NbBundle.getMessage(this.getClass(), "GstVideoPanel.progressLabel.bufferingErr")); return; } - ClockTime dur = null; + ClockTime dur; synchronized (playbinLock) { // must play, then pause and get state to get duration. if (gstPlaybin2.play() == StateChangeReturn.FAILURE) { @@ -766,7 +734,6 @@ public class GstVideoPanel extends MediaViewVideoPanel { gstPlaybin2.getState(); dur = gstPlaybin2.queryDuration(); } - duration = dur.toString(); durationMillis = dur.toMillis(); // pick out the total hours, minutes, seconds @@ -777,33 +744,31 @@ public class GstVideoPanel extends MediaViewVideoPanel { durationSeconds -= totalMinutes * 60; totalSeconds = (int) durationSeconds; - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - progressSlider.setMaximum((int) durationMillis); - progressSlider.setMinimum(0); + SwingUtilities.invokeLater(() -> { + progressSlider.setMaximum((int) durationMillis); + progressSlider.setMinimum(0); - synchronized (playbinLock) { - if (gstPlaybin2.play() == StateChangeReturn.FAILURE) { - logger.log(Level.WARNING, "Attempt to call PlayBin2.play() failed."); //NON-NLS - infoLabel.setText(MEDIA_PLAYER_ERROR_STRING); - } + synchronized (playbinLock) { + if (gstPlaybin2.play() == StateChangeReturn.FAILURE) { + logger.log(Level.WARNING, "Attempt to call PlayBin2.play() failed."); //NON-NLS + infoLabel.setText(MEDIA_PLAYER_ERROR_STRING); } - pauseButton.setText("||"); - videoProgressWorker = new VideoProgressWorker(); - videoProgressWorker.execute(); } + pauseButton.setText("||"); + videoProgressWorker = new VideoProgressWorker(); + videoProgressWorker.execute(); }); } } - + @Override public String[] getExtensions() { - return EXTENSIONS; + return EXTENSIONS.clone(); } @Override public List getMimeTypes() { return MIMETYPES; } + } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java index d38e58525e..66a672c16b 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java @@ -66,7 +66,9 @@ public class Installer extends ModuleInstall { UIManager.put(DefaultTabbedContainerUI.KEY_VIEW_CONTENT_BORDER, BorderFactory.createEmptyBorder()); UIManager.put("TabbedPane.contentBorderInsets", new Insets(0, 0, 0, 0)); - /* Open the passed in case, if an aut file was double clicked. */ + /* + * Open the passed in case, if an aut file was double clicked. + */ WindowManager.getDefault().invokeWhenUIReady(new Runnable() { @Override public void run() { @@ -88,7 +90,6 @@ public class Installer extends ModuleInstall { } }); - } @Override @@ -100,50 +101,48 @@ public class Installer extends ModuleInstall { @Override public void close() { try { - if (Case.isCaseOpen()) + if (Case.isCaseOpen()) { Case.getCurrentCase().closeCase(); - } - catch (CaseActionException ex) { + } + } catch (CaseActionException ex) { logger.log(Level.WARNING, "Error closing case. ", ex); //NON-NLS } } - + private void setupLAF() { //TODO apply custom skinning //UIManager.put("nimbusBase", new Color()); //UIManager.put("nimbusBlueGrey", new Color()); //UIManager.put("control", new Color()); - if (System.getProperty("os.name").toLowerCase().contains("mac")) { //NON-NLS setupMacOsXLAF(); } - + } /** - * Set the look and feel to be the Cross Platform 'Metal', but keep Aqua - * dependent elements that set the Menu Bar to be in the correct place on + * Set the look and feel to be the Cross Platform 'Metal', but keep Aqua + * dependent elements that set the Menu Bar to be in the correct place on * Mac OS X. */ private void setupMacOsXLAF() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (ClassNotFoundException | InstantiationException - | IllegalAccessException | UnsupportedLookAndFeelException ex) { + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { logger.log(Level.WARNING, "Unable to set theme. ", ex); //NON-NLS } - + final String[] UI_MENU_ITEM_KEYS = new String[]{"MenuBarUI", //NON-NLS - }; - + }; + Map uiEntries = new TreeMap<>(); - + // Store the keys that deal with menu items - for(String key : UI_MENU_ITEM_KEYS) { + for (String key : UI_MENU_ITEM_KEYS) { uiEntries.put(key, UIManager.get(key)); } - + //use Metal if available for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { if ("Nimbus".equals(info.getName())) { //NON-NLS @@ -158,7 +157,7 @@ public class Installer extends ModuleInstall { } // Overwrite the Metal menu item keys to use the Aqua versions - for (Map.Entry entry : uiEntries.entrySet()) { + for (Map.Entry entry : uiEntries.entrySet()) { UIManager.put(entry.getKey(), entry.getValue()); } } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.css b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.css new file mode 100644 index 0000000000..8cd592b28b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.css @@ -0,0 +1,28 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.label { + -fx-wrap-text:true; + -fx-text-fill: red; + -fx-font-size: 2em; +} + +.bg { + -fx-background-color:black; +} \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java index 584e5babb5..15997146ea 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,41 +21,68 @@ package org.sleuthkit.autopsy.corecomponents; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.image.BufferedImage; +import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.SortedSet; import java.util.logging.Level; +import java.util.stream.Collectors; import javafx.application.Platform; import javafx.embed.swing.JFXPanel; import javafx.embed.swing.SwingFXUtils; import javafx.scene.Scene; +import javafx.scene.control.Label; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.BorderPane; import javax.imageio.ImageIO; +import javax.swing.JPanel; import javax.swing.SwingUtilities; import org.openide.util.NbBundle; +import org.python.google.common.collect.Lists; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.corelibs.ScalrWrapper; +import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.ReadContentInputStream; /** - * Container for the image viewer part of media view, on a layered pane. To be - * used with JavaFx image viewer only. + * Image viewer part of the Media View layered pane. Uses JavaFX to display the + * image. */ - public class MediaViewImagePanel extends javax.swing.JPanel { +public class MediaViewImagePanel extends JPanel implements DataContentViewerMedia.MediaViewPanel { + + private static final Logger LOGGER = Logger.getLogger(MediaViewImagePanel.class.getName()); + + private final boolean fxInited; + private JFXPanel fxPanel; private ImageView fxImageView; - private static final Logger logger = Logger.getLogger(MediaViewImagePanel.class.getName()); - private boolean fxInited = false; - - private final List supportedExtensions; - static private final List supportedMimes = Arrays.asList("image/jpeg", "image/png", "image/gif", "image/bmp", "image/x-ms-bmp"); //NON-NLS + private BorderPane borderpane; + + private final Label errorLabel = new Label("Could not load file into media view."); + private final Label tooLargeLabel = new Label("Could not load file into media view (too large)."); + + static { + ImageIO.scanForPlugins(); + + } + /** + * mime types we should be able to display. if the mimetype is unknown we + * will fall back on extension and jpg/png header + */ + static private final SortedSet supportedMimes = ImageUtils.getSupportedImageMimeTypes(); + + /** + * extensions we should be able to display + */ + static private final List supportedExtensions = ImageUtils.getSupportedImageExtensions().stream() + .map("."::concat) + .collect(Collectors.toList()); /** * Creates new form MediaViewImagePanel @@ -64,74 +91,59 @@ import org.sleuthkit.datamodel.ReadContentInputStream; initComponents(); fxInited = org.sleuthkit.autopsy.core.Installer.isJavaFxInited(); if (fxInited) { - setupFx(); - } - - supportedExtensions = new ArrayList<>(); - //logger.log(Level.INFO, "Supported image formats by javafx image viewer: "); - for (String suffix : ImageIO.getReaderFileSuffixes()) { - //logger.log(Level.INFO, "suffix: " + suffix); - supportedExtensions.add("." + suffix); + Platform.runLater(() -> { + + // build jfx ui (we could do this in FXML?) + fxImageView = new ImageView(); // will hold image + borderpane = new BorderPane(fxImageView); // centers and sizes imageview + borderpane.getStyleClass().add("bg"); + fxPanel = new JFXPanel(); // bridge jfx-swing + Scene scene = new Scene(borderpane); //root of jfx tree + scene.getStylesheets().add(MediaViewImagePanel.class.getResource("MediaViewImagePanel.css").toExternalForm()); + fxPanel.setScene(scene); + + //bind size of image to that of scene, while keeping proportions + fxImageView.fitWidthProperty().bind(scene.widthProperty()); + fxImageView.fitHeightProperty().bind(scene.heightProperty()); + fxImageView.setPreserveRatio(true); + fxImageView.setSmooth(true); + fxImageView.setCache(true); + + EventQueue.invokeLater(() -> { + add(fxPanel);//add jfx ui to JPanel + }); + }); } } - + public boolean isInited() { return fxInited; } /** - * Setup FX components + * clear the displayed image */ - private void setupFx() { - // load the image - Platform.runLater(new Runnable() { - @Override - public void run() { - fxPanel = new JFXPanel(); - fxImageView = new ImageView(); - // resizes the image to have width of 100 while preserving the ratio and using - // higher quality filtering method; this ImageView is also cached to - // improve performance - fxImageView.setPreserveRatio(true); - fxImageView.setSmooth(true); - fxImageView.setCache(true); - - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - add(fxPanel); - - //TODO - // setVisible(true); - } - }); - } - }); - } - public void reset() { - Platform.runLater(new Runnable() { - @Override - public void run() { - fxImageView.setImage(null); - } + Platform.runLater(() -> { + fxImageView.setImage(null); + borderpane.setCenter(null); }); } - + /** - * Show image + * Show the contents of the given AbstractFile as a visual image. * * @param file image file to show - * @param dims dimension of the parent window + * @param dims dimension of the parent window (ignored) */ + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) void showImageFx(final AbstractFile file, final Dimension dims) { if (!fxInited) { return; } - final String fileName = file.getName(); - //hide the panel during loading/transformations + //TODO: repalce this with a progress indicator fxPanel.setVisible(false); // load the image @@ -139,90 +151,78 @@ import org.sleuthkit.datamodel.ReadContentInputStream; @Override public void run() { if (!Case.isCaseOpen()) { - //handle in-between condition when case is being closed - //and an image was previously selected + /* + * handle in-between condition when case is being closed and + * an image was previously selected + */ return; } + try (InputStream inputStream = new BufferedInputStream(new ReadContentInputStream(file));) { - final InputStream inputStream = new ReadContentInputStream(file); - - final Image fxImage; - try { - //original input stream - BufferedImage bi = ImageIO.read(inputStream); - if (bi == null) { - logger.log(Level.WARNING, "Could image reader not found for file: " + fileName); //NON-NLS - return; + BufferedImage bufferedImage = ImageIO.read(inputStream); + if (bufferedImage == null) { + LOGGER.log(Level.WARNING, "Image reader not found for file: {0}", file.getName()); //NON-NLS + borderpane.setCenter(errorLabel); + } else { + Image fxImage = SwingFXUtils.toFXImage(bufferedImage, null); + if (fxImage.isError()) { + LOGGER.log(Level.WARNING, "Could not load image file into media view: " + file.getName(), fxImage.getException()); //NON-NLS + borderpane.setCenter(errorLabel); + return; + } else { + fxImageView.setImage(fxImage); + borderpane.setCenter(fxImageView); + } } - //scale image using Scalr - BufferedImage biScaled = ScalrWrapper.resizeHighQuality(bi, (int) dims.getWidth(), (int) dims.getHeight()); - //convert from awt imageto fx image - fxImage = SwingFXUtils.toFXImage(biScaled, null); - } catch (IOException ex) { - logger.log(Level.WARNING, "Could not load image file into media view: " + fileName, ex); //NON-NLS - return; - } catch (OutOfMemoryError ex) { - logger.log(Level.WARNING, "Could not load image file into media view (too large): " + fileName, ex); //NON-NLS + } catch (IllegalArgumentException | IOException ex) { + LOGGER.log(Level.WARNING, "Could not load image file into media view: " + file.getName(), ex); //NON-NLS + borderpane.setCenter(errorLabel); + } catch (OutOfMemoryError ex) { // this might be redundant since we are not attempting to rescale the image anymore + LOGGER.log(Level.WARNING, "Could not load image file into media view (too large): " + file.getName(), ex); //NON-NLS MessageNotifyUtil.Notify.warn( NbBundle.getMessage(this.getClass(), "MediaViewImagePanel.imgFileTooLarge.msg", file.getName()), ex.getMessage()); - return; - } finally { - try { - inputStream.close(); - } catch (IOException ex) { - logger.log(Level.WARNING, "Could not close input stream after loading image in media view: " + fileName, ex); //NON-NLS - } + borderpane.setCenter(tooLargeLabel); } - if (fxImage == null || fxImage.isError()) { - logger.log(Level.WARNING, "Could not load image file into media view: " + fileName); //NON-NLS - return; - } - - //use border pane to center the image in the scene - BorderPane borderpane = new BorderPane(); - borderpane.setCenter(fxImageView); - - fxImageView.setImage(fxImage); - fxImageView.setFitWidth(dims.getWidth()); - fxImageView.setFitHeight(dims.getHeight()); - - //Group fxRoot = new Group(); - - //Scene fxScene = new Scene(fxRoot, dims.getWidth(), dims.getHeight(), javafx.scene.paint.Color.BLACK); - Scene fxScene = new Scene(borderpane, javafx.scene.paint.Color.BLACK); - // borderpane.getChildren().add(fxImageView); - - fxPanel.setScene(fxScene); - - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - //show the panel after fully loaded - fxPanel.setVisible(true); - } + SwingUtilities.invokeLater(() -> { + //show the panel after fully loaded + fxPanel.setVisible(true); }); - } }); + } - } - /** - * returns supported mime types - * @return + * @return supported mime types */ + @Override public List getMimeTypes() { - return supportedMimes; + return Collections.unmodifiableList(Lists.newArrayList(supportedMimes)); } - + /** * returns supported extensions (each starting with .) - * @return + * + * @return + */ + @Override + public List getExtensionsList() { + return getExtensions(); + } + + /** + * returns supported extensions (each starting with .) + * + * @return */ public List getExtensions() { - return supportedExtensions; + return Collections.unmodifiableList(supportedExtensions); + } + + @Override + public boolean isSupported(AbstractFile file) { + return ImageUtils.isImageThumbnailSupported(file); } /** @@ -239,4 +239,5 @@ import org.sleuthkit.datamodel.ReadContentInputStream; }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables -} \ No newline at end of file + +} diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewVideoPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewVideoPanel.java index 05351a2959..7ceb31f697 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewVideoPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewVideoPanel.java @@ -21,30 +21,38 @@ package org.sleuthkit.autopsy.corecomponents; import java.awt.Dimension; import java.util.Arrays; import java.util.List; +import static java.util.Objects.nonNull; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import java.util.logging.Level; -import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.JPanel; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.TskCoreException; /** - * Video viewer part of the Media View layered pane. - * Uses different engines depending on platform. + * Video viewer part of the Media View layered pane. Uses different engines + * depending on platform. */ -public abstract class MediaViewVideoPanel extends JPanel implements FrameCapture { - +public abstract class MediaViewVideoPanel extends JPanel implements FrameCapture, DataContentViewerMedia.MediaViewPanel { + + private static final Set AUDIO_EXTENSIONS = new TreeSet<>(Arrays.asList(".mp3", ".wav", ".wma")); //NON-NLS + private static final Logger logger = Logger.getLogger(MediaViewVideoPanel.class.getName()); - + // 64 bit architectures private static final String[] ARCH64 = new String[]{"amd64", "x86_64"}; //NON-NLS NON-NLS - + // 32 bit architectures private static final String[] ARCH32 = new String[]{"x86"}; //NON-NLS - + /** - * Factory Method to create a MediaViewVideoPanel. - * + * Factory Method to create a MediaViewVideoPanel. + * * Implementation is dependent on the architecture of the JVM. - * + * * @return a MediaViewVideoPanel instance. */ public static MediaViewVideoPanel createVideoPanel() { @@ -56,10 +64,10 @@ public abstract class MediaViewVideoPanel extends JPanel implements FrameCapture return getGstImpl(); } } - + /** * Is the JVM architecture 64 bit? - * + * * @return */ private static boolean is64BitJVM() { @@ -69,34 +77,34 @@ public abstract class MediaViewVideoPanel extends JPanel implements FrameCapture /** * Get a GStreamer video player implementation. - * + * * @return a GstVideoPanel */ private static MediaViewVideoPanel getGstImpl() { return new GstVideoPanel(); } - /** + /** * Get a JavaFX video player implementation. - * + * * @return a FXVideoPanel */ private static MediaViewVideoPanel getFXImpl() { return new FXVideoPanel(); } - + /** * Has this MediaViewVideoPanel been initialized correctly? - * - * @return + * + * @return */ public abstract boolean isInited(); - + /** * Prepare this MediaViewVideoPanel to accept a different media file. */ abstract void reset(); - + /** * Initialize all the necessary vars to play a video/audio file. * @@ -104,13 +112,45 @@ public abstract class MediaViewVideoPanel extends JPanel implements FrameCapture * @param dims dimension of the parent window */ abstract void setupVideo(final AbstractFile file, final Dimension dims); - + /** * Return the extensions supported by this video panel. + * + * @return */ abstract public String[] getExtensions(); + /** * Return the MimeTypes supported by this video panel. */ + @Override abstract public List getMimeTypes(); + + @Override + public List getExtensionsList() { + return Arrays.asList(getExtensions()); + } + + @Override + public boolean isSupported(AbstractFile file) { + String extension = file.getNameExtension(); + //TODO: is this what we want, to require both extension and mimetype support? + if (AUDIO_EXTENSIONS.contains("." + extension) || getExtensionsList().contains("." + extension)) { + SortedSet mimeTypes = new TreeSet<>(getMimeTypes()); + try { + String mimeType = new FileTypeDetector().getFileType(file); + if (nonNull(mimeType)) { + return mimeTypes.contains(mimeType); + } + } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { + logger.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex); + if (!mimeTypes.isEmpty() && file.isMimeType(mimeTypes) == AbstractFile.MimeMatchEnum.TRUE) { + return true; + } + } + + return getExtensionsList().contains("." + extension); + } + return false; + } } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/NoTabsTabDisplayerUI.java b/Core/src/org/sleuthkit/autopsy/corecomponents/NoTabsTabDisplayerUI.java index 1db15285d8..0cb5d58f32 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/NoTabsTabDisplayerUI.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/NoTabsTabDisplayerUI.java @@ -34,71 +34,74 @@ import org.netbeans.swing.tabcontrol.TabDisplayerUI; * @author dfickling */ public class NoTabsTabDisplayerUI extends TabDisplayerUI { - - /** Creates a new instance of NoTabsTabDisplayerUI */ + + /** + * Creates a new instance of NoTabsTabDisplayerUI + */ public NoTabsTabDisplayerUI(TabDisplayer displayer) { super(displayer); } - + public static ComponentUI createUI(JComponent jc) { assert jc instanceof TabDisplayer; return new NoTabsTabDisplayerUI((TabDisplayer) jc); } - - private static final int[] PTS = new int[] { 0, 0, 0 }; + + private static final int[] PTS = new int[]{0, 0, 0}; + public Polygon getExactTabIndication(int i) { //Should never be called return new Polygon(PTS, PTS, PTS.length); } - + public Polygon getInsertTabIndication(int i) { return new Polygon(PTS, PTS, PTS.length); } - + public int tabForCoordinate(Point point) { return -1; } - + public Rectangle getTabRect(int i, Rectangle rectangle) { - return new Rectangle(0,0,0,0); + return new Rectangle(0, 0, 0, 0); } - + protected SingleSelectionModel createSelectionModel() { return new DefaultSingleSelectionModel(); } - + public java.lang.String getCommandAtPoint(Point point) { return null; } - + public int dropIndexOfPoint(Point point) { return -1; } - + public void registerShortcuts(javax.swing.JComponent jComponent) { //do nothing } - + public void unregisterShortcuts(javax.swing.JComponent jComponent) { //do nothing } - + protected void requestAttention(int i) { //do nothing } - + protected void cancelRequestAttention(int i) { //do nothing } - + public Dimension getPreferredSize(javax.swing.JComponent c) { return new Dimension(0, 0); } - + public Dimension getMinimumSize(javax.swing.JComponent c) { return new Dimension(0, 0); } - + public Dimension getMaximumSize(javax.swing.JComponent c) { return new Dimension(0, 0); } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/OfflineHelpAction.java b/Core/src/org/sleuthkit/autopsy/corecomponents/OfflineHelpAction.java index f2e755553a..2ab921907f 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/OfflineHelpAction.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/OfflineHelpAction.java @@ -53,8 +53,8 @@ import java.util.logging.Logger; public final class OfflineHelpAction implements ActionListener { private URI uri; - private static final Logger Logger = - org.sleuthkit.autopsy.coreutils.Logger.getLogger(AboutWindowPanel.class.getName()); + private static final Logger Logger + = org.sleuthkit.autopsy.coreutils.Logger.getLogger(AboutWindowPanel.class.getName()); @Override public void actionPerformed(ActionEvent e) { @@ -65,8 +65,7 @@ public final class OfflineHelpAction implements ActionListener { * Displays the Offline Documentation in the system browser. If not * available, displays it in the built-in OpenIDE HTML Browser. * - * Tested and working: Chrome, Firefox, IE - * Not tested: Opera, Safari + * Tested and working: Chrome, Firefox, IE Not tested: Opera, Safari */ private void viewOfflineHelp() { String fileForHelp = ""; diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/OptionsPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/OptionsPanel.java index 95ed4c5025..2f21942f52 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/OptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/OptionsPanel.java @@ -8,16 +8,16 @@ package org.sleuthkit.autopsy.corecomponents; * */ public interface OptionsPanel { - + /** * Store the current state of all options in this OptionsPanel. */ public void store(); - + /** - * Load the saved state of all options, and refresh this - * OptionsPanel accordingly. + * Load the saved state of all options, and refresh this OptionsPanel + * accordingly. */ public void load(); - + } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/TableFilterChildren.java b/Core/src/org/sleuthkit/autopsy/corecomponents/TableFilterChildren.java index dcc3a78846..bcb1657314 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/TableFilterChildren.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/TableFilterChildren.java @@ -27,7 +27,9 @@ import org.openide.nodes.Node; */ class TableFilterChildren extends FilterNode.Children { - /** the constructor */ + /** + * the constructor + */ TableFilterChildren(Node arg) { super(arg); } @@ -47,6 +49,7 @@ class TableFilterChildren extends FilterNode.Children { * Converts the given FsContent into "Children". * * @param fs + * * @return children */ public static Children createInstance(Node arg, boolean createChild) { @@ -56,4 +59,4 @@ class TableFilterChildren extends FilterNode.Children { return Children.LEAF; } } -} \ No newline at end of file +} diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/TableFilterNode.java b/Core/src/org/sleuthkit/autopsy/corecomponents/TableFilterNode.java index 4715658265..59a1bd343a 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/TableFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/TableFilterNode.java @@ -23,8 +23,9 @@ import org.openide.nodes.Node; import org.openide.util.NbBundle; /** - * This class is used to filter the nodes that we want to show on the "TreeTableView". - * So basically we just want to show one layer of nodes from it's parent. + * This class is used to filter the nodes that we want to show on the + * "TreeTableView". So basically we just want to show one layer of nodes from + * it's parent. * * @author jantonius */ @@ -32,7 +33,9 @@ public class TableFilterNode extends FilterNode { private boolean createChild; - /** the constructor */ + /** + * the constructor + */ public TableFilterNode(Node arg, boolean crChild) { super(arg, TableFilterChildren.createInstance(arg, crChild)); this.createChild = crChild; @@ -42,7 +45,7 @@ public class TableFilterNode extends FilterNode { * Override the display name / header for the first (tree) column on the * "TreeTableView". * - * @return disName the display name for the first column + * @return disName the display name for the first column */ @Override public String getDisplayName() { diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewChildren.java b/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewChildren.java index 8487310b67..e7a39f62ce 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewChildren.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewChildren.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -43,7 +43,7 @@ class ThumbnailViewChildren extends Children.Keys { static final int IMAGES_PER_PAGE = 200; private Node parent; - private final HashMap> pages = new HashMap>(); + private final HashMap> pages = new HashMap<>(); private int totalImages = 0; private int totalPages = 0; private int iconSize = ImageUtils.ICON_SIZE_MEDIUM; @@ -57,13 +57,8 @@ class ThumbnailViewChildren extends Children.Keys { this.parent = arg; this.iconSize = iconSize; - // } - // @Override -// protected Node copyNode(Node arg0) { - // return new ThumbnailViewNode(arg0); -// } @Override protected void addNotify() { super.addNotify(); @@ -85,7 +80,7 @@ class ThumbnailViewChildren extends Children.Keys { //TODO when lazy loading of original nodes is fixed //we should be asking the datamodel for the children instead //and not counting the children nodes (which might not be preloaded at this point) - final List suppContent = new ArrayList(); + final List suppContent = new ArrayList<>(); for (Node child : parent.getChildren().getNodes()) { if (isSupported(child)) { ++totalImages; @@ -122,8 +117,6 @@ class ThumbnailViewChildren extends Children.Keys { pageNums[i] = i + 1; } setKeys(pageNums); - - } @Override diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewNode.java b/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewNode.java index 4cdc1f128a..de26a7977f 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewNode.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewNode.java @@ -19,9 +19,17 @@ package org.sleuthkit.autopsy.corecomponents; import java.awt.Image; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; import java.lang.ref.SoftReference; +import java.util.concurrent.ExecutionException; +import javax.swing.SwingWorker; +import javax.swing.Timer; +import org.netbeans.api.progress.ProgressHandle; +import org.netbeans.api.progress.ProgressHandleFactory; import org.openide.nodes.FilterNode; import org.openide.nodes.Node; +import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.datamodel.Content; @@ -31,9 +39,13 @@ import org.sleuthkit.datamodel.Content; */ class ThumbnailViewNode extends FilterNode { + static private final Image waitingIcon = Toolkit.getDefaultToolkit().createImage(ThumbnailViewNode.class.getResource("/org/sleuthkit/autopsy/images/working_spinner.gif")); + private SoftReference iconCache = null; private int iconSize = ImageUtils.ICON_SIZE_MEDIUM; - //private final BufferedImage defaultIconBI; + + private SwingWorker swingWorker; + private Timer timer; /** * the constructor @@ -55,29 +67,60 @@ class ThumbnailViewNode extends FilterNode { @Override public Image getIcon(int type) { Image icon = null; - + if (iconCache != null) { icon = iconCache.get(); } - if (icon == null) { - Content content = this.getLookup().lookup(Content.class); - - if (content != null) { - icon = ImageUtils.getIcon(content, iconSize); - } else { - icon = ImageUtils.getDefaultIcon(); + if (icon != null) { + return icon; + } else { + final Content content = this.getLookup().lookup(Content.class); + if (content == null) { + return ImageUtils.getDefaultThumbnail(); } + if (swingWorker == null || swingWorker.isDone()) { + swingWorker = new SwingWorker() { + final private ProgressHandle progressHandle = ProgressHandleFactory.createHandle("generating thumbnail for video file " + content.getName()); - iconCache = new SoftReference<>(icon); + @Override + protected Image doInBackground() throws Exception { + progressHandle.start(); + return ImageUtils.getThumbnail(content, iconSize); + } + + @Override + protected void done() { + super.done(); + try { + iconCache = new SoftReference<>(super.get()); + progressHandle.finish(); + fireIconChange(); + if (timer != null) { + timer.stop(); + timer = null; + } + } catch (InterruptedException | ExecutionException ex) { + Exceptions.printStackTrace(ex); + } + swingWorker = null; + } + }; + swingWorker.execute(); + } + if (timer == null) { + timer = new Timer(100, (ActionEvent e) -> { + fireIconChange(); + }); + timer.start(); + } + return waitingIcon; } - - return icon; } - + public void setIconSize(int iconSize) { this.iconSize = iconSize; iconCache = null; + swingWorker = null; } - } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/VideoFrame.java b/Core/src/org/sleuthkit/autopsy/corecomponents/VideoFrame.java index 95ce2c6d29..9d2ee91b7b 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/VideoFrame.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/VideoFrame.java @@ -9,7 +9,7 @@ public class VideoFrame { private Image frame; private long timeMillis; - + public VideoFrame(Image frame, long timeMillis) { this.frame = frame; this.timeMillis = timeMillis; diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/AutopsyExceptionHandler.java b/Core/src/org/sleuthkit/autopsy/coreutils/AutopsyExceptionHandler.java index e31768bd80..405cf3705d 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/AutopsyExceptionHandler.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/AutopsyExceptionHandler.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.coreutils; import java.awt.Component; @@ -42,20 +41,19 @@ public class AutopsyExceptionHandler extends Handler { static final Handler nbErrorManager = new NbErrorManager(); // Default NetBeans handler static final Version.Type buildType = Version.getBuildType(); private final Logger logger = Logger.getLogger(AutopsyExceptionHandler.class.getName()); - + public AutopsyExceptionHandler() { super(); - + this.setLevel(Level.SEVERE); /* - if (buildType == Version.Type.DEVELOPMENT) - //for dev builds, show dialogs for WARNING and above - this.setLevel(Level.WARNING); - else - //for production builds, show dialogs for SEVERE and above (TODO in future consider not show any, explicit dialogs should be in place) - this.setLevel(Level.SEVERE); - */ - + * if (buildType == Version.Type.DEVELOPMENT) //for dev builds, show + * dialogs for WARNING and above this.setLevel(Level.WARNING); else + * //for production builds, show dialogs for SEVERE and above (TODO in + * future consider not show any, explicit dialogs should be in place) + * this.setLevel(Level.SEVERE); + */ + this.setFilter(new ExceptionFilter()); this.setFormatter(new SimpleFormatter()); } @@ -69,7 +67,7 @@ public class AutopsyExceptionHandler extends Handler { // Throwable was anticipated, caught and logged. Display log message and throwable message. final int levelValue = record.getLevel().intValue(); - + final Component parentComponent = null; // Use default window frame. final String message = formatExplanation(record); final String title = getTitleForLevelValue(levelValue); @@ -78,19 +76,19 @@ public class AutopsyExceptionHandler extends Handler { // publish() was probably not called from the EDT, so run the message box there instead of here. //only show the dialog in dev builds if (buildType == Version.Type.DEVELOPMENT) { - SwingUtilities.invokeLater(new Runnable() { + SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - JOptionPane.showMessageDialog( - parentComponent, - message, - title, - messageType); - } - }); + @Override + public void run() { + JOptionPane.showMessageDialog( + parentComponent, + message, + title, + messageType); + } + }); } - logger.log(Level.SEVERE, "Unexpected error: " + title + ", " + message ); //NON-NLS + logger.log(Level.SEVERE, "Unexpected error: " + title + ", " + message); //NON-NLS } else { // Throwable (unanticipated) error. Use built-in exception handler to offer details, stacktrace. nbErrorManager.publish(record); @@ -98,11 +96,11 @@ public class AutopsyExceptionHandler extends Handler { } } - /** * Filter only accepts records with exceptions attached. */ private static class ExceptionFilter implements Filter { + @Override public boolean isLoggable(LogRecord record) { // True if there is an uncaught exception being thrown. @@ -112,8 +110,11 @@ public class AutopsyExceptionHandler extends Handler { /** * - * @param record A LogRecord with both a message and associated Throwable set. - * @return A String containing the log message and the cause of the Throwable (if there is one). + * @param record A LogRecord with both a message and associated Throwable + * set. + * + * @return A String containing the log message and the cause of the + * Throwable (if there is one). */ private String formatExplanation(LogRecord record) { final String logMessage = getFormatter().formatMessage(record); @@ -136,7 +137,6 @@ public class AutopsyExceptionHandler extends Handler { // return explanation + recursiveExplanation(cause); // } // } - private static int getMessageTypeForLevelValue(int levelValue) { if (levelValue >= SEVERE_VALUE) { return JOptionPane.ERROR_MESSAGE; diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java b/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java index 10cb36ac33..a8da5147c7 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java @@ -29,9 +29,11 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.ContextMenuActionsProvider; * This class implements the ContextMenuActionsProvider extension point. */ public class ContextMenuExtensionPoint { + /** - * Gets all of the Actions provided by registered implementers of the + * Gets all of the Actions provided by registered implementers of the * ContextMenuActionsProvider interface. + * * @return A list, possibly empty, of Action objects. */ static public List getActions() { diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ErrorInfo.java b/Core/src/org/sleuthkit/autopsy/coreutils/ErrorInfo.java index e7da64bcf4..d56e20e405 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ErrorInfo.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ErrorInfo.java @@ -22,6 +22,7 @@ package org.sleuthkit.autopsy.coreutils; * Encapsulates an error message and an associated exception, if any. */ final public class ErrorInfo { + private final String errorSource; private final String message; private final Exception exception; @@ -41,7 +42,7 @@ final public class ErrorInfo { public String getErrroSource() { return this.errorSource; } - + public String getMessage() { return this.message; } @@ -49,7 +50,7 @@ final public class ErrorInfo { public boolean hasException() { return exception != null; } - + public Exception getException() { return this.exception; } diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/EscapeUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/EscapeUtil.java index f66b5eb333..a95f74a10f 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/EscapeUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/EscapeUtil.java @@ -35,6 +35,7 @@ public class EscapeUtil { * Decode the given url in UTF-8. * * @param url the url to be decoded + * * @return the decoded URL */ public static String decodeURL(String url) { @@ -51,6 +52,7 @@ public class EscapeUtil { * Encode the given url in UTF-8 to * * @param url the url to be decoded + * * @return the encoded URL string */ public static String encodeURL(String url) { @@ -62,19 +64,23 @@ public class EscapeUtil { return ""; } } - + /** - * Escape html + * Escape html + * * @param toEscape text (with html tags) to escape + * * @return html-escaped string */ public static String escapeHtml(String toEscape) { return StringEscapeUtils.escapeHtml4(toEscape); } - + /** * Unescape html + * * @param toUnescape text (potentially escaped html) to unescape + * * @return html unescaped string */ public static String unEscapeHtml(String toUnescape) { diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ExecUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/ExecUtil.java index 7e2659fca4..e63dd38fb8 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ExecUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ExecUtil.java @@ -61,12 +61,12 @@ public final class ExecUtil { public static class TimedProcessTerminator implements ProcessTerminator { private final long startTimeInSeconds; - private final long maxRunTimeInSeconds; + private final long maxRunTimeInSeconds; /** * Creates a process terminator that can be used to kill a process after * it has run for a given period of time. - * + * * @param maxRunTimeInSeconds The maximum allowable run time in seconds. */ public TimedProcessTerminator(long maxRunTimeInSeconds) { @@ -88,11 +88,13 @@ public final class ExecUtil { * Runs a process without a timeout and terminator. * * @param processBuilder A process builder used to configure and construct - * the process to be run. + * the process to be run. + * * @return the exit value of the process + * * @throws SecurityException if a security manager exists and vetoes any - * aspect of running the process. - * @throws IOException if an I/O error occurs. + * aspect of running the process. + * @throws IOException if an I/O error occurs. */ public static int execute(ProcessBuilder processBuilder) throws SecurityException, IOException { return ExecUtil.execute(processBuilder, 30, TimeUnit.DAYS, new ProcessTerminator() { @@ -110,12 +112,14 @@ public final class ExecUtil { * Runs a process using the default timeout and a custom terminator. * * @param processBuilder A process builder used to configure and construct - * the process to be run. - * @param terminator The terminator. + * the process to be run. + * @param terminator The terminator. + * * @return the exit value of the process + * * @throws SecurityException if a security manager exists and vetoes any - * aspect of running the process. - * @throws IOException if an I/O error occurs. + * aspect of running the process. + * @throws IOException if an I/O error occurs. */ public static int execute(ProcessBuilder processBuilder, ProcessTerminator terminator) throws SecurityException, IOException { return ExecUtil.execute(processBuilder, ExecUtil.DEFAULT_TIMEOUT, ExecUtil.DEFAULT_TIMEOUT_UNITS, terminator); @@ -125,14 +129,16 @@ public final class ExecUtil { * Runs a process using a custom terminator. * * @param processBuilder A process builder used to configure and construct - * the process to be run. - * @param timeOut The duration of the timeout. - * @param units The units for the timeout. - * @param terminator The terminator. + * the process to be run. + * @param timeOut The duration of the timeout. + * @param units The units for the timeout. + * @param terminator The terminator. + * * @return the exit value of the process + * * @throws SecurityException if a security manager exists and vetoes any - * aspect of running the process. - * @throws IOException if an I/o error occurs. + * aspect of running the process. + * @throws IOException if an I/o error occurs. */ public static int execute(ProcessBuilder processBuilder, long timeOut, TimeUnit units, ProcessTerminator terminator) throws SecurityException, IOException { Process process = processBuilder.start(); @@ -196,7 +202,8 @@ public final class ExecUtil { * variant with Writer. * * @param aCommand command to be executed - * @param params parameters of the command + * @param params parameters of the command + * * @return string buffer with captured stdout */ @Deprecated @@ -241,8 +248,9 @@ public final class ExecUtil { * and stderr to nowhere. * * @param stdoutWriter file writer to write stdout to - * @param aCommand command to be executed - * @param params parameters of the command + * @param aCommand command to be executed + * @param params parameters of the command + * * @return string buffer with captured stdout */ @Deprecated @@ -316,7 +324,7 @@ public final class ExecUtil { * Gets the exit value returned by the subprocess used to execute a command. * * @return The exit value or the distinguished value -100 if this method is - * called before the exit value is set. + * called before the exit value is set. */ @Deprecated synchronized public int getExitValue() { diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/FileUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/FileUtil.java index dfc5bea3ba..5540fd8ef4 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/FileUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/FileUtil.java @@ -26,23 +26,26 @@ import org.openide.filesystems.FileObject; /** * File and dir utilities */ - public class FileUtil { +public class FileUtil { private static final Logger logger = Logger.getLogger(FileUtil.class.getName()); /** * Recursively delete all of the files and sub-directories in a directory. - * Use deleteFileDir() if you are not sure if the path is a file or directory. + * Use deleteFileDir() if you are not sure if the path is a file or + * directory. * * @param dirPath Path of the directory to delete - * @return true if the dir was deleted with no errors. False otherwise (including if the passed in path was for a file). + * + * @return true if the dir was deleted with no errors. False otherwise + * (including if the passed in path was for a file). */ public static boolean deleteDir(File dirPath) { if (dirPath.isDirectory() == false || dirPath.exists() == false) { logger.log(Level.WARNING, "deleteDir passed in a non-directory: {0}", dirPath.getPath()); //NON-NLS return false; } - + File[] files = dirPath.listFiles(); boolean hadErrors = false; if (files != null) { @@ -64,16 +67,18 @@ import org.openide.filesystems.FileObject; logger.log(Level.WARNING, "Failed to delete the empty directory at {0}", dirPath.getPath()); //NON-NLS hadErrors = true; } - + return hadErrors; } /** - * Delete the file or dir at the given path. If the path is for a directory, + * Delete the file or dir at the given path. If the path is for a directory, * recursively delete its contents. * * @param path the path to the file or directory to delete - * @return true if the file or directory were deleted with no errors. False otherwise. + * + * @return true if the file or directory were deleted with no errors. False + * otherwise. */ public static boolean deleteFileDir(File path) { boolean sucess = true; @@ -89,21 +94,24 @@ import org.openide.filesystems.FileObject; } /** - * Copy a file to a new directory, potentially new file name, and overwrite old one if requested - * - * @param source source file path + * Copy a file to a new directory, potentially new file name, and overwrite + * old one if requested + * + * @param source source file path * @param destFolder destination folder path - * @param newName file name of the copied file, which can be different from original - * @param ext file extension, e.g. ".java" - * @param overwrite if new file, already exists, overwrite it (delete it first) + * @param newName file name of the copied file, which can be different + * from original + * @param ext file extension, e.g. ".java" + * @param overwrite if new file, already exists, overwrite it (delete it + * first) * * @return path to the created file, or null if file was not created + * * @throws IOException exception thrown if file copying failed */ public static String copyFile(String source, String destFolder, String newName, String ext, boolean overwrite) throws IOException { - final String destFileName = destFolder + File.separator + newName + ext; final File destFile = new File(destFileName); if (destFile.exists()) { @@ -114,7 +122,6 @@ import org.openide.filesystems.FileObject; } } - final FileObject sourceFileObj = org.openide.filesystems.FileUtil.createData(new File(source)); final FileObject destFolderObj = org.openide.filesystems.FileUtil.createData(new File(destFolder)); @@ -124,37 +131,40 @@ import org.openide.filesystems.FileObject; return created.getPath(); } - + /** * Copy a folder into a new directory. - * - * @param source path to the source folder - * @param path destination path of the new folder + * + * @param source path to the source folder + * @param path destination path of the new folder * @param folderName name of the new folder - * + * * @return path to the new folder if created, null if it was not created + * * @throws IOException exception thrown if file copying failed */ public static String copyFolder(String source, String path, String folderName) throws IOException { String destFolder = path + File.separator + folderName; org.openide.filesystems.FileUtil.createFolder(new File(destFolder)); - + final FileObject sourceFileObj = org.openide.filesystems.FileUtil.createData(new File(source)); final FileObject destFolderObj = org.openide.filesystems.FileUtil.createData(new File(destFolder)); FileObject created = org.openide.filesystems.FileUtil.copyFile(sourceFileObj, destFolderObj, sourceFileObj.getName(), sourceFileObj.getExt()); - + return created.getPath(); } - + /** * Escape special characters in a file name or a file name component + * * @param fileName to escape + * * @return escaped string */ - public static String escapeFileName(String fileName) { + public static String escapeFileName(String fileName) { //for now escaping / (not valid in file name, at least on Windows) //with underscores. Windows/Java seem to ignore \\/ and \\\\/ escapings - return fileName.replaceAll("/", "_"); + return fileName.replaceAll("/", "_"); } } diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/History.java b/Core/src/org/sleuthkit/autopsy/coreutils/History.java index 17fb8733b4..50abf7e5cf 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/History.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/History.java @@ -91,6 +91,12 @@ public class History { canRetreat.bind(historyStack.emptyProperty().not()); } + synchronized public void reset(T newState) { + forwardStack.clear(); + historyStack.clear(); + currentState.set(newState); + } + /** * advance through the forward states by one, and put the current state in * the history. Is a no-op if there are no forward states. diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index f8ad010859..26fffc6319 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -2,7 +2,7 @@ * * Autopsy Forensic Browser * - * Copyright 2012 Basis Technology Corp. + * Copyright 2012-15 Basis Technology Corp. * * Copyright 2012 42six Solutions. * Contact: aebadirad 42six com @@ -22,157 +22,376 @@ */ package org.sleuthkit.autopsy.coreutils; +import com.google.common.io.Files; import java.awt.Image; import java.awt.image.BufferedImage; +import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; +import java.nio.file.Paths; import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Objects; +import static java.util.Objects.isNull; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; import java.util.logging.Level; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import javax.imageio.ImageIO; -import javax.swing.ImageIcon; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; +import org.opencv.core.Core; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corelibs.ScalrWrapper; +import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; +import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector.FileTypeDetectorInitException; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.TskCoreException; /** - * Utilities for creating and manipulating thumbnail and icon images. - * @author jwallace + * + * Utilities for working with Images and creating thumbnails. Reuses thumbnails + * by storing them in the case's cache directory. */ public class ImageUtils { + + private static final Logger LOGGER = Logger.getLogger(ImageUtils.class.getName()); + + /** + * save thumbnails to disk as this format + */ + private static final String FORMAT = "png"; //NON-NLS + public static final int ICON_SIZE_SMALL = 50; public static final int ICON_SIZE_MEDIUM = 100; public static final int ICON_SIZE_LARGE = 200; - private static final Logger logger = Logger.getLogger(ImageUtils.class.getName()); - private static final Image DEFAULT_ICON = new ImageIcon("/org/sleuthkit/autopsy/images/file-icon.png").getImage(); //NON-NLS - private static final List SUPP_EXTENSIONS = Arrays.asList(ImageIO.getReaderFileSuffixes()); - private static final List SUPP_MIME_TYPES = new ArrayList<>(Arrays.asList(ImageIO.getReaderMIMETypes())); + + private static final Logger logger = LOGGER; + private static final BufferedImage DEFAULT_THUMBNAIL; + + private static final List SUPPORTED_IMAGE_EXTENSIONS; + private static final TreeSet SUPPORTED_IMAGE_MIME_TYPES; + private static final List CONDITIONAL_MIME_TYPES = Arrays.asList("audio/x-aiff", "application/octet-stream"); + + private static final boolean openCVLoaded; + static { - SUPP_MIME_TYPES.add("image/x-ms-bmp"); + ImageIO.scanForPlugins(); + BufferedImage tempImage; + try { + tempImage = ImageIO.read(ImageUtils.class.getResourceAsStream("/org/sleuthkit/autopsy/images/file-icon.png"));//NON-NLS + } catch (IOException ex) { + LOGGER.log(Level.SEVERE, "Failed to load default icon.", ex); + tempImage = null; + } + DEFAULT_THUMBNAIL = tempImage; + + //load opencv libraries + boolean openCVLoadedTemp; + try { + System.loadLibrary(Core.NATIVE_LIBRARY_NAME); + if (System.getProperty("os.arch").equals("amd64") || System.getProperty("os.arch").equals("x86_64")) { + System.loadLibrary("opencv_ffmpeg248_64"); + } else { + System.loadLibrary("opencv_ffmpeg248"); + } + + openCVLoadedTemp = true; + } catch (UnsatisfiedLinkError e) { + openCVLoadedTemp = false; + LOGGER.log(Level.SEVERE, "OpenCV Native code library failed to load", e); + //TODO: show warning bubble + + } + + openCVLoaded = openCVLoadedTemp; + SUPPORTED_IMAGE_EXTENSIONS = Arrays.asList(ImageIO.getReaderFileSuffixes()); + + SUPPORTED_IMAGE_MIME_TYPES = new TreeSet<>(Arrays.asList(ImageIO.getReaderMIMETypes())); + /* + * special cases and variants that we support, but don't get registered + * with ImageIO automatically + */ + SUPPORTED_IMAGE_MIME_TYPES.addAll(Arrays.asList( + "image/x-rgb", + "image/x-ms-bmp", + "image/x-portable-graymap", + "image/x-portable-bitmap", + "application/x-123")); + SUPPORTED_IMAGE_MIME_TYPES.removeIf("application/octet-stream"::equals); } - + /** - * Get the default Icon, which is the icon for a file. - * @return + * initialized lazily */ - public static Image getDefaultIcon() { - return DEFAULT_ICON; + private static FileTypeDetector fileTypeDetector; + + /** + * thread that saves generated thumbnails to disk in the background + */ + private static final Executor imageSaver + = Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder() + .namingPattern("icon saver-%d").build()); + + private ImageUtils() { } - + + public static List getSupportedImageExtensions() { + return Collections.unmodifiableList(SUPPORTED_IMAGE_EXTENSIONS); + } + + public static SortedSet getSupportedImageMimeTypes() { + return Collections.unmodifiableSortedSet(SUPPORTED_IMAGE_MIME_TYPES); + } + + /** + * Get the default thumbnail, which is the icon for a file. Used when we can + * not generate content based thumbnail. + * + * @return + * + * @deprecated use {@link #getDefaultThumbnail() } instead. + */ + @Deprecated + public static Image getDefaultIcon() { + return getDefaultThumbnail(); + } + + /** + * Get the default thumbnail, which is the icon for a file. Used when we can + * not generate content based thumbnail. + * + * @return the default thumbnail + */ + public static Image getDefaultThumbnail() { + return DEFAULT_THUMBNAIL; + } + /** * Can a thumbnail be generated for the content? - * + * * @param content - * @return + * + * @return + * */ public static boolean thumbnailSupported(Content content) { - if (content instanceof AbstractFile == false) { - return false; - } - - AbstractFile f = (AbstractFile) content; - if (f.getSize() == 0) { - return false; - } - // check the blackboard for a file type attribute + if (content.getSize() == 0) { + return false; + } + if (!(content instanceof AbstractFile)) { + return false; + } + AbstractFile file = (AbstractFile) content; + + return VideoUtils.isVideoThumbnailSupported(file) + || isImageThumbnailSupported(file); + + } + + public static boolean isImageThumbnailSupported(AbstractFile file) { + + return isMediaThumbnailSupported(file, SUPPORTED_IMAGE_MIME_TYPES, SUPPORTED_IMAGE_EXTENSIONS, CONDITIONAL_MIME_TYPES) + || hasImageFileHeader(file); + } + + /** + * Check if a file is "supported" by checking it mimetype and extension + * + * //TODO: this should move to a better place. Should ImageUtils and + * VideoUtils both implement/extend some base interface/abstract class. That + * would be the natural place to put this. + * + * @param file + * @param supportedMimeTypes a set of mimetypes that the could have to be + * supported + * @param supportedExtension a set of extensions a file could have to be + * supported if the mime lookup fails or is + * inconclusive + * @param conditionalMimes a set of mimetypes that a file could have to be + * supoprted if it also has a supported extension + * + * @return true if a thumbnail can be generated for the given file with the + * given lists of supported mimetype and extensions + */ + static boolean isMediaThumbnailSupported(AbstractFile file, final SortedSet supportedMimeTypes, final List supportedExtension, List conditionalMimes) { + if (file.getSize() == 0) { + return false; + } + final String extension = file.getNameExtension(); try { - ArrayList attributes = f.getGenInfoAttributes(ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG); - for (BlackboardAttribute attribute : attributes) { - if (SUPP_MIME_TYPES.contains(attribute.getValueString())) { - return true; - } + String mimeType = getFileTypeDetector().getFileType(file); + if (Objects.nonNull(mimeType)) { + return supportedMimeTypes.contains(mimeType) + || (conditionalMimes.contains(mimeType.toLowerCase()) && supportedExtension.contains(extension)); } - // if the file type is known and we don't support it, bail - if (attributes.size() > 0) { + } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { + LOGGER.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex); + + AbstractFile.MimeMatchEnum mimeMatch = file.isMimeType(supportedMimeTypes); + if (mimeMatch == AbstractFile.MimeMatchEnum.TRUE) { + return true; + } else if (mimeMatch == AbstractFile.MimeMatchEnum.FALSE) { return false; } - } - catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error while getting file signature from blackboard.", ex); //NON-NLS } - // if we have an extension, check it - final String extension = f.getNameExtension(); - if (extension.equals("") == false) { - // Note: thumbnail generator only supports JPG, GIF, and PNG for now - if (SUPP_EXTENSIONS.contains(extension)) { - return true; - } - } - - // if no extension or one that is not for an image, then read the content - return isJpegFileHeader(f); + return StringUtils.isNotBlank(extension) && supportedExtension.contains(extension); } - /** - * Get a thumbnail of a specified size. Generates the image if it is - * not already cached. - * + * returns a lazily instatiated FileTypeDetector + * + * @return a FileTypeDetector + * + * @throws FileTypeDetectorInitException if a initializing the + * FileTypeDetector failed. + */ + synchronized private static FileTypeDetector getFileTypeDetector() throws FileTypeDetector.FileTypeDetectorInitException { + if (fileTypeDetector == null) { + fileTypeDetector = new FileTypeDetector(); + } + return fileTypeDetector; + } + + /** + * Get a thumbnail of a specified size. Generates the image if it is not + * already cached. + * * @param content * @param iconSize - * @return + * + * + * @return a thumbnail for the given image or a default one if there was a + * problem making a thumbnail. + * + * @deprecated use {@link #getThumbnail(org.sleuthkit.datamodel.Content, int) + * } instead. + * */ + @Nonnull + @Deprecated public static Image getIcon(Content content, int iconSize) { - Image icon; - // If a thumbnail file is already saved locally - // @@@ Bug here in that we do not refer to size in the cache. - File file = getFile(content.getId()); - if (file.exists()) { - try { - BufferedImage bicon = ImageIO.read(file); - if (bicon == null) { - icon = DEFAULT_ICON; - } else if (bicon.getWidth() != iconSize) { - icon = generateAndSaveIcon(content, iconSize, file); - } else { - icon = bicon; - } - } catch (IOException ex) { - logger.log(Level.WARNING, "Error while reading image.", ex); //NON-NLS - icon = DEFAULT_ICON; - } - } else { // Make a new icon - icon = generateAndSaveIcon(content, iconSize, file); - } - return icon; + return getThumbnail(content, iconSize); } - + /** - * Get a thumbnail of a specified size. Generates the image if it is - * not already cached. + * Get a thumbnail of a specified size. Generates the image if it is not + * already cached. + * * @param content * @param iconSize - * @return File object for cached image. Is guaranteed to exist. + * + * @return a thumbnail for the given image or a default one if there was a + * problem making a thumbnail. */ - public static File getIconFile(Content content, int iconSize) { - if (getIcon(content, iconSize) != null) { - return getFile(content.getId()); + public static Image getThumbnail(Content content, int iconSize) { + if (content instanceof AbstractFile) { + AbstractFile file = (AbstractFile) content; + // If a thumbnail file is already saved locally + File cacheFile = getCachedThumbnailLocation(content.getId()); + if (cacheFile.exists()) { + try { + BufferedImage thumbnail = ImageIO.read(cacheFile); + if (isNull(thumbnail) || thumbnail.getWidth() != iconSize) { + return generateAndSaveThumbnail(file, iconSize, cacheFile); + } else { + return thumbnail; + } + } catch (Exception ex) { + LOGGER.log(Level.WARNING, "Error while reading image: " + content.getName(), ex); //NON-NLS + return generateAndSaveThumbnail(file, iconSize, cacheFile); + } + } else { + return generateAndSaveThumbnail(file, iconSize, cacheFile); + } + } else { + return DEFAULT_THUMBNAIL; } - return null; } - + /** - * Get a file object for where the cached icon should exist. The returned file may not exist. - * - * @param id - * @return + * Get a thumbnail of a specified size. Generates the image if it is not + * already cached. + * + * @param content + * @param iconSize + * + * @return File object for cached image. Is guaranteed to exist, as long as + * there was not an error generating or saving the thumbnail. + * + * @deprecated use {@link #getCachedThumbnailFile(org.sleuthkit.datamodel.Content, int) + * } instead. + * */ - // TODO: This should be private and be renamed to something like getCachedThumbnailLocation(). - public static File getFile(long id) { - return new File(Case.getCurrentCase().getCacheDirectory() + File.separator + id + ".png"); + @Nullable + @Deprecated + public static File getIconFile(Content content, int iconSize) { + return getCachedThumbnailFile(content, iconSize); + } - + /** - * Check if is jpeg file based on header + * + * Get a thumbnail of a specified size. Generates the image if it is not + * already cached. + * + * @param content + * @param iconSize + * + * @return File object for cached image. Is guaranteed to exist, as long as + * there was not an error generating or saving the thumbnail. + */ + @Nullable + public static File getCachedThumbnailFile(Content content, int iconSize) { + getThumbnail(content, iconSize); + return getCachedThumbnailLocation(content.getId()); + } + + /** + * Get a file object for where the cached icon should exist. The returned + * file may not exist. + * + * @param id + * + * @return + * + * + * @deprecated use {@link #getCachedThumbnailLocation(long) } instead + */ + @Deprecated + + public static File getFile(long id) { + return getCachedThumbnailLocation(id); + } + + /** + * Get a file object for where the cached icon should exist. The returned + * file may not exist. + * + * @param fileID + * + * @return + * + */ + private static File getCachedThumbnailLocation(long fileID) { + return Paths.get(Case.getCurrentCase().getCacheDirectory(), "thumbnails", fileID + ".png").toFile(); + } + + public static boolean hasImageFileHeader(AbstractFile file) { + return isJpegFileHeader(file) || isPngFileHeader(file); + } + + /** + * Check if the given file is a jpeg based on header. * * @param file * @@ -183,114 +402,140 @@ public class ImageUtils { return false; } - byte[] fileHeaderBuffer = new byte[2]; - int bytesRead; try { - bytesRead = file.read(fileHeaderBuffer, 0, 2); + byte[] fileHeaderBuffer = readHeader(file, 2); + /* + * Check for the JPEG header. Since Java bytes are signed, we cast + * them to an int first. + */ + return (((fileHeaderBuffer[0] & 0xff) == 0xff) && ((fileHeaderBuffer[1] & 0xff) == 0xd8)); } catch (TskCoreException ex) { //ignore if can't read the first few bytes, not a JPEG return false; } - if (bytesRead != 2) { - return false; - } - /* - * Check for the JPEG header. Since Java bytes are signed, we cast them - * to an int first. - */ - return (((fileHeaderBuffer[0] & 0xff) == 0xff) && ((fileHeaderBuffer[1] & 0xff) == 0xd8)); } - + + /** + * Check if the given file is a png based on header. + * + * @param file + * + * @return true if png file, false otherwise + */ public static boolean isPngFileHeader(AbstractFile file) { if (file.getSize() < 10) { return false; } - byte[] fileHeaderBuffer = new byte[8]; - int bytesRead; try { - bytesRead = file.read(fileHeaderBuffer, 0, 8); + byte[] fileHeaderBuffer = readHeader(file, 8); + /* + * Check for the png header. Since Java bytes are signed, we cast + * them to an int first. + */ + return (((fileHeaderBuffer[1] & 0xff) == 0x50) && ((fileHeaderBuffer[2] & 0xff) == 0x4E) + && ((fileHeaderBuffer[3] & 0xff) == 0x47) && ((fileHeaderBuffer[4] & 0xff) == 0x0D) + && ((fileHeaderBuffer[5] & 0xff) == 0x0A) && ((fileHeaderBuffer[6] & 0xff) == 0x1A) + && ((fileHeaderBuffer[7] & 0xff) == 0x0A)); + } catch (TskCoreException ex) { - //ignore if can't read the first few bytes, not an image + //ignore if can't read the first few bytes, not an png return false; } - if (bytesRead != 8) { - return false; - } - /* - * Check for the header. Since Java bytes are signed, we cast them - * to an int first. - */ - return (((fileHeaderBuffer[1] & 0xff) == 0x50) && ((fileHeaderBuffer[2] & 0xff) == 0x4E) && - ((fileHeaderBuffer[3] & 0xff) == 0x47) && ((fileHeaderBuffer[4] & 0xff) == 0x0D) && - ((fileHeaderBuffer[5] & 0xff) == 0x0A) && ((fileHeaderBuffer[6] & 0xff) == 0x1A) && - ((fileHeaderBuffer[7] & 0xff) == 0x0A)); } - - + + private static byte[] readHeader(AbstractFile file, int buffLength) throws TskCoreException { + byte[] fileHeaderBuffer = new byte[buffLength]; + int bytesRead = file.read(fileHeaderBuffer, 0, buffLength); + + if (bytesRead != buffLength) { + //ignore if can't read the first few bytes, not an image + throw new TskCoreException("Could not read " + buffLength + " bytes from " + file.getName()); + } + return fileHeaderBuffer; + } + /** - * Generate an icon and save it to specified location. - * @param content File to generate icon for + * Generate an icon and save it to specified location. + * + * @param file File to generate icon for * @param iconSize - * @param saveFile Location to save thumbnail to + * @param cacheFile Location to save thumbnail to + * * @return Generated icon or null on error */ - private static Image generateAndSaveIcon(Content content, int iconSize, File saveFile) { - Image icon = null; + private static Image generateAndSaveThumbnail(AbstractFile file, int iconSize, File cacheFile) { + BufferedImage thumbnail = null; try { - icon = generateIcon(content, iconSize); - if (icon == null) { - return DEFAULT_ICON; - } else { - if (saveFile.exists()) { - saveFile.delete(); + if (VideoUtils.isVideoThumbnailSupported(file)) { + if (openCVLoaded) { + thumbnail = VideoUtils.generateVideoThumbnail(file, iconSize); + } else { + return DEFAULT_THUMBNAIL; } - ImageIO.write((BufferedImage) icon, "png", saveFile); //NON-NLS - } - } catch (IOException ex) { - logger.log(Level.WARNING, "Could not write cache thumbnail: " + content, ex); //NON-NLS - } - return icon; - } - - /* - * Generate and return a scaled image - */ - private static BufferedImage generateIcon(Content content, int iconSize) { + } else { + thumbnail = generateImageThumbnail(file, iconSize); + } + + if (thumbnail == null) { + return DEFAULT_THUMBNAIL; + + } else { + BufferedImage toSave = thumbnail; + imageSaver.execute(() -> { + try { + Files.createParentDirs(cacheFile); + if (cacheFile.exists()) { + cacheFile.delete(); + } + ImageIO.write(toSave, FORMAT, cacheFile); + } catch (IllegalArgumentException | IOException ex1) { + LOGGER.log(Level.WARNING, "Could not write cache thumbnail: " + file, ex1); //NON-NLS + } + }); + } + } catch (NullPointerException ex) { + logger.log(Level.WARNING, "Could not write cache thumbnail: " + file, ex); //NON-NLS + } + return thumbnail; + } + + /** + * + * Generate and return a scaled image + * + * @param content + * @param iconSize + * + * @return a Thumbnail of the given content at the given size, or null if + * there was a problem. + */ + @Nullable + private static BufferedImage generateImageThumbnail(Content content, int iconSize) { + + try (InputStream inputStream = new BufferedInputStream(new ReadContentInputStream(content));) { + BufferedImage bi = ImageIO.read(inputStream); - InputStream inputStream = null; - BufferedImage bi = null; - try { - inputStream = new ReadContentInputStream(content); - bi = ImageIO.read(inputStream); if (bi == null) { - logger.log(Level.WARNING, "No image reader for file: " + content.getName()); //NON-NLS + LOGGER.log(Level.WARNING, "No image reader for file: {0}", content.getName()); //NON-NLS return null; } - BufferedImage biScaled = ScalrWrapper.resizeFast(bi, iconSize); + try { + return ScalrWrapper.resizeFast(bi, iconSize); + } catch (IllegalArgumentException e) { + // if resizing does not work due to extreme aspect ratio, + // crop the image instead. + return ScalrWrapper.cropImage(bi, Math.min(iconSize, bi.getWidth()), Math.min(iconSize, bi.getHeight())); + } + } catch (OutOfMemoryError e) { + LOGGER.log(Level.WARNING, "Could not scale image (too large): " + content.getName(), e); //NON-NLS - return biScaled; - } catch (IllegalArgumentException e) { - // if resizing does not work due to extremely small height/width ratio, - // crop the image instead. - BufferedImage biCropped = ScalrWrapper.cropImage(bi, Math.min(iconSize, bi.getWidth()), Math.min(iconSize, bi.getHeight())); - return biCropped; - } - catch (OutOfMemoryError e) { - logger.log(Level.WARNING, "Could not scale image (too large): " + content.getName(), e); //NON-NLS return null; } catch (Exception e) { - logger.log(Level.WARNING, "Could not scale image: " + content.getName(), e); //NON-NLS + LOGGER.log(Level.WARNING, "Could not load image: " + content.getName(), e); //NON-NLS return null; - } finally { - if (inputStream != null) { - try { - inputStream.close(); - } catch (IOException ex) { - logger.log(Level.WARNING, "Could not close input stream after resizing thumbnail: " + content.getName(), ex); //NON-NLS - } - } } } + } diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/Installer.java b/Core/src/org/sleuthkit/autopsy/coreutils/Installer.java index eee59f8eb2..74fcc8b854 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/Installer.java @@ -31,14 +31,14 @@ public class Installer extends ModuleInstall { private static Handler logs; private static Installer instance; - + public synchronized static Installer getDefault() { if (instance == null) { instance = new Installer(); } return instance; } - + private Installer() { super(); } @@ -54,14 +54,12 @@ public class Installer extends ModuleInstall { autopsyLogger.log(Level.INFO, "Application name: " + Version.getName() //NON-NLS + ", version: " + Version.getVersion() + ", build: " + Version.getBuildType()); //NON-NLS NON-NLS - + autopsyLogger.log(Level.INFO, "os.name: " + System.getProperty("os.name")); //NON-NLS autopsyLogger.log(Level.INFO, "os.arch: " + System.getProperty("os.arch")); //NON-NLS autopsyLogger.log(Level.INFO, "PID: " + PlatformUtil.getPID()); //NON-NLS autopsyLogger.log(Level.INFO, "Process Virtual Memory Used: " + PlatformUtil.getProcessVirtualMemoryUsed()); //NON-NLS - - - + } @Override diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/JLNK.java b/Core/src/org/sleuthkit/autopsy/coreutils/JLNK.java index ff9787c405..073b9c3107 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/JLNK.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/JLNK.java @@ -33,7 +33,8 @@ import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType; * * @author dick */ - public class JLNK { +public class JLNK { + private int header; private byte[] linkClassIdentifier; private List linkFlags; @@ -45,25 +46,25 @@ import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType; private int iconIndex; private int showCommand; private short hotKey; - + private List linkTargetIdList; - + private boolean hasUnicodeLocalBaseAndCommonSuffixOffset; private String localBasePath; private String commonPathSuffix; private String localBasePathUnicode; private String commonPathSuffixUnicode; - + private String name; private String relativePath; private String workingDir; private String arguments; private String iconLocation; - + private int driveSerialNumber; private DriveType driveType; private String volumeLabel; - + private List commonNetworkRelativeListFlags; private NetworkProviderType networkProviderType; private boolean unicodeNetAndDeviceName; @@ -88,14 +89,14 @@ import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType; this.header = header; this.linkClassIdentifier = linkClassIdentifier; this.linkFlags = new ArrayList(); - for(LnkEnums.LinkFlags enumVal : LnkEnums.LinkFlags.values()) { - if((linkFlags & enumVal.getFlag()) == enumVal.getFlag()) { + for (LnkEnums.LinkFlags enumVal : LnkEnums.LinkFlags.values()) { + if ((linkFlags & enumVal.getFlag()) == enumVal.getFlag()) { this.linkFlags.add(enumVal); } } this.fileAttributesFlags = new ArrayList(); - for(LnkEnums.FileAttributesFlags enumVal : LnkEnums.FileAttributesFlags.values()) { - if((fileAttributesFlags & enumVal.getFlag()) == enumVal.getFlag()) { + for (LnkEnums.FileAttributesFlags enumVal : LnkEnums.FileAttributesFlags.values()) { + if ((fileAttributesFlags & enumVal.getFlag()) == enumVal.getFlag()) { this.fileAttributesFlags.add(enumVal); } } @@ -121,8 +122,8 @@ import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType; this.driveType = driveType; this.volumeLabel = volumeLabel; this.commonNetworkRelativeListFlags = new ArrayList(); - for(LnkEnums.CommonNetworkRelativeLinkFlags enumVal : LnkEnums.CommonNetworkRelativeLinkFlags.values()) { - if((commonNetworkRelativeListFlags & enumVal.getFlag()) == enumVal.getFlag()) { + for (LnkEnums.CommonNetworkRelativeLinkFlags enumVal : LnkEnums.CommonNetworkRelativeLinkFlags.values()) { + if ((commonNetworkRelativeListFlags & enumVal.getFlag()) == enumVal.getFlag()) { this.commonNetworkRelativeListFlags.add(enumVal); } } @@ -193,7 +194,7 @@ import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType; public short getHotKey() { return hotKey; } - + public List getLinkTargetIdList() { return linkTargetIdList; } @@ -261,46 +262,44 @@ import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType; public String getWorkingDir() { return workingDir; } - - - + public String getBestPath() { - if(localBasePathUnicode != null && !localBasePathUnicode.isEmpty()) { - if(commonPathSuffixUnicode != null) { + if (localBasePathUnicode != null && !localBasePathUnicode.isEmpty()) { + if (commonPathSuffixUnicode != null) { return localBasePathUnicode + commonPathSuffixUnicode; - } else if(commonPathSuffix != null) { + } else if (commonPathSuffix != null) { return localBasePathUnicode + commonPathSuffix; } - } else if(localBasePath != null && !localBasePath.isEmpty()) { - if(commonPathSuffixUnicode != null) { + } else if (localBasePath != null && !localBasePath.isEmpty()) { + if (commonPathSuffixUnicode != null) { return localBasePath + commonPathSuffixUnicode; - } else if(commonPathSuffix != null) { + } else if (commonPathSuffix != null) { return localBasePath + commonPathSuffix; } - } else if(netNameUnicode != null && !netNameUnicode.isEmpty()) { - if(commonPathSuffixUnicode != null && !commonPathSuffixUnicode.isEmpty()) { + } else if (netNameUnicode != null && !netNameUnicode.isEmpty()) { + if (commonPathSuffixUnicode != null && !commonPathSuffixUnicode.isEmpty()) { return netNameUnicode + "\\" + commonPathSuffixUnicode; - } else if(commonPathSuffix != null && !commonPathSuffix.isEmpty()) { + } else if (commonPathSuffix != null && !commonPathSuffix.isEmpty()) { return netNameUnicode + "\\" + commonPathSuffix; } - } else if(netName != null && !netName.isEmpty()) { - if(commonPathSuffixUnicode != null && !commonPathSuffixUnicode.isEmpty()) { + } else if (netName != null && !netName.isEmpty()) { + if (commonPathSuffixUnicode != null && !commonPathSuffixUnicode.isEmpty()) { return netName + "\\" + commonPathSuffixUnicode; - } else if(commonPathSuffix != null && !commonPathSuffix.isEmpty()) { + } else if (commonPathSuffix != null && !commonPathSuffix.isEmpty()) { return netName + "\\" + commonPathSuffix; } - } else if(linkTargetIdList != null && !linkTargetIdList.isEmpty()) { + } else if (linkTargetIdList != null && !linkTargetIdList.isEmpty()) { String ret = ""; - for(String s : linkTargetIdList) { + for (String s : linkTargetIdList) { ret += s; } return ret; } return NbBundle.getMessage(this.getClass(), "JLNK.noPrefPath.text"); } - + public String getBestName() { return new File(getBestPath()).getName(); // not very cross platform :( } - + } diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/JLnkParser.java b/Core/src/org/sleuthkit/autopsy/coreutils/JLnkParser.java index e02ec720ff..7cef330e6e 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/JLnkParser.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/JLnkParser.java @@ -32,17 +32,16 @@ import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType; /** * - * @author dfickling - * Parse lnk files using documentation from + * @author dfickling Parse lnk files using documentation from * http://msdn.microsoft.com/en-us/library/dd871305(v=prot.13).aspx * http://msdn.microsoft.com/en-us/library/windows/desktop/cc144090(v=vs.85).aspx#unknown_74413 * http://blog.0x01000000.org/2010/08/10/lnk-parsing-youre-doing-it-wrong-i/ */ - public class JLnkParser { - +public class JLnkParser { + private byte[] content; private static final Logger logger = Logger.getLogger(JLnkParser.class.getName()); - + public JLnkParser(InputStream is, int length) { content = new byte[length]; try { @@ -51,7 +50,7 @@ import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType; Logger.getLogger(JLnkParser.class.getName()).log(Level.WARNING, "Error reading input stream", ex); //NON-NLS } } - + public JLNK parse() throws JLnkParserException { try { ByteBuffer bb = ByteBuffer.wrap(content); @@ -69,18 +68,18 @@ import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType; short hotkey = bb.getShort(); bb.get(new byte[10]); // reserved (???) List linkTargetIdList = new ArrayList(); - if((linkFlags & LnkEnums.LinkFlags.HasLinkTargetIDList.getFlag()) == - LnkEnums.LinkFlags.HasLinkTargetIDList.getFlag()) { + if ((linkFlags & LnkEnums.LinkFlags.HasLinkTargetIDList.getFlag()) + == LnkEnums.LinkFlags.HasLinkTargetIDList.getFlag()) { int idListSize = bb.getShort(); int bytesRead = 0; List linkTargetIdListBytes = new ArrayList(); - while(true) { + while (true) { short itemIdSize = bb.getShort(); - if(itemIdSize == 0) { + if (itemIdSize == 0) { bytesRead += 2; // two null bytes to terminate id list break; } - byte[] theArray = new byte[itemIdSize-2]; + byte[] theArray = new byte[itemIdSize - 2]; bb.get(theArray); // an idlist data object linkTargetIdListBytes.add(theArray); bytesRead = bytesRead + itemIdSize; @@ -103,8 +102,8 @@ import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType; String deviceName = null; String deviceNameUnicode = null; - if((linkFlags & LnkEnums.LinkFlags.HasLinkInfo.getFlag()) == - LnkEnums.LinkFlags.HasLinkInfo.getFlag()) { + if ((linkFlags & LnkEnums.LinkFlags.HasLinkInfo.getFlag()) + == LnkEnums.LinkFlags.HasLinkInfo.getFlag()) { int startOfLinkInfo = bb.position(); int linkInfoSize = bb.getInt(); int linkInfoHeaderSize = bb.getInt(); @@ -122,7 +121,7 @@ import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType; } if ((linkInfoFlags & LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag()) == LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag()) { - bb.position(startOfLinkInfo+volumeIdOffset); + bb.position(startOfLinkInfo + volumeIdOffset); int volumeIdSize = bb.getInt(); driveType = DriveType.valueOf(bb.getInt()); driveSerialNumber = bb.getInt(); @@ -137,7 +136,7 @@ import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType; } if ((linkInfoFlags & LnkEnums.LinkInfoFlags.CommonNetworkRelativeLinkAndPathSuffix.getFlag()) == LnkEnums.LinkInfoFlags.CommonNetworkRelativeLinkAndPathSuffix.getFlag()) { - bb.position(startOfLinkInfo+commonNetworkRelativeLinkOffset); + bb.position(startOfLinkInfo + commonNetworkRelativeLinkOffset); int commonNetworkRelativeLinkSize = bb.getInt(); commonNetworkRelativeLinkFlags = bb.getInt(); int netNameOffset = bb.getInt(); @@ -174,31 +173,31 @@ import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType; commonPathSuffixUnicode = parseCommonPathSuffix(startOfLinkInfo + commonPathSuffixOffsetUnicode, true); } - bb.position(startOfLinkInfo+linkInfoSize); + bb.position(startOfLinkInfo + linkInfoSize); } String name = null; - if((linkFlags & LnkEnums.LinkFlags.HasName.getFlag()) == - LnkEnums.LinkFlags.HasName.getFlag()) { + if ((linkFlags & LnkEnums.LinkFlags.HasName.getFlag()) + == LnkEnums.LinkFlags.HasName.getFlag()) { name = readStringData(bb); } String relativePath = null; - if((linkFlags & LnkEnums.LinkFlags.HasRelativePath.getFlag()) == - LnkEnums.LinkFlags.HasRelativePath.getFlag()) { + if ((linkFlags & LnkEnums.LinkFlags.HasRelativePath.getFlag()) + == LnkEnums.LinkFlags.HasRelativePath.getFlag()) { relativePath = readStringData(bb); } String workingDir = null; - if((linkFlags & LnkEnums.LinkFlags.HasWorkingDir.getFlag()) == - LnkEnums.LinkFlags.HasWorkingDir.getFlag()) { + if ((linkFlags & LnkEnums.LinkFlags.HasWorkingDir.getFlag()) + == LnkEnums.LinkFlags.HasWorkingDir.getFlag()) { workingDir = readStringData(bb); } String arguments = null; - if((linkFlags & LnkEnums.LinkFlags.HasArguments.getFlag()) == - LnkEnums.LinkFlags.HasArguments.getFlag()) { + if ((linkFlags & LnkEnums.LinkFlags.HasArguments.getFlag()) + == LnkEnums.LinkFlags.HasArguments.getFlag()) { arguments = readStringData(bb); } String iconLocation = null; - if((linkFlags & LnkEnums.LinkFlags.HasIconLocation.getFlag()) == - LnkEnums.LinkFlags.HasIconLocation.getFlag()) { + if ((linkFlags & LnkEnums.LinkFlags.HasIconLocation.getFlag()) + == LnkEnums.LinkFlags.HasIconLocation.getFlag()) { iconLocation = readStringData(bb); } @@ -215,13 +214,13 @@ import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType; throw new JLnkParserException(e); } } - + private String readStringData(ByteBuffer bb) { short countCharacters = bb.getShort(); - if(countCharacters == 0) { + if (countCharacters == 0) { return null; } - byte[] theString = new byte[countCharacters*2]; + byte[] theString = new byte[countCharacters * 2]; bb.get(theString); try { return new String(theString, "UTF-16LE"); @@ -230,7 +229,7 @@ import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType; return null; } } - + private String parseString(int offset, boolean unicode, int maxlen) { ByteBuffer bb = ByteBuffer.wrap(content); bb.order(ByteOrder.LITTLE_ENDIAN); @@ -240,7 +239,7 @@ import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType; while (bb.remaining() > 0 && (i < maxlen || maxlen == -1)) // safer { char c; - if(unicode) { + if (unicode) { c = bb.getChar(); } else { c = (char) bb.get(); @@ -253,28 +252,28 @@ import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType; } return sb.toString(); } - + private String parseCommonPathSuffix(int offset, boolean unicode) { return parseString(offset, unicode, -1); - + } - + private String parseLocalBasePath(int offset, boolean unicode) { return parseString(offset, unicode, -1); - + } - + private String parseNetName(int offset, boolean unicode) { return parseString(offset, unicode, -1); } - + private String parseDeviceName(int offset, boolean unicode) { return parseString(offset, unicode, -1); } - + private List parseLinkTargetIdList(List idList) { List ret = new ArrayList(); - if(!idList.isEmpty()) { + if (!idList.isEmpty()) { CommonCLSIDS clsid = CommonCLSIDS.valueOf(Arrays.copyOfRange(idList.remove(0), 2, 18)); switch (clsid) { case CDrivesFolder: @@ -294,13 +293,13 @@ import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType; } return ret; } - + private List parsePathElements(List idList) { List ret = new ArrayList(); for (byte[] pathElement : idList) { ByteBuffer bb = ByteBuffer.wrap(pathElement); bb.order(ByteOrder.LITTLE_ENDIAN); - int offset = bb.getShort(bb.limit() - 2)-2; + int offset = bb.getShort(bb.limit() - 2) - 2; if (pathElement[offset + 0x02] < 0x03 || pathElement[offset + 0x10] >= pathElement[offset] || pathElement[offset + 0x10] < 0x14) { @@ -323,7 +322,7 @@ import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType; } return ret; } - + private String get0xC(ByteBuffer bb) { return getStringAt(bb, 0xC, false); } @@ -340,5 +339,3 @@ import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType; return new String(nameArr).split("\0")[0]; } } - - diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/JLnkParserException.java b/Core/src/org/sleuthkit/autopsy/coreutils/JLnkParserException.java index f9e034df42..de215a56c2 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/JLnkParserException.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/JLnkParserException.java @@ -22,11 +22,11 @@ package org.sleuthkit.autopsy.coreutils; * * @author jwallace */ - public class JLnkParserException extends Exception { +public class JLnkParserException extends Exception { /** - * Constructs an instance of - * JLnkParserException caused by the given exception. + * Constructs an instance of JLnkParserException caused by the + * given exception. * * @param msg the detail message. */ diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/LnkEnums.java b/Core/src/org/sleuthkit/autopsy/coreutils/LnkEnums.java index 5b35043057..dcad3b318c 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/LnkEnums.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/LnkEnums.java @@ -22,38 +22,40 @@ package org.sleuthkit.autopsy.coreutils; * * @author dick */ - class LnkEnums { - - private static final byte[] CDRIVES = new byte[] { (byte)0xe0, 0x4f, (byte)0xd0, 0x20, - (byte)0xea, 0x3a, 0x69, 0x10, (byte)0xa2, (byte)0xd8, 0x08, 0x00, 0x2b, 0x30, 0x30, (byte)0x9d }; - private static final byte[] CMYDOCS = new byte[] { (byte)0xba, (byte)0x8a, 0x0d, - 0x45, 0x25, (byte)0xad, (byte)0xd0, 0x11, (byte)0x98, (byte)0xa8, 0x08, 0x00, 0x36, 0x1b, 0x11, 0x03 }; - private static final byte[] IEFRAME = new byte[] { (byte)0x80, 0x53, 0x1c, (byte)0x87, (byte)0xa0, - 0x42, 0x69, 0x10, (byte)0xa2, (byte)0xea, 0x08, 0x00, 0x2b, 0x30, 0x30, (byte)0x9d }; +class LnkEnums { + + private static final byte[] CDRIVES = new byte[]{(byte) 0xe0, 0x4f, (byte) 0xd0, 0x20, + (byte) 0xea, 0x3a, 0x69, 0x10, (byte) 0xa2, (byte) 0xd8, 0x08, 0x00, 0x2b, 0x30, 0x30, (byte) 0x9d}; + private static final byte[] CMYDOCS = new byte[]{(byte) 0xba, (byte) 0x8a, 0x0d, + 0x45, 0x25, (byte) 0xad, (byte) 0xd0, 0x11, (byte) 0x98, (byte) 0xa8, 0x08, 0x00, 0x36, 0x1b, 0x11, 0x03}; + private static final byte[] IEFRAME = new byte[]{(byte) 0x80, 0x53, 0x1c, (byte) 0x87, (byte) 0xa0, + 0x42, 0x69, 0x10, (byte) 0xa2, (byte) 0xea, 0x08, 0x00, 0x2b, 0x30, 0x30, (byte) 0x9d}; public enum CommonCLSIDS { + CDrivesFolder(CDRIVES), CMyDocsFolder(CMYDOCS), IEFrameDLL(IEFRAME), Unknown(new byte[16]); - + private byte[] flag; - + private CommonCLSIDS(byte[] flag) { this.flag = flag; } - + static CommonCLSIDS valueOf(byte[] type) { - for(CommonCLSIDS value : CommonCLSIDS.values()) { - if(java.util.Arrays.equals(value.flag, type)) { + for (CommonCLSIDS value : CommonCLSIDS.values()) { + if (java.util.Arrays.equals(value.flag, type)) { return value; } } return Unknown; } } - + public enum LinkFlags { + HasLinkTargetIDList(0x00000001), HasLinkInfo(0x00000002), HasName(0x00000004), @@ -81,19 +83,20 @@ package org.sleuthkit.autopsy.coreutils; UnaliasOnSave(0x01000000), PreferEnvironmentPath(0x02000000), KeepLocalIDListForUNCTarget(0x04000000); - + private int flag; - + private LinkFlags(int flag) { this.flag = flag; } - + public int getFlag() { return flag; } } - + public enum DriveType { + DRIVE_UNKNOWN(0x00000000), DRIVE_NO_ROOT_DIR(0x00000001), DRIVE_REMOVABLE(0x00000002), @@ -101,28 +104,29 @@ package org.sleuthkit.autopsy.coreutils; DRIVE_REMOTE(0x00000004), DRIVE_CDROM(0x00000005), DRIVE_RAMDISK(0x00000006); - + private int flag; - + private DriveType(int flag) { this.flag = flag; } - + public int getFlag() { return flag; } - + static DriveType valueOf(int type) { - for(DriveType value : DriveType.values()) { - if(value.flag == type) { + for (DriveType value : DriveType.values()) { + if (value.flag == type) { return value; } } return DRIVE_UNKNOWN; } } - + public enum FileAttributesFlags { + READONLY(0x00000001), HIDDEN(0x00000002), SYSTEM(0x00000004), @@ -138,50 +142,52 @@ package org.sleuthkit.autopsy.coreutils; OFFLINE(0x00001000), NOT_CONTENT_INDEXED(0x00002000), ENCRYPTED(0x00004000); - + private int flag; - + private FileAttributesFlags(int flag) { this.flag = flag; } - + public int getFlag() { return flag; } } - + public enum LinkInfoFlags { + VolumeIDAndLocalBasePath(0x00000001), CommonNetworkRelativeLinkAndPathSuffix(0x00000002); - + private int flag; - + private LinkInfoFlags(int flag) { this.flag = flag; } - + public int getFlag() { return flag; } } - - + public enum CommonNetworkRelativeLinkFlags { + ValidDevice(0x00000001), ValidNetType(0x00000002); - + private int flag; - + private CommonNetworkRelativeLinkFlags(int flag) { this.flag = flag; } - + public int getFlag() { return flag; } } - + public enum NetworkProviderType { + WNNC_NET_AVID(0x001A0000), WNNC_NET_DOCUSPACE(0x001B0000), WNNC_NET_MANGOSOFT(0x001C0000), @@ -224,22 +230,22 @@ package org.sleuthkit.autopsy.coreutils; WNNC_NET_MS_NFS(0x00420000), WNNC_NET_GOOGLE(0x00430000), WNNC_NET_UNKNOWN(0x00000000); - + private int flag; - + private NetworkProviderType(int flag) { this.flag = flag; } - + static NetworkProviderType valueOf(int type) { - for(NetworkProviderType value : NetworkProviderType.values()) { - if(value.flag == type) { + for (NetworkProviderType value : NetworkProviderType.values()) { + if (value.flag == type) { return value; } } return WNNC_NET_UNKNOWN; } - + public int getFlag() { return flag; } diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/LocalDisk.java b/Core/src/org/sleuthkit/autopsy/coreutils/LocalDisk.java index 518b4d1059..dce10640aa 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/LocalDisk.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/LocalDisk.java @@ -22,41 +22,42 @@ package org.sleuthkit.autopsy.coreutils; * Representation of a PhysicalDisk or partition. */ public class LocalDisk { + private String name; private String path; private long size; - + public LocalDisk(String name, String path, long size) { this.name = name; this.path = path; this.size = size; } - + public String getName() { return name; } - + public String getPath() { return path; } - + public long getSize() { return size; } - + public String getReadableSize() { int unit = 1024; if (size < unit) { return size + " B"; //NON-NLS } int exp = (int) (Math.log(size) / Math.log(unit)); - String pre = "KMGTPE".charAt(exp-1) + ""; //NON-NLS + String pre = "KMGTPE".charAt(exp - 1) + ""; //NON-NLS return String.format("%.1f %sB", size / Math.pow(unit, exp), pre); //NON-NLS } - + @Override public String toString() { return name + ": " + getReadableSize(); } - + } diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java b/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java index 8ae2480883..e0ef048b13 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java @@ -125,7 +125,9 @@ public final class Logger extends java.util.logging.Logger { * factory method. * * @param name A name for the logger. This should be a dot-separated name - * and should normally be based on the package name or class name. + * and should normally be based on the package name or class + * name. + * * @return org.sleuthkit.autopsy.coreutils.Logger instance */ public static Logger getLogger(String name) { @@ -137,11 +139,14 @@ public final class Logger extends java.util.logging.Logger { * instance derived from java.util.logging.Logger. Hides the base class * factory method. * - * @param name A name for the logger. This should be a dot-separated name - * and should normally be based on the package name or class name. + * @param name A name for the logger. This should be a + * dot-separated name and should normally be based + * on the package name or class name. * @param resourceBundleName - name of ResourceBundle to be used for - * localizing messages for this logger. May be null if none of the messages - * require localization. + * localizing messages for this logger. May be + * null if none of the messages require + * localization. + * * @return org.sleuthkit.autopsy.coreutils.Logger instance */ public static Logger getLogger(String name, String resourceBundleName) { diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java index 498115f310..56970be4e6 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java @@ -53,7 +53,9 @@ public class MessageNotifyUtil { INFO(NotifyDescriptor.INFORMATION_MESSAGE, "info-icon-16.png"), //NON-NLS ERROR(NotifyDescriptor.ERROR_MESSAGE, "error-icon-16.png"), //NON-NLS - WARNING(NotifyDescriptor.WARNING_MESSAGE, "warning-icon-16.png"); //NON-NLS + WARNING(NotifyDescriptor.WARNING_MESSAGE, "warning-icon-16.png"), //NON-NLS + CONFIRM(NotifyDescriptor.YES_NO_OPTION, "warning-icon-16.png"); //NON-NLS + private final int notifyDescriptorType; private final Icon icon; @@ -103,7 +105,7 @@ public class MessageNotifyUtil { /** * Show a message of the specified type * - * @param message message to show + * @param message message to show * @param messageType message type to show */ public static void show(String message, MessageType messageType) { @@ -111,6 +113,18 @@ public class MessageNotifyUtil { messageType.getNotifyDescriptorType())); } + /** + * Show an confirm, yes-no dialog + * + * @param message message to show + * + * @return true if yes is clicked + */ + public static boolean confirm(String message) { + return getDialogDisplayer().notify(new NotifyDescriptor.Confirmation(message, + MessageType.CONFIRM.getNotifyDescriptorType())) == NotifyDescriptor.YES_OPTION; + } + /** * Show an information dialog * @@ -123,7 +137,7 @@ public class MessageNotifyUtil { /** * Show an error dialog * - * @param message message to shpw + * @param message message to show */ public static void error(String message) { show(message, MessageType.ERROR); @@ -137,6 +151,7 @@ public class MessageNotifyUtil { public static void warn(String message) { show(message, MessageType.WARNING); } + } /** @@ -145,7 +160,7 @@ public class MessageNotifyUtil { public static class Notify { private static final SimpleDateFormat TIME_STAMP_FORMAT = new SimpleDateFormat("MM/dd/yy HH:mm:ss z"); - + //notifications to keep track of and to reset when case is closed private static final List notifications = Collections.synchronizedList(new ArrayList()); @@ -164,6 +179,11 @@ public class MessageNotifyUtil { /** * Show message with the specified type and action listener + * + * @param title message title + * @param message message text + * @param type type of the message + * @param actionListener action listener */ public static void show(String title, String message, MessageType type, ActionListener actionListener) { Notification newNotification @@ -176,9 +196,9 @@ public class MessageNotifyUtil { * displays the message using MessageNotifyUtil.Message with the same * message type * - * @param title message title + * @param title message title * @param message message text - * @param type type of the message + * @param type type of the message */ public static void show(String title, final String message, final MessageType type) { ActionListener actionListener = (ActionEvent e) -> { @@ -191,7 +211,7 @@ public class MessageNotifyUtil { /** * Show an information notification * - * @param title message title + * @param title message title * @param message message text */ public static void info(String title, String message) { @@ -201,7 +221,7 @@ public class MessageNotifyUtil { /** * Show an error notification * - * @param title message title + * @param title message title * @param message message text */ public static void error(String title, String message) { @@ -211,7 +231,7 @@ public class MessageNotifyUtil { /** * Show an warning notification * - * @param title message title + * @param title message title * @param message message text */ public static void warn(String title, String message) { @@ -223,7 +243,8 @@ public class MessageNotifyUtil { * will be in order (they are sorted alphabetically) in the * notifications area. * - * @param title A notification title without a time stamp prefix. + * @param title A notification title without a time stamp prefix. + * * @return The notification title with a time stamp prefix. */ private static String addTimeStampToTitle(String title) { diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ModuleSettings.java b/Core/src/org/sleuthkit/autopsy/coreutils/ModuleSettings.java index 2f1b6eee22..2aa0990993 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ModuleSettings.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ModuleSettings.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.coreutils; import java.io.File; @@ -31,8 +30,8 @@ import java.util.Set; import java.util.logging.Level; /** - * This class contains the framework to read, add, update, and remove - * from the property files located at %USERDIR%/Config/x.properties + * This class contains the framework to read, add, update, and remove from the + * property files located at %USERDIR%/Config/x.properties */ public class ModuleSettings { @@ -41,29 +40,35 @@ public class ModuleSettings { public static final String DEFAULT_CONTEXT = "GeneralContext"; //NON-NLS public static final String MAIN_SETTINGS = "Case"; //NON-NLS - /** the constructor */ - private ModuleSettings() {} + /** + * the constructor + */ + private ModuleSettings() { + } /** - * Makes a new config file of the specified name. Do not include the extension. + * Makes a new config file of the specified name. Do not include the + * extension. + * * @param moduleName - The name of the config file to make - * @return True if successfully created, false if already exists or an error is thrown. + * + * @return True if successfully created, false if already exists or an error + * is thrown. */ - public static boolean makeConfigFile(String moduleName){ - if(!configExists(moduleName)){ + public static boolean makeConfigFile(String moduleName) { + if (!configExists(moduleName)) { File propPath = new File(moduleDirPath + File.separator + moduleName + ".properties"); File parent = new File(propPath.getParent()); - if(! parent.exists()){ + if (!parent.exists()) { parent.mkdirs(); } Properties props = new Properties(); - try{ - propPath.createNewFile(); - FileOutputStream fos = new FileOutputStream(propPath); - props.store(fos, ""); - fos.close(); - } - catch(IOException e){ + try { + propPath.createNewFile(); + FileOutputStream fos = new FileOutputStream(propPath); + props.store(fos, ""); + fos.close(); + } catch (IOException e) { Logger.getLogger(ModuleSettings.class.getName()).log(Level.WARNING, "Was not able to create a new properties file.", e); //NON-NLS return false; } @@ -71,51 +76,57 @@ public class ModuleSettings { } return false; } - - + /** * Determines if a given properties file exists or not. + * * @param moduleName - The name of the config file to evaluate + * * @return true if the config exists, false otherwise. */ - public static boolean configExists(String moduleName){ + public static boolean configExists(String moduleName) { File f = new File(moduleDirPath + File.separator + moduleName + ".properties"); return f.exists(); } - - public static boolean settingExists(String moduleName, String settingName){ - if(! configExists(moduleName)){ + + public static boolean settingExists(String moduleName, String settingName) { + if (!configExists(moduleName)) { return false; } - try{ + try { Properties props = fetchProperties(moduleName); return (props.getProperty(settingName) != null); - } - catch(IOException e){ + } catch (IOException e) { return false; } - + } - + /** * Returns the path of the given properties file. + * * @param moduleName - The name of the config file to evaluate - * @return The path of the given config file. Returns null if the config file doesn't exist. + * + * @return The path of the given config file. Returns null if the config + * file doesn't exist. */ - private static String getPropertyPath(String moduleName){ - if(configExists(moduleName)){ + private static String getPropertyPath(String moduleName) { + if (configExists(moduleName)) { return moduleDirPath + File.separator + moduleName + ".properties"; //NON-NLS } - + return null; } - + /** - * Returns the given properties file's setting as specific by settingName. - * @param moduleName - The name of the config file to read from. - * @param settingName - The setting name to retrieve. + * Returns the given properties file's setting as specific by settingName. + * + * @param moduleName - The name of the config file to read from. + * @param settingName - The setting name to retrieve. + * * @return - the value associated with the setting. - * @throws IOException + * + * @throws IOException */ public static String getConfigSetting(String moduleName, String settingName) { if (!configExists(moduleName)) { @@ -133,13 +144,16 @@ public class ModuleSettings { } } - - + /** * Returns the given properties file's map of settings. + * * @param moduleName - the name of the config file to read from. - * @return - the map of all key:value pairs representing the settings of the config. - * @throws IOException + * + * @return - the map of all key:value pairs representing the settings of the + * config. + * + * @throws IOException */ public static Map< String, String> getConfigSettings(String moduleName) { @@ -166,8 +180,10 @@ public class ModuleSettings { /** * Sets the given properties file to the given setting map. + * * @param moduleName - The name of the module to be written to. - * @param settings - The mapping of all key:value pairs of settings to add to the config. + * @param settings - The mapping of all key:value pairs of settings to add + * to the config. */ public static synchronized void setConfigSettings(String moduleName, Map settings) { if (!configExists(moduleName)) { @@ -189,12 +205,13 @@ public class ModuleSettings { Logger.getLogger(ModuleSettings.class.getName()).log(Level.WARNING, "Property file exists for [" + moduleName + "] at [" + getPropertyPath(moduleName) + "] but could not be loaded.", e); //NON-NLS NON-NLS NON-NLS } } - + /** * Sets the given properties file to the given settings. - * @param moduleName - The name of the module to be written to. + * + * @param moduleName - The name of the module to be written to. * @param settingName - The name of the setting to be modified. - * @param settingVal - the value to set the setting to. + * @param settingVal - the value to set the setting to. */ public static synchronized void setConfigSetting(String moduleName, String settingName, String settingVal) { if (!configExists(moduleName)) { @@ -218,52 +235,56 @@ public class ModuleSettings { /** * Removes the given key from the given properties file. + * * @param moduleName - The name of the properties file to be modified. - * @param key - the name of the key to remove. + * @param key - the name of the key to remove. */ - public static synchronized void removeProperty(String moduleName, String key){ - try{ - if(getConfigSetting(moduleName, key) != null){ - Properties props = fetchProperties(moduleName); - - props.remove(key); - File path = new File(getPropertyPath(moduleName)); - FileOutputStream fos = new FileOutputStream(path); - props.store(fos, "Removed " + key); //NON-NLS - fos.close(); + public static synchronized void removeProperty(String moduleName, String key) { + try { + if (getConfigSetting(moduleName, key) != null) { + Properties props = fetchProperties(moduleName); + + props.remove(key); + File path = new File(getPropertyPath(moduleName)); + FileOutputStream fos = new FileOutputStream(path); + props.store(fos, "Removed " + key); //NON-NLS + fos.close(); } - } - catch(IOException e ){ + } catch (IOException e) { Logger.getLogger(ModuleSettings.class.getName()).log(Level.WARNING, "Could not remove property from file, file not found", e); //NON-NLS } } - + /** - * Returns the properties file as specified by moduleName. + * Returns the properties file as specified by moduleName. + * * @param moduleName + * * @return Properties file as specified by moduleName. - * @throws IOException + * + * @throws IOException */ - private static Properties fetchProperties(String moduleName)throws IOException{ + private static Properties fetchProperties(String moduleName) throws IOException { InputStream inputStream = new FileInputStream(getPropertyPath(moduleName)); Properties props = new Properties(); props.load(inputStream); inputStream.close(); return props; } - + /** * Gets the property file as specified. + * * @param moduleName + * * @return A new file handle, returns null if the file does not exist. */ public static File getPropertyFile(String moduleName) { String path = getPropertyPath(moduleName); - if (path == null){ + if (path == null) { return null; - } - else{ - return new File(getPropertyPath(moduleName)); + } else { + return new File(getPropertyPath(moduleName)); } } } diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/PlatformUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/PlatformUtil.java index 0ff5d311ac..f742e31848 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/PlatformUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/PlatformUtil.java @@ -74,7 +74,7 @@ public class PlatformUtil { * Get root path where the application modules are installed * * @return absolute path string to the install modules root dir, or null if - * not found + * not found */ public static String getInstallModulesPath() { File coreFolder = InstalledFileLocator.getDefault().locate("core", PlatformUtil.class.getPackage().getName(), false); //NON-NLS @@ -101,7 +101,7 @@ public class PlatformUtil { * Get root path where the user modules are installed * * @return absolute path string to the install modules root dir, or null if - * not found + * not found */ public static String getUserModulesPath() { return getUserDirectory().getAbsolutePath() + File.separator + "modules"; @@ -211,13 +211,15 @@ public class PlatformUtil { * Utility to extract a resource file to a user configuration directory, if * it does not exist - useful for setting up default configurations. * - * @param resourceClass class in the same package as the resourceFile to - * extract + * @param resourceClass class in the same package as the resourceFile to + * extract * @param resourceFileName Name of the resource file to extract - * @param overWrite true to overwrite an existing resource + * @param overWrite true to overwrite an existing resource + * * @return true if extracted, false otherwise (if file already exists) + * * @throws IOException exception thrown if extract the file failed for IO - * reasons + * reasons */ public static boolean extractResourceToUserConfigDir(final Class resourceClass, final String resourceFileName, boolean overWrite) throws IOException { Path resourceFilePath = Paths.get(getUserConfigDirectory(), resourceFileName); @@ -225,7 +227,7 @@ public class PlatformUtil { if (resourceFile.exists() && !overWrite) { return false; } - + InputStream inputStream = resourceClass.getResourceAsStream(resourceFileName); if (null == inputStream) { return false; @@ -283,6 +285,7 @@ public class PlatformUtil { * Convert file path (quote) for OS specific * * @param origFilePath + * * @return converted file path */ public static String getOSFilePath(String origFilePath) { @@ -298,7 +301,7 @@ public class PlatformUtil { * system. May not be completely reliable for non-Windows operating systems. * * @return True if the operating system is definitely a 64-bit operating - * system, false otherwise. + * system, false otherwise. */ public static boolean is64BitOS() { if (System.getProperty("os.name").contains("Windows")) { //NON-NLS @@ -407,7 +410,9 @@ public class PlatformUtil { * assuming the results are almost exactly the same. * * @param diskPath path to the disk we want to read + * * @return true if we successfully read the first byte + * * @throws IOException if we fail to read */ private static boolean canReadDrive(String diskPath) { @@ -460,9 +465,9 @@ public class PlatformUtil { * Query and get PID of another java process * * @param sigarSubQuery a sigar subquery to identify a unique java process - * among other java processes, for example, by class name, use: - * Args.*.eq=org.jboss.Main more examples here: - * http://support.hyperic.com/display/SIGAR/PTQL + * among other java processes, for example, by class + * name, use: Args.*.eq=org.jboss.Main more examples + * here: http://support.hyperic.com/display/SIGAR/PTQL * * @return PID of a java process or -1 if it couldn't be determined */ @@ -491,12 +496,12 @@ public class PlatformUtil { * Query and get PIDs of another java processes matching a query * * @param sigarSubQuery a sigar subquery to identify a java processes among - * other java processes, for example, by class name, use: - * Args.*.eq=org.jboss.Main more examples here: - * http://support.hyperic.com/display/SIGAR/PTQL + * other java processes, for example, by class name, + * use: Args.*.eq=org.jboss.Main more examples here: + * http://support.hyperic.com/display/SIGAR/PTQL * * @return array of PIDs of a java processes matching the query or null if - * it couldn't be determined + * it couldn't be determined */ public static synchronized long[] getJavaPIDs(String sigarSubQuery) { long[] jpids = null; diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/SQLiteDBConnect.java b/Core/src/org/sleuthkit/autopsy/coreutils/SQLiteDBConnect.java index d869459b75..ada674433a 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/SQLiteDBConnect.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/SQLiteDBConnect.java @@ -41,12 +41,21 @@ public class SQLiteDBConnect { public Statement statement = null; private static final Logger logger = Logger.getLogger(SQLiteDBConnect.class.getName()); - /* Stub constructor for quick instantiation o/t fly for using some of the ancillary stuff */ + /* + * Stub constructor for quick instantiation o/t fly for using some of the + * ancillary stuff + */ public SQLiteDBConnect() { } - /* quick and dirty constructor to test the database passing the DriverManager name and the fully loaded url to handle */ - /* NB this will typically be available if you make this class concrete and not abstract */ + /* + * quick and dirty constructor to test the database passing the + * DriverManager name and the fully loaded url to handle + */ + /* + * NB this will typically be available if you make this class concrete and + * not abstract + */ public SQLiteDBConnect(String sDriverToLoad, String sUrlToLoad) throws SQLException { init(sDriverToLoad, sUrlToLoad); } @@ -69,9 +78,8 @@ public class SQLiteDBConnect { public void setConnection() throws SQLException { try { Class.forName(sDriver); - } - catch (ClassNotFoundException e) { - + } catch (ClassNotFoundException e) { + } conn = DriverManager.getConnection(sUrl); } @@ -115,4 +123,4 @@ public class SQLiteDBConnect { } catch (Exception ignore) { } } -} \ No newline at end of file +} diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/StopWatch.java b/Core/src/org/sleuthkit/autopsy/coreutils/StopWatch.java index 51fff538ae..db5381c763 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/StopWatch.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/StopWatch.java @@ -16,59 +16,53 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.coreutils; /** * Utility to measure time elapsed, useful for debugging. */ public class StopWatch { - + private long startTime = 0; private long stopTime = 0; private boolean running = false; - public void start() { this.startTime = System.currentTimeMillis(); this.running = true; } - public void stop() { this.stopTime = System.currentTimeMillis(); this.running = false; } - //elaspsed time in milliseconds public long getElapsedTime() { long elapsed; if (running) { - elapsed = (System.currentTimeMillis() - startTime); - } - else { + elapsed = (System.currentTimeMillis() - startTime); + } else { elapsed = (stopTime - startTime); } return elapsed; } - - public void reset(){ - - startTime = 0; - stopTime = 0; - running = false; + + public void reset() { + + startTime = 0; + stopTime = 0; + running = false; } - + //elaspsed time in seconds public long getElapsedTimeSecs() { long elapsed; if (running) { elapsed = ((System.currentTimeMillis() - startTime) / 1000); - } - else { + } else { elapsed = ((stopTime - startTime) / 1000); } return elapsed; } -} \ No newline at end of file +} diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/StringExtract.java b/Core/src/org/sleuthkit/autopsy/coreutils/StringExtract.java index 3f096a8ed7..f9de453a40 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/StringExtract.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/StringExtract.java @@ -36,8 +36,8 @@ import org.sleuthkit.autopsy.coreutils.StringExtract.StringExtractUnicodeTable.S * Currently supports UTF-16 LE, UTF-16 BE and UTF8 Latin, Cyrillic, Chinese, * Arabic * - * TODO: process control characters - * + * TODO: process control characters + * * TODO: handle tie better (when number of chars in 2 results is equal) */ public class StringExtract { @@ -54,21 +54,21 @@ public class StringExtract { private List tags scripts.append(tag.getElement().getContent()).append("\n"); numScripts++; - } else if(tag.getName().equals("a")) { //NON-NLS + } else if (tag.getName().equals("a")) { //NON-NLS links.append(numLinks).append(") "); links.append(tag.getTagContent()).append("\n"); numLinks++; - } else if(tag.getName().equals("img")) { //NON-NLS + } else if (tag.getName().equals("img")) { //NON-NLS images.append(numImages).append(") "); images.append(tag.getTagContent()).append("\n"); numImages++; - } else if(tag.getTagType().equals(StartTagType.COMMENT)) { + } else if (tag.getTagType().equals(StartTagType.COMMENT)) { comments.append(numComments).append(") "); comments.append(tag.getTagContent()).append("\n"); numComments++; } else { // Make sure it has an attribute Attributes atts = tag.getAttributes(); - if (atts!=null && atts.length()>0) { + if (atts != null && atts.length() > 0) { others.append(numOthers).append(") "); others.append(tag.getName()).append(":"); others.append(tag.getTagContent()).append("\n"); @@ -119,19 +121,23 @@ class JerichoParserWrapper { out.append(text).append("\n\n"); out.append("----------NONVISIBLE TEXT----------\n\n"); //NON-NLS - if(numScripts>1) { + if (numScripts > 1) { out.append("---Scripts---\n"); //NON-NLS out.append(scripts.toString()).append("\n"); - } if(numLinks>1) { + } + if (numLinks > 1) { out.append("---Links---\n"); //NON-NLS out.append(links.toString()).append("\n"); - } if(numImages>1) { + } + if (numImages > 1) { out.append("---Images---\n"); //NON-NLS out.append(images.toString()).append("\n"); - } if(numComments>1) { + } + if (numComments > 1) { out.append("---Comments---\n"); //NON-NLS out.append(comments.toString()).append("\n"); - } if(numOthers>1) { + } + if (numOthers > 1) { out.append("---Others---\n"); //NON-NLS out.append(others.toString()).append("\n"); } @@ -141,7 +147,7 @@ class JerichoParserWrapper { logger.log(Level.WARNING, "Unable to parse the HTML file", ex); //NON-NLS } } - + // Extract text from the source, nicely formatted with whitespace and // newlines where appropriate. private String renderHTMLAsPlainText(Source source) { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Keyword.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Keyword.java index 4aca3779a1..293244c6f1 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Keyword.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Keyword.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.keywordsearch; import org.openide.util.NbBundle; @@ -26,14 +25,15 @@ import org.sleuthkit.datamodel.BlackboardAttribute; * Representation of single keyword to search for */ class Keyword { + private String keywordString; // keyword to search for private boolean isLiteral; // false if reg exp private boolean isWholeword; // false if match a substring private BlackboardAttribute.ATTRIBUTE_TYPE keywordType = null; /** - * - * @param query Keyword to search for + * + * @param query Keyword to search for * @param isLiteral false if reg exp */ Keyword(String query, boolean isLiteral) { @@ -41,40 +41,41 @@ class Keyword { this.isLiteral = isLiteral; this.isWholeword = true; } - + /** - * - * @param query Keyword to search for - * @param isLiteral false if reg exp - * @param isWholeword false to match substring (undefined behavior if regexp is true) + * + * @param query Keyword to search for + * @param isLiteral false if reg exp + * @param isWholeword false to match substring (undefined behavior if regexp + * is true) */ Keyword(String query, boolean isLiteral, boolean isWholeword) { this.keywordString = query; this.isLiteral = isLiteral; this.isWholeword = isWholeword; } - + /** - * - * @param query Keyword to search for - * @param isLiteral false if reg exp - * @param keywordType + * + * @param query Keyword to search for + * @param isLiteral false if reg exp + * @param keywordType */ Keyword(String query, boolean isLiteral, BlackboardAttribute.ATTRIBUTE_TYPE keywordType) { this(query, isLiteral); this.keywordType = keywordType; } - + void setType(BlackboardAttribute.ATTRIBUTE_TYPE keywordType) { this.keywordType = keywordType; } - + BlackboardAttribute.ATTRIBUTE_TYPE getType() { return this.keywordType; } /** - * + * * @return Keyword to search for */ String getQuery() { @@ -84,7 +85,7 @@ class Keyword { boolean isLiteral() { return isLiteral; } - + boolean isWholeword() { return isWholeword; } @@ -93,7 +94,7 @@ class Keyword { public String toString() { return NbBundle.getMessage(this.getClass(), "Keyword.toString.text", keywordString, isLiteral, keywordType); } - + @Override public boolean equals(Object obj) { if (obj == null) { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordCachedArtifact.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordCachedArtifact.java index e144f7f1cc..93a83a25b2 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordCachedArtifact.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordCachedArtifact.java @@ -25,8 +25,9 @@ import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; /** - * result of writing keyword search result to blackboard (cached artifact and attributes) - * This is mainly to cache the attributes, so that we don't query the DB to get them back again. + * result of writing keyword search result to blackboard (cached artifact and + * attributes) This is mainly to cache the attributes, so that we don't query + * the DB to get them back again. */ class KeywordCachedArtifact { @@ -59,4 +60,4 @@ class KeywordCachedArtifact { this.attributes.put(attr.getAttributeTypeID(), attr); } } -} \ No newline at end of file +} diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java index ca1454ab40..cf86ce20c9 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java @@ -47,12 +47,12 @@ class KeywordHit { /** * Parse the Solr document id to get the Solr object id and chunk id. - * The Solr object id will either be a file id or an artifact id from + * The Solr object id will either be a file id or an artifact id from * the case database. - * - * For every object (file or artifact) there will at least - * two Solr documents. One contains object metadata (chunk #1) and the - * second and subsequent documents contain chunks of the text. + * + * For every object (file or artifact) there will at least two Solr + * documents. One contains object metadata (chunk #1) and the second and + * subsequent documents contain chunks of the text. */ final int separatorIndex = solrDocumentId.indexOf(Server.ID_CHUNK_SEP); if (-1 != separatorIndex) { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordList.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordList.java index 68512fe4b4..2dd2933fa9 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordList.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordList.java @@ -44,10 +44,11 @@ public class KeywordList { KeywordList(String name, Date created, Date modified, Boolean useForIngest, Boolean ingestMessages, List keywords) { this(name, created, modified, useForIngest, ingestMessages, keywords, false); } - + /** - * Create an unnamed list. Usually used for ad-hoc searches - * @param keywords + * Create an unnamed list. Usually used for ad-hoc searches + * + * @param keywords */ KeywordList(List keywords) { this("", new Date(0), new Date(0), false, false, keywords, false); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordListsManager.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordListsManager.java index b99bc289b7..13bf972e18 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordListsManager.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordListsManager.java @@ -32,7 +32,7 @@ import java.util.Observable; // motivated by a desire to not expose XmlKeywordSearchList to public clients. // It should be futher developed as time constraints and needs dictate. public class KeywordListsManager extends Observable { - + private static KeywordListsManager instance; private final PropertyChangeListener listsChangeListener; @@ -72,5 +72,5 @@ public class KeywordListsManager extends Observable { } return names; } - + } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordQueryFilter.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordQueryFilter.java index df8c281f0a..6dab2eb224 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordQueryFilter.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordQueryFilter.java @@ -24,8 +24,8 @@ import java.util.Set; /** * - * Filter to restrict query only specific files, chunks, images - * Single filter supports multiple ids per file/chunk/image, that act as OR filter + * Filter to restrict query only specific files, chunks, images Single filter + * supports multiple ids per file/chunk/image, that act as OR filter */ class KeywordQueryFilter { @@ -33,7 +33,7 @@ class KeywordQueryFilter { FILE, CHUNK, DATA_SOURCE }; - private SetidFilters; + private Set idFilters; private FilterType filterType; public KeywordQueryFilter(FilterType filterType, long id) { @@ -42,7 +42,7 @@ class KeywordQueryFilter { this.idFilters.add(id); } - public KeywordQueryFilter(FilterType filterType, Setids) { + public KeywordQueryFilter(FilterType filterType, Set ids) { this.filterType = filterType; this.idFilters = ids; } @@ -59,8 +59,8 @@ class KeywordQueryFilter { public String toString() { StringBuilder sb = new StringBuilder(); String id = null; - - Iteratorit = idFilters.iterator(); + + Iterator it = idFilters.iterator(); for (int i = 0; it.hasNext(); ++i) { if (i > 0) { sb.append(" "); //OR diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearch.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearch.java index 00c2bb46d7..e92b4f5410 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearch.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearch.java @@ -34,8 +34,8 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import java.util.logging.Level; /** - * Wrapper over KeywordSearch Solr server singleton. - * The class also provides some global types and property change support on the server events. + * Wrapper over KeywordSearch Solr server singleton. The class also provides + * some global types and property change support on the server events. */ public class KeywordSearch { @@ -44,7 +44,9 @@ public class KeywordSearch { //a separate logger from framework logs private static final Logger TIKA_LOGGER = Logger.getLogger("Tika"); //NON-NLS private static final org.sleuthkit.autopsy.coreutils.Logger logger = org.sleuthkit.autopsy.coreutils.Logger.getLogger(Case.class.getName()); + public enum QueryType { + LITERAL, REGEX }; public static final String NUM_FILES_CHANGE_EVT = "NUM_FILES_CHANGE_EVT"; //NON-NLS @@ -88,27 +90,25 @@ public class KeywordSearch { static Logger getTikaLogger() { return TIKA_LOGGER; } - public static void addNumIndexedFilesChangeListener(PropertyChangeListener l) { changeSupport.addPropertyChangeListener(NUM_FILES_CHANGE_EVT, l); } - + public static void removeNumIndexedFilesChangeListener(PropertyChangeListener l) { changeSupport.removePropertyChangeListener(l); } - + public static void fireNumIndexedFilesChange(Integer oldNum, Integer newNum) { - + try { changeSupport.firePropertyChange(NUM_FILES_CHANGE_EVT, oldNum, newNum); - } - catch (Exception e) { + } catch (Exception e) { logger.log(Level.SEVERE, "KeywordSearch listener threw exception", e); //NON-NLS MessageNotifyUtil.Notify.show(NbBundle.getMessage(KeywordSearch.class, "KeywordSearch.moduleErr"), - NbBundle.getMessage(KeywordSearch.class, - "KeywordSearch.fireNumIdxFileChg.moduleErr.msg"), - MessageNotifyUtil.MessageType.ERROR); + NbBundle.getMessage(KeywordSearch.class, + "KeywordSearch.fireNumIdxFileChg.moduleErr.msg"), + MessageNotifyUtil.MessageType.ERROR); } } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchConfigurationAction.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchConfigurationAction.java index e4593171bf..8bada4be8d 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchConfigurationAction.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchConfigurationAction.java @@ -30,8 +30,8 @@ import org.sleuthkit.autopsy.corecomponents.AdvancedConfigurationDialog; /** * System action to open the KeywordSearch Options panel. */ -class KeywordSearchConfigurationAction extends CallableSystemAction{ - +class KeywordSearchConfigurationAction extends CallableSystemAction { + private static final String ACTION_NAME = org.openide.util.NbBundle.getMessage(DropdownToolbar.class, "ListBundleConfig"); private KeywordSearchGlobalSettingsPanel panel; @@ -59,9 +59,9 @@ class KeywordSearchConfigurationAction extends CallableSystemAction{ dialog.addWindowListener(exitListener); dialog.display(panel); } - + private KeywordSearchGlobalSettingsPanel getPanel() { - if(panel==null) { + if (panel == null) { panel = new KeywordSearchGlobalSettingsPanel(); } return panel; @@ -76,7 +76,7 @@ class KeywordSearchConfigurationAction extends CallableSystemAction{ public HelpCtx getHelpCtx() { return HelpCtx.DEFAULT_HELP; } - + @Override protected boolean asynchronous() { return false; diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java index ea57c13db9..892b5e666d 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java @@ -41,7 +41,7 @@ import org.sleuthkit.datamodel.DerivedFile; import org.sleuthkit.datamodel.File; /** - * + * */ class KeywordSearchFilterNode extends FilterNode { @@ -81,6 +81,7 @@ class KeywordSearchFilterNode extends FilterNode { * table and the output view. * * @param popup + * * @return actions */ @Override @@ -100,12 +101,12 @@ class KeywordSearchFilterNode extends FilterNode { public List visit(File f) { return getFileActions(); } - + @Override public List visit(DerivedFile f) { return getFileActions(); } - + private List getFileActions() { List actions = new ArrayList<>(); actions.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.viewInNewWinActionLbl"), KeywordSearchFilterNode.this)); @@ -116,7 +117,7 @@ class KeywordSearchFilterNode extends FilterNode { actions.add(null); // creates a menu separator actions.add(AddContentTagAction.getInstance()); actions.addAll(ContextMenuExtensionPoint.getActions()); - return actions; + return actions; } @Override diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalLanguageSettingsPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalLanguageSettingsPanel.java index 254b0f75ab..b88ce6de59 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalLanguageSettingsPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalLanguageSettingsPanel.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.keywordsearch; import java.awt.GridLayout; @@ -81,7 +80,7 @@ class KeywordSearchGlobalLanguageSettingsPanel extends javax.swing.JPanel implem sb.append(")"); return sb.toString(); } - + private void initScriptsCheckBoxes() { final List supportedScripts = StringExtract.getSupportedScripts(); checkPanel.setLayout(new GridLayout(0, 1)); @@ -95,41 +94,41 @@ class KeywordSearchGlobalLanguageSettingsPanel extends javax.swing.JPanel implem } } - private void reloadScriptsCheckBoxes() { - boolean utf16 = - Boolean.parseBoolean(KeywordSearchSettings.getStringExtractOption(TextExtractor.ExtractOptions.EXTRACT_UTF16.toString())); - + private void reloadScriptsCheckBoxes() { + boolean utf16 + = Boolean.parseBoolean(KeywordSearchSettings.getStringExtractOption(TextExtractor.ExtractOptions.EXTRACT_UTF16.toString())); + enableUTF16Checkbox.setSelected(utf16); - - boolean utf8 = - Boolean.parseBoolean(KeywordSearchSettings.getStringExtractOption(TextExtractor.ExtractOptions.EXTRACT_UTF8.toString())); + + boolean utf8 + = Boolean.parseBoolean(KeywordSearchSettings.getStringExtractOption(TextExtractor.ExtractOptions.EXTRACT_UTF8.toString())); enableUTF8Checkbox.setSelected(utf8); - + final List