1
0
mirror of https://github.com/elisspace/autopsy.git synced 2026-09-06 02:24:30 +00:00

Merge branch 'develop' of https://github.com/sleuthkit/autopsy into newMboxParser

Conflicts:
	Core/src/org/sleuthkit/autopsy/ingest/GeneralIngestConfigurator.java
This commit is contained in:
Jeff Wallace
2013-12-12 15:34:33 -05:00
197 changed files with 11351 additions and 7599 deletions

View File

@@ -1,10 +1,10 @@
Manifest-Version: 1.0
OpenIDE-Module: org.sleuthkit.autopsy.core/9
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties
OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml
OpenIDE-Module-Implementation-Version: 9
OpenIDE-Module-Requires: org.openide.windows.WindowManager, org.netbeans.api.javahelp.Help
AutoUpdate-Show-In-Client: true
AutoUpdate-Essential-Module: true
OpenIDE-Module-Install: org/sleuthkit/autopsy/core/Installer.class
Manifest-Version: 1.0
OpenIDE-Module: org.sleuthkit.autopsy.core/9
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties
OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml
OpenIDE-Module-Implementation-Version: 9
OpenIDE-Module-Requires: org.openide.windows.WindowManager, org.netbeans.api.javahelp.Help
AutoUpdate-Show-In-Client: true
AutoUpdate-Essential-Module: true
OpenIDE-Module-Install: org/sleuthkit/autopsy/core/Installer.class

View File

@@ -191,6 +191,7 @@
</dependency>
</module-dependencies>
<public-packages>
<package>org.sleuthkit.autopsy.actions</package>
<package>org.sleuthkit.autopsy.casemodule</package>
<package>org.sleuthkit.autopsy.casemodule.services</package>
<package>org.sleuthkit.autopsy.core</package>

View File

@@ -0,0 +1,69 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.actions;
import java.util.Collection;
import java.util.logging.Level;
import javax.swing.JOptionPane;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.TskCoreException;
/**
* 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() {
if (null == instance) {
instance = new AddBlackboardArtifactTagAction();
}
return instance;
}
private AddBlackboardArtifactTagAction() {
super("");
}
@Override
protected String getActionDisplayName() {
return Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class).size() > 1 ? "Tag Results" : "Tag Result";
}
@Override
protected void addTag(TagName tagName, String comment) {
Collection<? extends BlackboardArtifact> selectedArtifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class);
for (BlackboardArtifact artifact : selectedArtifacts) {
try {
Case.getCurrentCase().getServices().getTagsManager().addBlackboardArtifactTag(artifact, tagName, comment);
}
catch (TskCoreException ex) {
Logger.getLogger(AddBlackboardArtifactTagAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex);
JOptionPane.showMessageDialog(null, "Unable to tag " + artifact.getDisplayName() + ".", "Tagging Error", JOptionPane.ERROR_MESSAGE);
}
}
}
}

View File

@@ -0,0 +1,99 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.actions;
import java.util.Collection;
import java.util.logging.Level;
import javax.swing.JOptionPane;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Instances of this Action allow users to apply tags to content.
*/
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).
private static AddContentTagAction instance;
public static synchronized AddContentTagAction getInstance() {
if (null == instance) {
instance = new AddContentTagAction();
}
return instance;
}
private AddContentTagAction() {
super("");
}
@Override
protected String getActionDisplayName() {
return Utilities.actionsGlobalContext().lookupAll(AbstractFile.class).size() > 1 ? "Tag Files" : "Tag File";
}
@Override
protected void addTag(TagName tagName, String comment) {
Collection<? extends AbstractFile> selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class);
for (AbstractFile file : selectedFiles) {
try {
// Handle the special cases of current (".") and parent ("..") directory entries.
if (file.getName().equals(".")) {
Content parentFile = file.getParent();
if (parentFile instanceof AbstractFile) {
file = (AbstractFile)parentFile;
}
else {
JOptionPane.showMessageDialog(null, "Unable to tag " + parentFile.getName() + ", not a regular file.", "Cannot Apply Tag", JOptionPane.WARNING_MESSAGE);
continue;
}
}
else if (file.getName().equals("..")) {
Content parentFile = file.getParent();
if (parentFile instanceof AbstractFile) {
parentFile = (AbstractFile)((AbstractFile)parentFile).getParent();
if (parentFile instanceof AbstractFile) {
file = (AbstractFile)parentFile;
}
else {
JOptionPane.showMessageDialog(null, "Unable to tag " + parentFile.getName() + ", not a regular file.", "Cannot Apply Tag", JOptionPane.WARNING_MESSAGE);
continue;
}
}
else {
JOptionPane.showMessageDialog(null, "Unable to tag " + parentFile.getName() + ", not a regular file.", "Cannot Apply Tag", JOptionPane.WARNING_MESSAGE);
continue;
}
}
Case.getCurrentCase().getServices().getTagsManager().addContentTag(file, tagName, comment);
}
catch (TskCoreException ex) {
Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex);
JOptionPane.showMessageDialog(null, "Unable to tag " + file.getName() + ".", "Tagging Error", JOptionPane.ERROR_MESSAGE);
}
}
}
}

View File

@@ -0,0 +1,148 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.actions;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import org.openide.util.actions.Presenter;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* An abstract base class for Actions that allow users to tag SleuthKit data
* model objects.
*/
abstract class AddTagAction extends TagAction implements Presenter.Popup {
private static final String NO_COMMENT = "";
AddTagAction(String menuText) {
super(menuText);
}
@Override
public JMenuItem getPopupPresenter() {
return new TagMenu();
}
@Override
protected void doAction(ActionEvent event) {
}
/**
* Template method to allow derived classes to provide a string for for a
* menu item label.
*/
abstract protected String getActionDisplayName();
/**
* Template method to allow derived classes to add the indicated tag and
* comment to one or more a SleuthKit data model objects.
*/
abstract protected void addTag(TagName tagName, String comment);
/**
* Instances of this class implement a context menu user interface for
* creating or selecting a tag name for a tag and specifying an optional tag
* comment.
*/
// @@@ This user interface has some significant usability issues and needs
// to be reworked.
private class TagMenu extends JMenu {
TagMenu() {
super(getActionDisplayName());
// Get the current set of tag names.
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
List<TagName> tagNames = null;
try {
tagNames = tagsManager.getAllTagNames();
}
catch (TskCoreException ex) {
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex);
}
// Create a "Quick Tag" sub-menu.
JMenu quickTagMenu = new JMenu("Quick Tag");
add(quickTagMenu);
// Each tag name in the current set of tags gets its own menu item in
// the "Quick Tags" sub-menu. Selecting one of these menu items adds
// a tag with the associated tag name.
if (null != tagNames && !tagNames.isEmpty()) {
for (final TagName tagName : tagNames) {
JMenuItem tagNameItem = new JMenuItem(tagName.getDisplayName());
tagNameItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
addTag(tagName, NO_COMMENT);
refreshDirectoryTree();
}
});
quickTagMenu.add(tagNameItem);
}
}
else {
JMenuItem empty = new JMenuItem("No tags");
empty.setEnabled(false);
quickTagMenu.add(empty);
}
quickTagMenu.addSeparator();
// The "Quick Tag" menu also gets an "Choose Tag..." menu item.
// Selecting this item initiates a dialog that can be used to create
// or select a tag name and adds a tag with the resulting name.
JMenuItem newTagMenuItem = new JMenuItem("New Tag...");
newTagMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
TagName tagName = GetTagNameDialog.doDialog();
if (tagName != null) {
addTag(tagName, NO_COMMENT);
refreshDirectoryTree();
}
}
});
quickTagMenu.add(newTagMenuItem);
// Create a "Choose Tag and Comment..." menu item. Selecting this item initiates
// a dialog that can be used to create or select a tag name with an
// optional comment and adds a tag with the resulting name.
JMenuItem tagAndCommentItem = new JMenuItem("Tag and Comment...");
tagAndCommentItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog();
if (null != tagNameAndComment) {
addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment());
refreshDirectoryTree();
}
}
});
add(tagAndCommentItem);
}
}
}

View File

@@ -0,0 +1,16 @@
GetTagNameDialog.tagNameField.text=
GetTagNameDialog.cancelButton.text=Cancel
GetTagNameDialog.okButton.text=OK
GetTagNameDialog.preexistingLabel.text=Pre-existing Tags:
GetTagNameDialog.newTagPanel.border.title=New Tag
GetTagNameDialog.tagNameLabel.text=Tag Name:
GetTagNameAndCommentDialog.newTagButton.text=New Tag
GetTagNameAndCommentDialog.okButton.text=OK
GetTagNameAndCommentDialog.commentText.toolTipText=Enter an optional tag comment or leave blank
GetTagNameAndCommentDialog.commentText.text=
GetTagNameAndCommentDialog.commentLabel.text=Comment:
# To change this template, choose Tools | Templates
# and open the template in the editor.
GetTagNameAndCommentDialog.cancelButton.text=Cancel
GetTagNameAndCommentDialog.tagCombo.toolTipText=Select tag to use
GetTagNameAndCommentDialog.tagLabel.text=Tag:

View File

@@ -0,0 +1,67 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.actions;
import java.awt.event.ActionEvent;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Instances of this Action allow users to delete tags applied to blackboard artifacts.
*/
public class DeleteBlackboardArtifactTagAction extends TagAction {
private static final String MENU_TEXT = "Delete Tag(s)";
// 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 DeleteBlackboardArtifactTagAction instance;
public static synchronized DeleteBlackboardArtifactTagAction getInstance() {
if (null == instance) {
instance = new DeleteBlackboardArtifactTagAction();
}
return instance;
}
private DeleteBlackboardArtifactTagAction() {
super(MENU_TEXT);
}
@Override
protected void doAction(ActionEvent event) {
Collection<? extends BlackboardArtifactTag> selectedTags = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifactTag.class);
for (BlackboardArtifactTag tag : selectedTags) {
try {
Case.getCurrentCase().getServices().getTagsManager().deleteBlackboardArtifactTag(tag);
}
catch (TskCoreException ex) {
Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex);
JOptionPane.showMessageDialog(null, "Unable to delete tag " + tag.getName() + ".", "Tag Deletion Error", JOptionPane.ERROR_MESSAGE);
}
}
}
}

View File

@@ -0,0 +1,66 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.actions;
import java.awt.event.ActionEvent;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Instances of this Action allow users to delete tags applied to content.
*/
public class DeleteContentTagAction extends TagAction {
private static final String MENU_TEXT = "Delete Tag(s)";
// 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 DeleteContentTagAction instance;
public static synchronized DeleteContentTagAction getInstance() {
if (null == instance) {
instance = new DeleteContentTagAction();
}
return instance;
}
private DeleteContentTagAction() {
super(MENU_TEXT);
}
@Override
protected void doAction(ActionEvent e) {
Collection<? extends ContentTag> selectedTags = Utilities.actionsGlobalContext().lookupAll(ContentTag.class);
for (ContentTag tag : selectedTags) {
try {
Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(tag);
}
catch (TskCoreException ex) {
Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex);
JOptionPane.showMessageDialog(null, "Unable to delete tag " + tag.getName() + ".", "Tag Deletion Error", JOptionPane.ERROR_MESSAGE);
}
}
}
}

View File

@@ -78,7 +78,7 @@
<Component class="javax.swing.JButton" name="okButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
@@ -91,7 +91,7 @@
<Component class="javax.swing.JButton" name="cancelButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
@@ -104,7 +104,7 @@
<StringArray count="0"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.tagCombo.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.tagCombo.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AuxValues>
@@ -114,31 +114,31 @@
<Component class="javax.swing.JLabel" name="tagLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.tagLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.tagLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="commentLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.commentLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.commentLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="commentText">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.commentText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.commentText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.commentText.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.commentText.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="newTagButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.newTagButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.newTagButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>

View File

@@ -16,11 +16,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.directorytree;
package org.sleuthkit.autopsy.actions;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.TreeSet;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
@@ -29,28 +31,28 @@ import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.KeyStroke;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.datamodel.Tags;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Tag dialog for tagging files and results. User enters an optional comment.
*/
public class TagAndCommentDialog extends JDialog {
public class GetTagNameAndCommentDialog extends JDialog {
private static final String NO_TAG_NAMES_MESSAGE = "No Tags";
private final HashMap<String, TagName> tagNames = new HashMap<>();
private TagNameAndComment tagNameAndComment = null;
private static final String NO_TAG_MESSAGE = "No Tags";
private String tagName = "";
private String comment = "";
public static class CommentedTag {
private String name;
public static class TagNameAndComment {
private TagName tagName;
private String comment;
CommentedTag(String name, String comment) {
this.name = name;
private TagNameAndComment(TagName tagName, String comment) {
this.tagName = tagName;
this.comment = comment;
}
public String getName() {
return name;
public TagName getTagName() {
return tagName;
}
public String getComment() {
@@ -58,25 +60,16 @@ public class TagAndCommentDialog extends JDialog {
}
}
public static CommentedTag doDialog() {
TagAndCommentDialog dialog = new TagAndCommentDialog();
if (!dialog.tagName.isEmpty()) {
return new CommentedTag(dialog.tagName, dialog.comment);
}
else {
return null;
}
public static TagNameAndComment doDialog() {
GetTagNameAndCommentDialog dialog = new GetTagNameAndCommentDialog();
return dialog.tagNameAndComment;
}
/**
* Creates new form TagDialog
*/
private TagAndCommentDialog() {
super((JFrame)WindowManager.getDefault().getMainWindow(), "Tag and Comment", true);
private GetTagNameAndCommentDialog() {
super((JFrame)WindowManager.getDefault().getMainWindow(), "Create Tag", true);
initComponents();
// Close the dialog when Esc is pressed
// Set up the dialog to close when Esc is pressed.
String cancelName = "cancel";
InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName);
@@ -87,24 +80,30 @@ public class TagAndCommentDialog extends JDialog {
dispose();
}
});
// get the current list of tag names
TreeSet<String> tags = Tags.getAllTagNames();
// if there are no tags, add the NO_TAG_MESSAGE
if (tags.isEmpty()) {
tags.add(NO_TAG_MESSAGE);
// 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<TagName> currentTagNames = null;
try {
currentTagNames = tagsManager.getAllTagNames();
}
// add the tags to the combo box
for (String tag : tags) {
tagCombo.addItem(tag);
catch (TskCoreException ex) {
Logger.getLogger(GetTagNameAndCommentDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex);
}
if (null != currentTagNames && currentTagNames.isEmpty()) {
tagCombo.addItem(NO_TAG_NAMES_MESSAGE);
}
else {
for (TagName tagName : currentTagNames) {
tagNames.put(tagName.getDisplayName(), tagName);
tagCombo.addItem(tagName.getDisplayName());
}
}
//center it
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
setVisible(true); // blocks
// Center and show the dialog box.
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
setVisible(true);
}
/**
@@ -130,30 +129,30 @@ public class TagAndCommentDialog extends JDialog {
}
});
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.okButton.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.okButton.text")); // NOI18N
okButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
okButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.cancelButton.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.cancelButton.text")); // NOI18N
cancelButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cancelButtonActionPerformed(evt);
}
});
tagCombo.setToolTipText(org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.tagCombo.toolTipText")); // NOI18N
tagCombo.setToolTipText(org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.tagCombo.toolTipText")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(tagLabel, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.tagLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(tagLabel, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.tagLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(commentLabel, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.commentLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(commentLabel, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentLabel.text")); // NOI18N
commentText.setText(org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.commentText.text")); // NOI18N
commentText.setToolTipText(org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.commentText.toolTipText")); // NOI18N
commentText.setText(org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentText.text")); // NOI18N
commentText.setToolTipText(org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentText.toolTipText")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(newTagButton, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.newTagButton.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(newTagButton, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.newTagButton.text")); // NOI18N
newTagButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
newTagButtonActionPerformed(evt);
@@ -212,27 +211,26 @@ public class TagAndCommentDialog extends JDialog {
}// </editor-fold>//GEN-END:initComponents
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
tagName = (String)tagCombo.getSelectedItem();
comment = commentText.getText();
tagNameAndComment = new TagNameAndComment(tagNames.get((String)tagCombo.getSelectedItem()), commentText.getText());
dispose();
}//GEN-LAST:event_okButtonActionPerformed
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
tagNameAndComment = null;
dispose();
}//GEN-LAST:event_cancelButtonActionPerformed
/**
* Closes the dialog
*/
private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog
tagNameAndComment = null;
dispose();
}//GEN-LAST:event_closeDialog
private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed
String newTagName = CreateTagDialog.getNewTagNameDialog(null);
TagName newTagName = GetTagNameDialog.doDialog();
if (newTagName != null) {
tagCombo.addItem(newTagName);
tagCombo.setSelectedItem(newTagName);
tagNames.put(newTagName.getDisplayName(), newTagName);
tagCombo.addItem(newTagName.getDisplayName());
tagCombo.setSelectedItem(newTagName.getDisplayName());
}
}//GEN-LAST:event_newTagButtonActionPerformed

View File

@@ -72,7 +72,7 @@
<Component class="javax.swing.JButton" name="cancelButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
@@ -82,7 +82,7 @@
<Component class="javax.swing.JButton" name="okButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
@@ -124,7 +124,7 @@
<Component class="javax.swing.JLabel" name="preexistingLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.preexistingLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.preexistingLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
@@ -133,7 +133,7 @@
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="New Tag">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.newTagPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.newTagPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
@@ -168,14 +168,14 @@
<Component class="javax.swing.JLabel" name="tagNameLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.tagNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.tagNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="tagNameField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.tagNameField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.tagNameField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>

View File

@@ -16,72 +16,130 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.directorytree;
package org.sleuthkit.autopsy.actions;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import javax.swing.table.AbstractTableModel;
import org.openide.util.ImageUtilities;
import org.sleuthkit.autopsy.datamodel.Tags;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
public class CreateTagDialog extends JDialog {
public class GetTagNameDialog extends JDialog {
private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
private static String newTagName;
private final HashMap<String, TagName> tagNames = new HashMap<>();
private TagName tagName = null;
/**
* Creates new form CreateTagDialog
*/
private CreateTagDialog(JFrame parent) {
super(parent, true);
init();
}
public static TagName doDialog() {
GetTagNameDialog dialog = new GetTagNameDialog();
return dialog.tagName;
}
public static String getNewTagNameDialog(JFrame parent) {
new CreateTagDialog(parent);
return newTagName;
}
private void init() {
setTitle("Create a new tag");
private GetTagNameDialog() {
super((JFrame)WindowManager.getDefault().getMainWindow(), "Create Tag", true);
setIconImage(ImageUtilities.loadImage(TAG_ICON_PATH));
initComponents();
tagsTable.setModel(new TagsTableModel());
// Set up the dialog to close when Esc is pressed.
String cancelName = "cancel";
InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName);
ActionMap actionMap = getRootPane().getActionMap();
actionMap.put(cancelName, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
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<TagName> currentTagNames = null;
try {
currentTagNames = tagsManager.getAllTagNames();
}
catch (TskCoreException ex) {
Logger.getLogger(GetTagNameDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex);
}
if (null != currentTagNames) {
for (TagName name : currentTagNames) {
this.tagNames.put(name.getDisplayName(), name);
}
}
else {
currentTagNames = new ArrayList<>();
}
// Populate the tag names table.
tagsTable.setModel(new TagsTableModel(currentTagNames));
tagsTable.setTableHeader(null);
//completely disable selections
tagsTable.setCellSelectionEnabled(false);
tagsTable.setFocusable(false);
tagsTable.setRowHeight(tagsTable.getRowHeight() + 5);
setIconImage(ImageUtilities.loadImage(TAG_ICON_PATH));
Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
// set the popUp window / JFrame
int w = this.getSize().width;
int h = this.getSize().height;
// set the location of the popUp Window on the center of the screen
setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2);
setVisible(true); //blocks
// Center and show the dialog box.
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
setVisible(true);
}
private boolean containsIllegalCharacters(String content) {
if ((content.contains("\\") || content.contains(":") || content.contains("*")
|| content.contains("?") || content.contains("\"") || content.contains("<")
|| content.contains(">") || content.contains("|"))) {
return true;
}
return false;
return (content.contains("\\")||
content.contains(":") ||
content.contains("*") ||
content.contains("?") ||
content.contains("\"")||
content.contains("<") ||
content.contains(">") ||
content.contains("|"));
}
private class TagsTableModel extends AbstractTableModel {
private final ArrayList<TagName> tagNames = new ArrayList<>();
TagsTableModel(List<TagName> tagNames) {
for (TagName tagName : tagNames) {
this.tagNames.add(tagName);
}
}
@Override
public int getRowCount() {
return tagNames.size();
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
@Override
public int getColumnCount() {
return 1;
}
@Override
public String getValueAt(int rowIndex, int columnIndex) {
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
@@ -107,14 +165,14 @@ public class CreateTagDialog extends JDialog {
}
});
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.cancelButton.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.cancelButton.text")); // NOI18N
cancelButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cancelButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.okButton.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.okButton.text")); // NOI18N
okButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
okButtonActionPerformed(evt);
@@ -137,13 +195,13 @@ public class CreateTagDialog extends JDialog {
tagsTable.setTableHeader(null);
jScrollPane1.setViewportView(tagsTable);
org.openide.awt.Mnemonics.setLocalizedText(preexistingLabel, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.preexistingLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(preexistingLabel, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.preexistingLabel.text")); // NOI18N
newTagPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.newTagPanel.border.title"))); // NOI18N
newTagPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.newTagPanel.border.title"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(tagNameLabel, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.tagNameLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(tagNameLabel, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.tagNameLabel.text")); // NOI18N
tagNameField.setText(org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.tagNameField.text")); // NOI18N
tagNameField.setText(org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.tagNameField.text")); // NOI18N
tagNameField.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyReleased(java.awt.event.KeyEvent evt) {
tagNameFieldKeyReleased(evt);
@@ -211,20 +269,39 @@ public class CreateTagDialog extends JDialog {
}// </editor-fold>//GEN-END:initComponents
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
newTagName = null;
tagName = null;
dispose();
}//GEN-LAST:event_cancelButtonActionPerformed
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
String tagName = tagNameField.getText();
if (tagName.isEmpty()) {
String tagDisplayName = tagNameField.getText();
if (tagDisplayName.isEmpty()) {
JOptionPane.showMessageDialog(null, "Must supply a tag name to continue.", "Tag Name", JOptionPane.ERROR_MESSAGE);
} else if (containsIllegalCharacters(tagName)) {
JOptionPane.showMessageDialog(null, "The tag name contains illegal characters.\nCannot contain any of the following symbols: \\ : * ? \" < > |",
"Illegal Characters", JOptionPane.ERROR_MESSAGE);
} else {
newTagName = tagName;
dispose();
}
else if (containsIllegalCharacters(tagDisplayName)) {
JOptionPane.showMessageDialog(null, "The tag name contains illegal characters.\nCannot contain any of the following symbols: \\ : * ? \" < > |", "Illegal Characters", JOptionPane.ERROR_MESSAGE);
}
else {
tagName = tagNames.get(tagDisplayName);
if (tagName == null) {
try {
tagName = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName);
dispose();
}
catch (TskCoreException ex) {
Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex);
JOptionPane.showMessageDialog(null, "Unable to add the " + tagDisplayName + " tag name to the case.", "Tagging Error", JOptionPane.ERROR_MESSAGE);
tagName = null;
}
catch (TagsManager.TagNameAlreadyExistsException ex) {
Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex);
JOptionPane.showMessageDialog(null, "A " + tagDisplayName + " tag name has already been defined.", "Duplicate Tag Error", JOptionPane.ERROR_MESSAGE);
tagName = null;
}
}
else {
dispose();
}
}
}//GEN-LAST:event_okButtonActionPerformed
@@ -251,32 +328,5 @@ public class CreateTagDialog extends JDialog {
private javax.swing.JTable tagsTable;
// End of variables declaration//GEN-END:variables
private class TagsTableModel extends AbstractTableModel {
List<String> tagNames;
TagsTableModel() {
tagNames = new ArrayList<>(Tags.getAllTagNames());
}
@Override
public int getRowCount() {
return tagNames.size();
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
@Override
public int getColumnCount() {
return 1;
}
@Override
public String getValueAt(int rowIndex, int columnIndex) {
return tagNames.get(rowIndex);
}
}
}

View File

@@ -0,0 +1,62 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.actions;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
import org.sleuthkit.datamodel.BlackboardArtifact;
/**
* Abstract base class for Actions involving tags.
*/
public abstract class TagAction extends AbstractAction {
public TagAction(String menuText) {
super(menuText);
}
@Override
public void actionPerformed(ActionEvent event) {
doAction(event);
refreshDirectoryTree();
}
/**
* Derived classes must implement this Template Method for actionPerformed().
* @param event ActionEvent object passed to actionPerformed()
*/
abstract protected void doAction(ActionEvent event);
/**
* Derived classes should call this method any time a tag is created, updated
* or deleted outside of an actionPerformed() call.
*/
protected void refreshDirectoryTree() {
// The way the "directory tree" currently works, a new tags sub-tree
// needs to be made to reflect the results of invoking tag Actions. The
// way to do this is to call DirectoryTreeTopComponent.refreshTree(),
// which calls RootContentChildren.refreshKeys(BlackboardArtifact.ARTIFACT_TYPE... types)
// for the RootContentChildren object that is the child factory for the
// ResultsNode that is the root of the tags sub-tree. There is a switch
// statement in RootContentChildren.refreshKeys() that maps both
// BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE and BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT
// to making a call to refreshKey(TagsNodeKey).
DirectoryTreeTopComponent.findInstance().refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE);
}
}

View File

@@ -0,0 +1,358 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.casemodule;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.SleuthkitJNI;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskDataException;
import org.sleuthkit.datamodel.TskException;
/*
* A background task (swingworker) 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.
*/
public class AddImageTask implements Runnable {
private Logger logger = Logger.getLogger(AddImageTask.class.getName());
private Case currentCase;
// true if the process was requested to stop
private volatile boolean cancelled = false;
//true if revert has been invoked.
private boolean reverted = false;
private boolean hasCritError = false;
private volatile boolean addImageDone = false;
private List<String> errorList = new ArrayList<String>();
private DSPProgressMonitor progressMonitor;
private DSPCallback callbackObj;
private final List<Content> newContents = Collections.synchronizedList(new ArrayList<Content>());
private SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess;
private Thread dirFetcher;
private String imagePath;
private String dataSourcetype;
String timeZone;
boolean noFatOrphans;
/*
* A Swingworker that updates the progressMonitor with the name of the
* directory currently being processed by the AddImageTask
*/
private class CurrentDirectoryFetcher implements Runnable {
DSPProgressMonitor progressMonitor;
SleuthkitJNI.CaseDbHandle.AddImageProcess process;
CurrentDirectoryFetcher(DSPProgressMonitor aProgressMonitor, SleuthkitJNI.CaseDbHandle.AddImageProcess proc) {
this.progressMonitor = aProgressMonitor;
this.process = proc;
}
/**
* @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("Adding: " + currDir);
}
}
Thread.sleep(2 * 1000);
}
return;
} catch (InterruptedException ie) {
return;
}
}
}
protected AddImageTask(String imgPath, String tz, boolean noOrphans, DSPProgressMonitor aProgressMonitor, DSPCallback 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();
//lock DB for writes in this thread
SleuthkitCase.dbWriteLock();
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);
//critical core/system error and process needs to be interrupted
hasCritError = true;
errorList.add(ex.getMessage());
} catch (TskDataException ex) {
logger.log(Level.WARNING, "Data errors occurred while running add image. ", ex);
errorList.add(ex.getMessage());
}
finally {
}
// handle addImage done
postProcess();
// unclock the DB
SleuthkitCase.dbWriteUnlock();
return;
}
/**
* 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 (TskException e) {
logger.log(Level.WARNING, "Errors occured while committing the image", e);
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: " + imageId);
logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo());
}
}
/**
* Post processing after the addImageProcess is done.
*
*/
private void postProcess() {
// cancel the directory fetcher
dirFetcher.interrupt();
addImageDone = true;
// attempt actions that might fail and force the process to stop
if (cancelled || hasCritError) {
logger.log(Level.WARNING, "Critical errors or interruption in add image process. Image will not be comitted.");
revert();
}
if (!errorList.isEmpty()) {
logger.log(Level.INFO, "There were errors that occured in add image process");
}
// When everything happens without an error:
if (!(cancelled || hasCritError)) {
try {
// Tell the progress monitor we're done
progressMonitor.setProgress(100);
if (newContents.isEmpty()) {
if (addImageProcess != null) { // and if we're done configuring ingest
// commit anything
try {
commitImage();
} catch (Exception ex) {
errorList.add(ex.getMessage());
// Log error/display warning
logger.log(Level.SEVERE, "Error adding image to case.", ex);
}
} else {
logger.log(Level.SEVERE, "Missing image process object");
}
}
else { //already commited?
logger.log(Level.INFO, "Assuming image already committed, will not commit.");
}
} 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);
logger.log(Level.SEVERE, "Error adding image to case", ex);
} finally {
}
}
// invoke the callBack, unless the caller cancelled
if (!cancelled) {
doCallBack();
}
return;
}
/*
* Call the callback with results, new content, and errors, if any
*/
private void doCallBack()
{
DSPCallback.DSP_Result result;
if (hasCritError) {
result = DSPCallback.DSP_Result.CRITICAL_ERRORS;
}
else if (!errorList.isEmpty()) {
result = DSPCallback.DSP_Result.NONCRITICAL_ERRORS;
}
else {
result = DSPCallback.DSP_Result.NO_ERRORS;
}
// invoke the callcak, 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() {
cancelled = true;
if (!addImageDone) {
try {
interrupt();
}
catch (Exception ex) {
logger.log(Level.SEVERE, "Failed to interrup the add image task...");
}
}
else {
try {
revert();
}
catch(Exception ex) {
logger.log(Level.SEVERE, "Failed to revert the add image task...");
}
}
}
/*
* Interrurp the add image process if it is still running
*/
private void interrupt() throws Exception {
try {
logger.log(Level.INFO, "interrupt() add image process");
addImageProcess.stop(); //it might take time to truly stop processing and writing to db
} catch (TskException ex) {
throw new Exception("Error stopping add-image process.", ex);
}
}
/*
* Revert - if image has already been added but not committed yet
*/
void revert() {
if (!reverted) {
try {
logger.log(Level.INFO, "Revert after add image process");
try {
addImageProcess.revert();
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error reverting add image process", ex);
}
} finally {
}
reverted = true;
}
}
}

View File

@@ -18,7 +18,9 @@
*/
package org.sleuthkit.autopsy.casemodule;
import java.awt.Color;
import java.awt.EventQueue;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
@@ -27,6 +29,7 @@ import javax.swing.event.ChangeListener;
import org.openide.WizardDescriptor;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor;
/**
* The final panel of the add image wizard. It displays a progress bar and
@@ -50,6 +53,49 @@ class AddImageWizardAddingProgressPanel implements WizardDescriptor.FinishablePa
private AddImageWizardAddingProgressVisual component;
private final Set<ChangeListener> 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 DSPProgressMonitor {
@Override
public void setIndeterminate(final boolean 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);
}
});
}
@Override
public void setProgressText(final String text) {
// update the progress UI asynchronously
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

View File

@@ -40,7 +40,7 @@
<Component id="inProgressPanel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="donePanel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="69" max="32767" attributes="0"/>
<EmptySpace min="0" pref="67" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@@ -136,16 +136,19 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="subTitle2Label" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="32767" attributes="0"/>
<Component id="progressBar" min="-2" pref="475" max="-2" attributes="1"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" max="-2" attributes="0">
<Component id="progressTextArea" max="32767" attributes="0"/>
<Component id="progressLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="subTitle1Label" alignment="0" max="32767" attributes="1"/>
<Component id="TextArea_CurrentDirectory" alignment="0" max="32767" attributes="0"/>
<Component id="progressBar" alignment="0" max="32767" attributes="1"/>
</Group>
<EmptySpace min="0" pref="8" max="32767" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@@ -153,12 +156,10 @@
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="subTitle1Label" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Component id="subTitle2Label" min="-2" pref="14" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<EmptySpace min="-2" pref="19" max="-2" attributes="0"/>
<Component id="progressBar" min="-2" pref="23" max="-2" attributes="1"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="TextArea_CurrentDirectory" min="-2" pref="91" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="progressTextArea" min="-2" pref="91" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="progressLabel" min="-2" pref="23" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
@@ -185,7 +186,7 @@
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="4"/>
</AuxValues>
</Component>
<Component class="javax.swing.JTextArea" name="TextArea_CurrentDirectory">
<Component class="javax.swing.JTextArea" name="progressTextArea">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
@@ -196,11 +197,11 @@
<Property name="wrapStyleWord" type="boolean" value="true"/>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Currently Adding:">
<TitledBorder title="Status">
<Border PropertyName="innerBorder" info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
<EtchetBorder/>
</Border>
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="AddImageWizardAddingProgressVisual.TextArea_CurrentDirectory.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="AddImageWizardAddingProgressVisual.progressTextArea.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
@@ -213,16 +214,6 @@
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="4"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="subTitle2Label">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="AddImageWizardAddingProgressVisual.subTitle2Label.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="4"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="subTitle1Label">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">

View File

@@ -71,7 +71,7 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
donePanel.setVisible(false);
viewLogButton.setVisible(false);
//match visual background of panel
this.TextArea_CurrentDirectory.setBackground(this.getBackground());
this.progressTextArea.setBackground(this.getBackground());
}
@@ -95,10 +95,10 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
/**
* Updates the currently processing directory
*
* @param dir the text to update with
* @param msg the text to update with
*/
public void setCurrentDirText(String dir) {
this.TextArea_CurrentDirectory.setText(dir);
public void setProgressMsgText(String msg) {
this.progressTextArea.setText(msg);
}
/**
@@ -114,8 +114,10 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
//progressBar.setValue(100); //always invoked when process completed
if (hasCriticalErrors) {
statusLabel.setText("*Failed to add image (critical errors encountered). Click below to view the log.");
statusLabel.setForeground(Color.RED);
statusLabel.setText("*Failed to add data source (critical errors encountered). Click below to view the log.");
} else {
statusLabel.setForeground(Color.BLACK);
statusLabel.setText("*Data Source added (non-critical errors encountered). Click below to view the log.");
}
@@ -140,8 +142,7 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
inProgressPanel = new javax.swing.JPanel();
progressBar = new javax.swing.JProgressBar();
progressLabel = new javax.swing.JLabel();
TextArea_CurrentDirectory = new javax.swing.JTextArea();
subTitle2Label = new javax.swing.JLabel();
progressTextArea = new javax.swing.JTextArea();
subTitle1Label = new javax.swing.JLabel();
javax.swing.GroupLayout loadingPanelLayout = new javax.swing.GroupLayout(loadingPanel);
@@ -193,16 +194,14 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
org.openide.awt.Mnemonics.setLocalizedText(progressLabel, org.openide.util.NbBundle.getMessage(AddImageWizardAddingProgressVisual.class, "AddImageWizardAddingProgressVisual.progressLabel.text")); // NOI18N
progressLabel.setPreferredSize(null);
TextArea_CurrentDirectory.setEditable(false);
TextArea_CurrentDirectory.setBackground(new java.awt.Color(240, 240, 240));
TextArea_CurrentDirectory.setLineWrap(true);
TextArea_CurrentDirectory.setRows(5);
TextArea_CurrentDirectory.setWrapStyleWord(true);
TextArea_CurrentDirectory.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), org.openide.util.NbBundle.getMessage(AddImageWizardAddingProgressVisual.class, "AddImageWizardAddingProgressVisual.TextArea_CurrentDirectory.border.title"))); // NOI18N
TextArea_CurrentDirectory.setCursor(new java.awt.Cursor(java.awt.Cursor.TEXT_CURSOR));
TextArea_CurrentDirectory.setFocusable(false);
org.openide.awt.Mnemonics.setLocalizedText(subTitle2Label, org.openide.util.NbBundle.getMessage(AddImageWizardAddingProgressVisual.class, "AddImageWizardAddingProgressVisual.subTitle2Label.text")); // NOI18N
progressTextArea.setEditable(false);
progressTextArea.setBackground(new java.awt.Color(240, 240, 240));
progressTextArea.setLineWrap(true);
progressTextArea.setRows(5);
progressTextArea.setWrapStyleWord(true);
progressTextArea.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), org.openide.util.NbBundle.getMessage(AddImageWizardAddingProgressVisual.class, "AddImageWizardAddingProgressVisual.progressTextArea.border.title"))); // NOI18N
progressTextArea.setCursor(new java.awt.Cursor(java.awt.Cursor.TEXT_CURSOR));
progressTextArea.setFocusable(false);
org.openide.awt.Mnemonics.setLocalizedText(subTitle1Label, org.openide.util.NbBundle.getMessage(AddImageWizardAddingProgressVisual.class, "AddImageWizardAddingProgressVisual.subTitle1Label.text")); // NOI18N
@@ -210,26 +209,26 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
inProgressPanel.setLayout(inProgressPanelLayout);
inProgressPanelLayout.setHorizontalGroup(
inProgressPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, inProgressPanelLayout.createSequentialGroup()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, 475, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
.addGroup(inProgressPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(inProgressPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(subTitle2Label)
.addComponent(progressLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(subTitle1Label, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(TextArea_CurrentDirectory)
.addComponent(progressBar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGap(0, 8, Short.MAX_VALUE))
.addGroup(inProgressPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(progressTextArea)
.addComponent(progressLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(subTitle1Label, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGap(0, 0, Short.MAX_VALUE))
);
inProgressPanelLayout.setVerticalGroup(
inProgressPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(inProgressPanelLayout.createSequentialGroup()
.addComponent(subTitle1Label)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(subTitle2Label, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGap(19, 19, 19)
.addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(TextArea_CurrentDirectory, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(progressTextArea, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(progressLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
@@ -245,7 +244,7 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
.addComponent(titleLabel)
.addComponent(inProgressPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(donePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(0, 69, Short.MAX_VALUE))
.addGap(0, 67, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@@ -268,15 +267,14 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
dialog.setVisible(true);
}//GEN-LAST:event_viewLogButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
protected javax.swing.JTextArea TextArea_CurrentDirectory;
protected javax.swing.JPanel donePanel;
protected javax.swing.JPanel inProgressPanel;
private javax.swing.JPanel loadingPanel;
private javax.swing.JProgressBar progressBar;
protected javax.swing.JLabel progressLabel;
protected javax.swing.JTextArea progressTextArea;
protected javax.swing.JLabel statusLabel;
protected javax.swing.JLabel subTitle1Label;
protected javax.swing.JLabel subTitle2Label;
protected javax.swing.JLabel titleLabel;
protected javax.swing.JButton viewLogButton;
// End of variables declaration//GEN-END:variables

View File

@@ -43,6 +43,7 @@ class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel<Wiza
* The visual component that displays this panel. If you need to access the
* component from this class, just use getComponent().
*/
private AddImageWizardAddingProgressPanel progressPanel;
private AddImageWizardChooseDataSourceVisual component;
private boolean isNextEnable = false;
private static final String PROP_LASTDATASOURCE_PATH = "LBL_LastDataSource_PATH";
@@ -50,6 +51,12 @@ class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel<Wiza
// paths to any set hash lookup databases (can be null)
private String NSRLPath, knownBadPath;
AddImageWizardChooseDataSourcePanel(AddImageWizardAddingProgressPanel proPanel) {
this.progressPanel = proPanel;
}
/**
* 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
@@ -173,13 +180,6 @@ class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel<Wiza
// Prepopulate the image directory from the properties file
try {
String lastDataSourceDirectory = ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, PROP_LASTDATASOURCE_PATH);
String lastDataSourceType = ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, PROP_LASTDATASOURCE_TYPE);
//set the last path for the content panel for which it was saved
if (component.getContentType().toString().equals(lastDataSourceType)) {
component.setContentPath(lastDataSourceDirectory);
}
// Load hash database settings, enable or disable the checkbox
this.NSRLPath = null;
@@ -216,19 +216,8 @@ class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel<Wiza
*/
@Override
public void storeSettings(WizardDescriptor settings) {
settings.putProperty(AddImageAction.DATASOURCEPATH_PROP, getComponent().getContentPaths());
settings.putProperty(AddImageAction.DATASOURCETYPE_PROP, getComponent().getContentType());
settings.putProperty(AddImageAction.TIMEZONE_PROP, getComponent().getSelectedTimezone()); // store the timezone
settings.putProperty(AddImageAction.NOFATORPHANS_PROP, Boolean.valueOf(getComponent().getNoFatOrphans()));
//settings.putProperty(AddImageAction.LOOKUPFILES_PROP, getComponent().getLookupFilesCheckboxChecked());
//settings.putProperty(AddImageAction.SOLR_PROP, getComponent().getIndexImageCheckboxChecked());
// Store the path to the first image selected into the properties file
String firstImage = getComponent().getContentPaths();
String firstImagePath = firstImage.substring(0, firstImage.lastIndexOf(File.separator) + 1);
ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, PROP_LASTDATASOURCE_PATH, firstImagePath);
ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, PROP_LASTDATASOURCE_TYPE, getComponent().getContentType().toString());
return;
}
/**

View File

@@ -39,16 +39,6 @@
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="nextLabel" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="timeZoneLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="timeZoneComboBox" min="-2" pref="252" max="-2" attributes="0"/>
</Group>
<Component id="noFatOrphansCheckbox" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="21" pref="21" max="-2" attributes="0"/>
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="imgInfoLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="54" max="32767" attributes="0"/>
@@ -65,16 +55,7 @@
<Component id="imgInfoLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="inputPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="timeZoneLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="timeZoneComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="noFatOrphansCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="64" max="32767" attributes="0"/>
<EmptySpace pref="45" max="32767" attributes="0"/>
<Component id="nextLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
</Group>
@@ -89,41 +70,6 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="timeZoneLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="AddImageWizardChooseDataSourceVisual.timeZoneLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="timeZoneComboBox">
<Properties>
<Property name="maximumRowCount" type="int" value="30"/>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
<Component class="javax.swing.JCheckBox" name="noFatOrphansCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="descLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="AddImageWizardChooseDataSourceVisual.descLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JPanel" name="inputPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
@@ -160,7 +106,7 @@
<Component id="typeComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="typePanel" pref="77" max="32767" attributes="0"/>
<Component id="typePanel" pref="173" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
@@ -192,7 +138,7 @@
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="77" max="32767" attributes="0"/>
<EmptySpace min="0" pref="173" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
@@ -204,7 +150,7 @@
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;ContentTypePanel&gt;"/>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
</SubComponents>

View File

@@ -18,49 +18,44 @@
*/
package org.sleuthkit.autopsy.casemodule;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Component;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import javax.swing.ComboBoxModel;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import javax.swing.JPanel;
import javax.swing.JList;
import javax.swing.JSeparator;
import javax.swing.event.DocumentEvent;
import javax.swing.event.ListDataListener;
import org.sleuthkit.autopsy.casemodule.ContentTypePanel.ContentType;
import javax.swing.ListCellRenderer;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
/**
* visual component for the first panel of add image wizard. Allows user to pick
* data source and timezone.
* visual component for the first panel of add image wizard.
* Allows the user to choose the data source type and then select the data source
*
*/
final class AddImageWizardChooseDataSourceVisual extends JPanel {
enum EVENT {
UPDATE_UI, FOCUS_NEXT
};
static final List<String> rawExt = Arrays.asList(new String[]{".img", ".dd", ".001", ".aa", ".raw"});
static final String rawDesc = "Raw Images (*.img, *.dd, *.001, *.aa, *.raw)";
static GeneralFilter rawFilter = new GeneralFilter(rawExt, rawDesc);
static final List<String> encaseExt = Arrays.asList(new String[]{".e01"});
static final String encaseDesc = "Encase Images (*.e01)";
static GeneralFilter encaseFilter = new GeneralFilter(encaseExt, encaseDesc);
static final List<String> allExt = new ArrayList<String>();
static {
allExt.addAll(rawExt);
allExt.addAll(encaseExt);
}
static final String allDesc = "All Supported Types";
static GeneralFilter allFilter = new GeneralFilter(allExt, allDesc);
static final Logger logger = Logger.getLogger(AddImageWizardChooseDataSourceVisual.class.getName());
private AddImageWizardChooseDataSourcePanel wizPanel;
private ContentTypeModel model;
private ContentTypePanel currentPanel;
private JPanel currentPanel;
private Map<String, DataSourceProcessor> datasourceProcessorsMap = new HashMap<String, DataSourceProcessor>();
List<String> coreDSPTypes = new ArrayList<String>();
/**
* Creates new form AddImageVisualPanel1
@@ -70,24 +65,83 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
AddImageWizardChooseDataSourceVisual(AddImageWizardChooseDataSourcePanel wizPanel) {
initComponents();
this.wizPanel = wizPanel;
createTimeZoneList();
customInit();
}
private void customInit() {
model = new ContentTypeModel();
typeComboBox.setModel(model);
typeComboBox.setSelectedIndex(0);
typePanel.setLayout(new BorderLayout());
updateCurrentPanel(ImageFilePanel.getDefault());
discoverDataSourceProcessors();
// set up the DSP type combobox
typeComboBox.removeAllItems();
Set<String> dspTypes = datasourceProcessorsMap.keySet();
// make a list of core DSPs
// ensure that the core DSPs are at the top and in a fixed order
coreDSPTypes.add(ImageDSProcessor.dsType);
coreDSPTypes.add(LocalDiskDSProcessor.dsType);
coreDSPTypes.add(LocalFilesDSProcessor.dsType);
for(String dspType:coreDSPTypes){
typeComboBox.addItem(dspType);
}
// now add any addtional DSPs that haven't already been added
for(String dspType:dspTypes){
if (!coreDSPTypes.contains(dspType)) {
typeComboBox.addItem(dspType);
}
}
// set a custom renderer that draws a separator at the end of the core DSPs in the combobox
typeComboBox.setRenderer(new ComboboxSeparatorRenderer(typeComboBox.getRenderer()){
@Override
protected boolean addSeparatorAfter(JList list, Object value, int index){
return (index == coreDSPTypes.size() - 1);
}
});
//add actionlistner to listen for change
ActionListener cbActionListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dspSelectionChanged();
}
};
typeComboBox.addActionListener(cbActionListener);
typeComboBox.setSelectedIndex(0);
}
private void discoverDataSourceProcessors() {
for (DataSourceProcessor dsProcessor: Lookup.getDefault().lookupAll(DataSourceProcessor.class)) {
if (!datasourceProcessorsMap.containsKey(dsProcessor.getType()) ) {
dsProcessor.reset();
datasourceProcessorsMap.put(dsProcessor.getType(), dsProcessor);
}
else {
logger.log(Level.SEVERE, "discoverDataSourceProcessors(): A DataSourceProcessor already exists for type = " + dsProcessor.getType() );
}
}
}
private void dspSelectionChanged() {
// update the current panel to selection
currentPanel = getCurrentDSProcessor().getPanel();
updateCurrentPanel(currentPanel);
}
/**
* Changes the current panel to the given panel.
*
* @param panel instance of ImageTypePanel to change to
*/
private void updateCurrentPanel(ContentTypePanel panel) {
private void updateCurrentPanel(JPanel panel) {
currentPanel = panel;
typePanel.removeAll();
typePanel.add((JPanel) currentPanel, BorderLayout.CENTER);
@@ -96,28 +150,32 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
currentPanel.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString())) {
if (evt.getPropertyName().equals(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString())) {
updateUI(null);
}
if (evt.getPropertyName().equals(AddImageWizardChooseDataSourceVisual.EVENT.FOCUS_NEXT.toString())) {
if (evt.getPropertyName().equals(DataSourceProcessor.DSP_PANEL_EVENT.FOCUS_NEXT.toString())) {
wizPanel.moveFocusToNext();
}
}
});
currentPanel.select();
if (currentPanel.getContentType().equals(ContentType.LOCAL)) {
//disable image specific options
noFatOrphansCheckbox.setEnabled(false);
descLabel.setEnabled(false);
timeZoneComboBox.setEnabled(false);
} else {
noFatOrphansCheckbox.setEnabled(true);
descLabel.setEnabled(true);
timeZoneComboBox.setEnabled(true);
}
updateUI(null);
}
/**
* Returns the currently selected DS Processor
* @return DataSourceProcessor the DataSourceProcessor corresponding to the data source type selected in the combobox
*/
public DataSourceProcessor getCurrentDSProcessor() {
// get the type of the currently selected panel and then look up
// the correspodning DS Handler in the map
String dsType = (String) typeComboBox.getSelectedItem();
DataSourceProcessor dsProcessor = datasourceProcessorsMap.get(dsType);
return dsProcessor;
}
/**
* Returns the name of the this panel. This name will be shown on the left
* panel of the "Add Image" wizard panel.
@@ -129,94 +187,6 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
return "Enter Data Source Information";
}
/**
* Gets the data sources path from the Image Path Text Field.
*
* @return data source path, can be comma separated for multiples
*/
public String getContentPaths() {
return currentPanel.getContentPaths();
}
/**
* Gets the data sources type selected
*
* @return data source selected
*/
public ContentType getContentType() {
return currentPanel.getContentType();
}
/**
* Reset the data sources panel selected
*/
public void reset() {
currentPanel.reset();
}
/**
* Sets the image path of the current panel.
*
* @param s the image path to set
*/
public void setContentPath(String s) {
currentPanel.setContentPath(s);
}
/**
*
* @return true if no fat orphans processing is selected
*/
boolean getNoFatOrphans() {
return noFatOrphansCheckbox.isSelected();
}
/**
* Gets the time zone that selected on the drop down list.
*
* @return timeZone the time zone that selected
*/
public String getSelectedTimezone() {
String tz = timeZoneComboBox.getSelectedItem().toString();
return tz.substring(tz.indexOf(")") + 2).trim();
}
// add the timeZone list to the timeZoneComboBox
/**
* Creates the drop down list for the time zones and then makes the local
* machine time zones to be selected.
*/
public void createTimeZoneList() {
// load and add all timezone
String[] ids = SimpleTimeZone.getAvailableIDs();
for (String id : ids) {
TimeZone zone = TimeZone.getTimeZone(id);
int offset = zone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = (offset % 3600) / 60;
String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id);
/*
* DateFormat dfm = new SimpleDateFormat("z");
* dfm.setTimeZone(zone); boolean hasDaylight =
* zone.useDaylightTime(); String first = dfm.format(new Date(2010,
* 1, 1)); String second = dfm.format(new Date(2011, 6, 6)); int mid
* = hour * -1; String result = first + Integer.toString(mid);
* if(hasDaylight){ result = result + second; }
* timeZoneComboBox.addItem(item + " (" + result + ")");
*/
timeZoneComboBox.addItem(item);
}
// get the current timezone
TimeZone thisTimeZone = Calendar.getInstance().getTimeZone();
int thisOffset = thisTimeZone.getRawOffset() / 1000;
int thisHour = thisOffset / 3600;
int thisMinutes = (thisOffset % 3600) / 60;
String formatted = String.format("(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID());
// set the selected timezone
timeZoneComboBox.setSelectedItem(formatted);
}
/**
* This method is called from within the constructor to initialize the form.
@@ -229,14 +199,10 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
buttonGroup1 = new javax.swing.ButtonGroup();
jLabel2 = new javax.swing.JLabel();
nextLabel = new javax.swing.JLabel();
timeZoneLabel = new javax.swing.JLabel();
timeZoneComboBox = new javax.swing.JComboBox<String>();
noFatOrphansCheckbox = new javax.swing.JCheckBox();
descLabel = new javax.swing.JLabel();
inputPanel = new javax.swing.JPanel();
typeTabel = new javax.swing.JLabel();
typePanel = new javax.swing.JPanel();
typeComboBox = new javax.swing.JComboBox<ContentTypePanel>();
typeComboBox = new javax.swing.JComboBox<String>();
imgInfoLabel = new javax.swing.JLabel();
org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.jLabel2.text")); // NOI18N
@@ -245,15 +211,6 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
org.openide.awt.Mnemonics.setLocalizedText(nextLabel, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.nextLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(timeZoneLabel, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.timeZoneLabel.text")); // NOI18N
timeZoneComboBox.setMaximumRowCount(30);
org.openide.awt.Mnemonics.setLocalizedText(noFatOrphansCheckbox, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.text")); // NOI18N
noFatOrphansCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.toolTipText")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(descLabel, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.descLabel.text")); // NOI18N
inputPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
org.openide.awt.Mnemonics.setLocalizedText(typeTabel, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.typeTabel.text")); // NOI18N
@@ -269,7 +226,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
);
typePanelLayout.setVerticalGroup(
typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 77, Short.MAX_VALUE)
.addGap(0, 173, Short.MAX_VALUE)
);
javax.swing.GroupLayout inputPanelLayout = new javax.swing.GroupLayout(inputPanel);
@@ -295,7 +252,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
.addComponent(typeTabel)
.addComponent(typeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(typePanel, javax.swing.GroupLayout.DEFAULT_SIZE, 77, Short.MAX_VALUE)
.addComponent(typePanel, javax.swing.GroupLayout.DEFAULT_SIZE, 173, Short.MAX_VALUE)
.addContainerGap())
);
@@ -313,14 +270,6 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(nextLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(layout.createSequentialGroup()
.addComponent(timeZoneLabel)
.addGap(18, 18, 18)
.addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 252, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(noFatOrphansCheckbox)
.addGroup(layout.createSequentialGroup()
.addGap(21, 21, 21)
.addComponent(descLabel))
.addComponent(imgInfoLabel))
.addGap(0, 54, Short.MAX_VALUE)))
.addContainerGap())
@@ -332,30 +281,18 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
.addComponent(imgInfoLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(inputPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(timeZoneLabel)
.addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(noFatOrphansCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(descLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 64, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 45, Short.MAX_VALUE)
.addComponent(nextLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0))
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.ButtonGroup buttonGroup1;
private javax.swing.JLabel descLabel;
private javax.swing.JLabel imgInfoLabel;
private javax.swing.JPanel inputPanel;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel nextLabel;
private javax.swing.JCheckBox noFatOrphansCheckbox;
private javax.swing.JComboBox<String> timeZoneComboBox;
private javax.swing.JLabel timeZoneLabel;
private javax.swing.JComboBox<ContentTypePanel> typeComboBox;
private javax.swing.JComboBox<String> typeComboBox;
private javax.swing.JPanel typePanel;
private javax.swing.JLabel typeTabel;
// End of variables declaration//GEN-END:variables
@@ -369,44 +306,31 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
* @param e the document event
*/
public void updateUI(DocumentEvent e) {
this.wizPanel.enableNextButton(currentPanel.enableNext());
// Enable the Next button if the current DSP panel is valid
this.wizPanel.enableNextButton(getCurrentDSProcessor().validatePanel());
}
/**
* ComboBoxModel to control typeComboBox and supply ImageTypePanels.
*/
private class ContentTypeModel implements ComboBoxModel<ContentTypePanel> {
public abstract class ComboboxSeparatorRenderer implements ListCellRenderer{
private ListCellRenderer delegate;
private JPanel separatorPanel = new JPanel(new BorderLayout());
private JSeparator separator = new JSeparator();
private ContentTypePanel selected;
private ContentTypePanel[] types = ContentTypePanel.getPanels();
@Override
public void setSelectedItem(Object anItem) {
selected = (ContentTypePanel) anItem;
updateCurrentPanel(selected);
public ComboboxSeparatorRenderer(ListCellRenderer delegate){
this.delegate = delegate;
}
@Override
public Object getSelectedItem() {
return selected;
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus){
Component comp = delegate.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if(index!=-1 && addSeparatorAfter(list, value, index)){
separatorPanel.removeAll();
separatorPanel.add(comp, BorderLayout.CENTER);
separatorPanel.add(separator, BorderLayout.SOUTH);
return separatorPanel;
}else
return comp;
}
@Override
public int getSize() {
return types.length;
}
@Override
public ContentTypePanel getElementAt(int index) {
return types[index];
}
@Override
public void addListDataListener(ListDataListener l) {
}
@Override
public void removeListDataListener(ListDataListener l) {
}
protected abstract boolean addSeparatorAfter(JList list, Object value, int index);
}
}

View File

@@ -18,41 +18,25 @@
*/
package org.sleuthkit.autopsy.casemodule;
import org.sleuthkit.autopsy.ingest.IngestConfigurator;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Window;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.event.ChangeListener;
import org.openide.WizardDescriptor;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.casemodule.ContentTypePanel.ContentType;
import org.sleuthkit.autopsy.casemodule.services.FileManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.FileSystem;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.SleuthkitJNI.CaseDbHandle.AddImageProcess;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskDataException;
import org.sleuthkit.datamodel.TskException;
import org.sleuthkit.datamodel.Volume;
import org.sleuthkit.datamodel.VolumeSystem;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
/**
* second panel of add image wizard, allows user to configure ingest modules.
*
@@ -68,28 +52,27 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
* component from this class, just use getComponent().
*/
private Component component = null;
private final List<Content> newContents = Collections.synchronizedList(new ArrayList<Content>());
private boolean ingested = false;
private boolean readyToIngest = false;
// the paths of the image files to be added
private String dataSourcePath;
private ContentType dataSourceType;
// the time zone where the image is added
private String timeZone;
//whether to not process FAT filesystem orphans
private boolean noFatOrphans;
// task that will clean up the created database file if the wizard is cancelled before it finishes
private AddImageAction.CleanupTask cleanupImage; // initialized to null in readSettings()
private CurrentDirectoryFetcher fetcher;
private AddImageProcess process;
private AddImageAction action;
private AddImageTask addImageTask;
private AddLocalFilesTask addLocalFilesTask;
private AddImageAction.CleanupTask cleanupTask;
private AddImageAction addImageAction;
private AddImageWizardAddingProgressPanel progressPanel;
private AddImageWizardChooseDataSourcePanel dataSourcePanel;
private DataSourceProcessor dsProcessor;
AddImageWizardIngestConfigPanel(AddImageAction action, AddImageWizardAddingProgressPanel proPanel) {
this.action = action;
AddImageWizardIngestConfigPanel(AddImageWizardChooseDataSourcePanel dsPanel, AddImageAction action, AddImageWizardAddingProgressPanel proPanel) {
this.addImageAction = action;
this.progressPanel = proPanel;
this.dataSourcePanel = dsPanel;
ingestConfig = Lookup.getDefault().lookup(IngestConfigurator.class);
List<String> messages = ingestConfig.setContext(AddImageWizardIngestConfigPanel.class.getCanonicalName());
if (messages.isEmpty() == false) {
@@ -183,24 +166,14 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
JButton cancel = new JButton("Cancel");
cancel.setEnabled(false);
settings.setOptions(new Object[]{WizardDescriptor.PREVIOUS_OPTION, WizardDescriptor.NEXT_OPTION, WizardDescriptor.FINISH_OPTION, cancel});
cleanupImage = null;
cleanupTask = null;
readyToIngest = false;
newContents.clear();
dataSourcePath = (String) settings.getProperty(AddImageAction.DATASOURCEPATH_PROP);
dataSourceType = (ContentType) settings.getProperty(AddImageAction.DATASOURCETYPE_PROP);
timeZone = settings.getProperty(AddImageAction.TIMEZONE_PROP).toString();
noFatOrphans = ((Boolean) settings.getProperty(AddImageAction.NOFATORPHANS_PROP)).booleanValue();
//start the process of adding the content
if (dataSourceType.equals(ContentType.LOCAL)) {
addLocalFilesTask = new AddLocalFilesTask(settings);
addLocalFilesTask.execute();
} else {
//disk or image
addImageTask = new AddImageTask(settings);
addImageTask.execute();
}
// Start processing the data source by handing it off to the selected DSP,
// so it gets going in the background while the user is still picking the Ingest modules
startDataSourceProcessing(settings);
}
/**
@@ -234,470 +207,102 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
}
}
/**
* Class for getting the currently processing directory.
*
/**
* Starts the Data source processing by kicking off the selected DataSourceProcessor
*/
private static class CurrentDirectoryFetcher extends SwingWorker<Integer, Integer> {
AddImageTask task;
JProgressBar prog;
AddImageWizardAddingProgressVisual wiz;
AddImageProcess proc;
CurrentDirectoryFetcher(JProgressBar prog, AddImageWizardAddingProgressVisual wiz, AddImageProcess proc) {
this.wiz = wiz;
this.proc = proc;
this.prog = prog;
}
/**
* @return the currently processing directory
*/
@Override
protected Integer doInBackground() {
try {
while (prog.getValue() < 100 || prog.isIndeterminate()) { //TODO Rely on state variable in AddImgTask class
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
wiz.setCurrentDirText(proc.currentDirectory());
}
});
Thread.sleep(2 * 1000);
}
return 1;
} catch (InterruptedException ie) {
return -1;
}
}
}
/**
* Thread that will add logical files to database, and then kick-off ingest
* modules. Note: the add logical files task cannot currently be reverted as
* the add image task can. This is a separate task from AddImgTask because
* it is much simpler and does not require locks, since the underlying file
* manager methods acquire the locks for each transaction when adding
* logical files.
*/
private class AddLocalFilesTask extends SwingWorker<Integer, Integer> {
private JProgressBar progressBar;
private Case currentCase;
// true if the process was requested to stop
private boolean interrupted = false;
private boolean hasCritError = false;
private String errorString = null;
private WizardDescriptor settings;
private Logger logger = Logger.getLogger(AddLocalFilesTask.class.getName());
protected AddLocalFilesTask(WizardDescriptor settings) {
this.progressBar = progressPanel.getComponent().getProgressBar();
currentCase = Case.getCurrentCase();
this.settings = settings;
}
/**
* Starts the addImage process, but does not commit the results.
*
* @return
*
* @throws Exception
*/
@Override
protected Integer doInBackground() {
this.setProgress(0);
// Add a cleanup task to interupt the backgroud process if the
// wizard exits while the background process is running.
AddImageAction.CleanupTask cancelledWhileRunning = action.new CleanupTask() {
@Override
void cleanup() throws Exception {
logger.log(Level.INFO, "Add logical files process interrupted.");
//nothing to be cleanedup
}
};
cancelledWhileRunning.enable();
final LocalFilesAddProgressUpdater progUpdater = new LocalFilesAddProgressUpdater(this.progressBar, progressPanel.getComponent());
try {
final FileManager fileManager = currentCase.getServices().getFileManager();
progressPanel.setStateStarted();
String[] paths = dataSourcePath.split(LocalFilesPanel.FILES_SEP);
List<String> absLocalPaths = new ArrayList<String>();
for (String path : paths) {
absLocalPaths.add(path);
}
newContents.add(fileManager.addLocalFilesDirs(absLocalPaths, progUpdater));
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Errors occurred while running add logical files. ", ex);
hasCritError = true;
errorString = ex.getMessage();
} finally {
// process is over, doesn't need to be dealt with if cancel happens
cancelledWhileRunning.disable();
//enqueue what would be in done() to EDT thread
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
postProcess();
}
});
}
return 0;
}
/**
*
* (called by EventDispatch Thread after doInBackground finishes)
*/
protected void postProcess() {
progressBar.setIndeterminate(false);
setProgress(100);
//clear updates
// progressPanel.getComponent().setProcessInvis();
if (interrupted || hasCritError) {
logger.log(Level.INFO, "Handling errors or interruption that occured in logical files process");
if (hasCritError) {
//core error
progressPanel.getComponent().showErrors(errorString, true);
}
return;
} else {
if (errorString != null) {
//data error (non-critical)
logger.log(Level.INFO, "Handling non-critical errors that occured in logical files process");
progressPanel.getComponent().showErrors(errorString, false);
}
}
try {
// When everything happens without an error:
if (errorString == null) { // complete progress bar
progressPanel.getComponent().setProgressBarTextAndColor("*Logical Files added.", 100, Color.black);
}
// Get attention for the process finish
java.awt.Toolkit.getDefaultToolkit().beep(); //BEEP!
AddImageWizardAddingProgressVisual panel = progressPanel.getComponent();
if (panel != null) {
Window w = SwingUtilities.getWindowAncestor(panel);
if (w != null) {
w.toFront();
}
}
progressPanel.setStateFinished();
//notify the case
if (!newContents.isEmpty()) {
Case.getCurrentCase().addLocalDataSource(newContents.get(0));
}
// Start ingest if we can
startIngest();
} catch (Exception ex) {
//handle unchecked exceptions
logger.log(Level.WARNING, "Unexpected errors occurred while running post add image cleanup. ", ex);
progressPanel.getComponent().setProgressBarTextAndColor("*Failed to add image.", 0, Color.black); // set error message
logger.log(Level.SEVERE, "Error adding image to case", ex);
}
}
/**
* Updates the wizard status with logical file/folder
*/
private class LocalFilesAddProgressUpdater implements FileManager.FileAddProgressUpdater {
private int count = 0;
private JProgressBar prog;
private AddImageWizardAddingProgressVisual wiz;
LocalFilesAddProgressUpdater(JProgressBar prog, AddImageWizardAddingProgressVisual wiz) {
this.wiz = wiz;
this.prog = prog;
}
private void startDataSourceProcessing(WizardDescriptor settings) {
// Add a cleanup task to interrupt the background process if the
// wizard exits while the background process is running.
cleanupTask = addImageAction.new CleanupTask() {
@Override
public void fileAdded(final AbstractFile newFile) {
if (count++ % 10 == 0 && (prog.getValue() < 100 || prog.isIndeterminate())) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
wiz.setCurrentDirText(newFile.getParentPath() + "/" + newFile.getName());
}
});
}
void cleanup() throws Exception {
cancelDataSourceProcessing();
}
}
};
cleanupTask.enable();
// get the selected DSProcessor
dsProcessor = dataSourcePanel.getComponent().getCurrentDSProcessor();
DSPCallback cbObj = new DSPCallback () {
@Override
public void doneEDT(DSPCallback.DSP_Result result, List<String> errList, List<Content> contents) {
dataSourceProcessorDone(result, errList, contents );
}
};
progressPanel.setStateStarted();
// Kick off the DSProcessor
dsProcessor.run(progressPanel.getDSPProgressMonitorImpl(), cbObj);
}
/**
* Thread that will make the JNI call to add image to database, and then
* kick-off ingest modules.
/*
* Cancels the data source processing - in case the users presses 'Cancel'
*/
private class AddImageTask extends SwingWorker<Integer, Integer> {
private JProgressBar progressBar;
private Case currentCase;
// true if the process was requested to stop
private boolean interrupted = false;
private boolean hasCritError = false;
private String errorString = null;
private WizardDescriptor wizDescriptor;
private Logger logger = Logger.getLogger(AddImageTask.class.getName());
protected AddImageTask(WizardDescriptor settings) {
this.progressBar = progressPanel.getComponent().getProgressBar();
currentCase = Case.getCurrentCase();
this.wizDescriptor = settings;
}
/**
* Starts the addImage process, but does not commit the results.
*
* @return
*
* @throws Exception
*/
@Override
protected Integer doInBackground() {
this.setProgress(0);
// Add a cleanup task to interupt the backgroud process if the
// wizard exits while the background process is running.
AddImageAction.CleanupTask cancelledWhileRunning = action.new CleanupTask() {
@Override
void cleanup() throws Exception {
logger.log(Level.INFO, "Add image process interrupted.");
addImageTask.interrupt(); //it might take time to truly interrupt
}
};
try {
//lock DB for writes in EWT thread
//wait until lock acquired in EWT
EventQueue.invokeAndWait(new Runnable() {
@Override
public void run() {
SleuthkitCase.dbWriteLock();
}
});
} catch (InterruptedException ex) {
logger.log(Level.WARNING, "Errors occurred while running add image, could not acquire lock. ", ex);
return 0;
} catch (InvocationTargetException ex) {
logger.log(Level.WARNING, "Errors occurred while running add image, could not acquire lock. ", ex);
return 0;
}
process = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans);
fetcher = new CurrentDirectoryFetcher(this.progressBar, progressPanel.getComponent(), process);
cancelledWhileRunning.enable();
try {
progressPanel.setStateStarted();
fetcher.execute();
process.run(new String[]{dataSourcePath});
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Core errors occurred while running add image. ", ex);
//critical core/system error and process needs to be interrupted
hasCritError = true;
errorString = ex.getMessage();
} catch (TskDataException ex) {
logger.log(Level.WARNING, "Data errors occurred while running add image. ", ex);
errorString = ex.getMessage();
} finally {
// process is over, doesn't need to be dealt with if cancel happens
cancelledWhileRunning.disable();
}
return 0;
}
/**
* Commit the finished AddImageProcess, and cancel the CleanupTask that
* would have reverted it.
*
* @param settings property set to get AddImageProcess and CleanupTask
* from
*
* @throws Exception if commit or adding the image to the case failed
*/
private void commitImage(WizardDescriptor settings) throws Exception {
String contentPath = (String) settings.getProperty(AddImageAction.DATASOURCEPATH_PROP);
String timezone = settings.getProperty(AddImageAction.TIMEZONE_PROP).toString();
settings.putProperty(AddImageAction.IMAGEID_PROP, "");
long imageId = 0;
try {
imageId = process.commit();
} catch (TskException e) {
logger.log(Level.WARNING, "Errors occured while committing the image", e);
} finally {
//commit done, unlock db write in EWT thread
//before doing anything else
SleuthkitCase.dbWriteUnlock();
if (imageId != 0) {
Image newImage = Case.getCurrentCase().addImage(contentPath, imageId, timezone);
//while we have the image, verify the size of its contents
String verificationErrors = newImage.verifyImageSize();
if (verificationErrors.equals("") == false) {
//data error (non-critical)
progressPanel.addErrors(verificationErrors, false);
}
newContents.add(newImage);
settings.putProperty(AddImageAction.IMAGEID_PROP, imageId);
}
// Can't bail and revert image add after commit, so disable image cleanup
// task
cleanupImage.disable();
settings.putProperty(AddImageAction.IMAGECLEANUPTASK_PROP, null);
logger.log(Level.INFO, "Image committed, imageId: " + imageId);
logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo());
private void cancelDataSourceProcessing() {
dsProcessor.cancel();
}
/*
* Callback for the data source processor.
* Invoked by the DSP on the EDT thread, when it finishes processing the data source.
*/
private void dataSourceProcessorDone(DSPCallback.DSP_Result result, List<String> errList, List<Content> contents) {
// disable the cleanup task
cleanupTask.disable();
// Get attention for the process finish
java.awt.Toolkit.getDefaultToolkit().beep(); //BEEP!
AddImageWizardAddingProgressVisual panel = progressPanel.getComponent();
if (panel != null) {
Window w = SwingUtilities.getWindowAncestor(panel);
if (w != null) {
w.toFront();
}
}
/**
*
* (called by EventDispatch Thread after doInBackground finishes)
*/
@Override
protected void done() {
//these are required to stop the CurrentDirectoryFetcher
progressBar.setIndeterminate(false);
setProgress(100);
// attempt actions that might fail and force the process to stop
if (interrupted || hasCritError) {
logger.log(Level.INFO, "Handling errors or interruption that occured in add image process");
revert();
if (hasCritError) {
//core error
progressPanel.addErrors(errorString, true);
}
return;
}
if (errorString != null) {
//data error (non-critical)
logger.log(Level.INFO, "Handling non-critical errors that occured in add image process");
progressPanel.addErrors(errorString, false);
}
try {
// When everything happens without an error:
// the add-image process needs to be reverted if the wizard doesn't finish
cleanupImage = action.new CleanupTask() {
//note, CleanupTask runs inside EWT thread
@Override
void cleanup() throws Exception {
logger.log(Level.INFO, "Running cleanup task after add image process");
revert();
}
};
cleanupImage.enable();
if (errorString == null) { // complete progress bar
progressPanel.getComponent().setProgressBarTextAndColor("*Data Source added.", 100, Color.black);
}
// Get attention for the process finish
java.awt.Toolkit.getDefaultToolkit().beep(); //BEEP!
AddImageWizardAddingProgressVisual panel = progressPanel.getComponent();
if (panel != null) {
Window w = SwingUtilities.getWindowAncestor(panel);
if (w != null) {
w.toFront();
}
}
// Tell the panel we're done
progressPanel.setStateFinished();
// Commit the image
if (!newContents.isEmpty()) //already commited
{
logger.log(Level.INFO, "Assuming image already committed, will not commit.");
return;
}
if (process != null) { // and if we're done configuring ingest
// commit anything
try {
commitImage(wizDescriptor);
} catch (Exception ex) {
// Log error/display warning
logger.log(Level.SEVERE, "Error adding image to case.", ex);
}
} else {
logger.log(Level.SEVERE, "Missing image process object");
}
// Start ingest if we can
startIngest();
} catch (Exception ex) {
//handle unchecked exceptions post image add
logger.log(Level.WARNING, "Unexpected errors occurred while running post add image cleanup. ", ex);
progressPanel.getComponent().setProgressBarTextAndColor("*Failed to add image.", 0, Color.black); // set error message
// Log error/display warning
logger.log(Level.SEVERE, "Error adding image to case", ex);
} finally {
}
// Tell the panel we're done
progressPanel.setStateFinished();
//check the result and display to user
if (result == DSPCallback.DSP_Result.NO_ERRORS)
progressPanel.getComponent().setProgressBarTextAndColor("*Data Source added.", 100, Color.black);
else
progressPanel.getComponent().setProgressBarTextAndColor("*Errors encountered in adding Data Source.", 100, Color.red);
//if errors, display them on the progress panel
boolean critErr = false;
if (result == DSPCallback.DSP_Result.CRITICAL_ERRORS) {
critErr = true;
}
for ( String err: errList ) {
// TBD: there probably should be an error level for each error
progressPanel.addErrors(err, critErr);
}
newContents.clear();
newContents.addAll(contents);
//notify the UI of the new content added to the case
if (!newContents.isEmpty()) {
Case.getCurrentCase().notifyNewDataSource(newContents.get(0));
}
void interrupt() throws Exception {
interrupted = true;
try {
logger.log(Level.INFO, "interrupt() add image process");
process.stop(); //it might take time to truly stop processing and writing to db
} catch (TskException ex) {
throw new Exception("Error stopping add-image process.", ex);
}
}
//runs in EWT
void revert() {
try {
logger.log(Level.INFO, "Revert after add image process");
try {
process.revert();
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error reverting add image process", ex);
}
} finally {
//unlock db write within EWT thread
SleuthkitCase.dbWriteUnlock();
}
}
// Start ingest if we can
progressPanel.setStateStarted();
startIngest();
}
}

View File

@@ -47,11 +47,16 @@ class AddImageWizardIterator implements WizardDescriptor.Iterator<WizardDescript
*/
private List<WizardDescriptor.Panel<WizardDescriptor>> getPanels() {
if (panels == null) {
AddImageWizardAddingProgressPanel wizPanel = new AddImageWizardAddingProgressPanel();
panels = new ArrayList<WizardDescriptor.Panel<WizardDescriptor>>();
panels.add(new AddImageWizardChooseDataSourcePanel());
panels.add(new AddImageWizardIngestConfigPanel(action, wizPanel));
panels.add(wizPanel);
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);
String[] steps = new String[panels.size()];
for (int i = 0; i < panels.size(); i++) {

View File

@@ -0,0 +1,185 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.casemodule;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.autopsy.casemodule.services.FileManager;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Thread that will add logical files to database, and then kick-off ingest
* modules. Note: the add logical files task cannot currently be reverted as
* the add image task can. This is a separate task from AddImgTask because
* it is much simpler and does not require locks, since the underlying file
* manager methods acquire the locks for each transaction when adding
* logical files.
*/
public class AddLocalFilesTask implements Runnable {
private Logger logger = Logger.getLogger(AddLocalFilesTask.class.getName());
private String dataSourcePath;
private DSPProgressMonitor progressMonitor;
private DSPCallback callbackObj;
private Case currentCase;
// true if the process was requested to stop
private volatile boolean cancelled = false;
private boolean hasCritError = false;
private List<String> errorList = new ArrayList<String>();
private final List<Content> newContents = Collections.synchronizedList(new ArrayList<Content>());
protected AddLocalFilesTask(String dataSourcePath, DSPProgressMonitor aProgressMonitor, DSPCallback cbObj) {
currentCase = Case.getCurrentCase();
this.dataSourcePath = dataSourcePath;
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();
final LocalFilesAddProgressUpdater progUpdater = new LocalFilesAddProgressUpdater(progressMonitor);
try {
progressMonitor.setIndeterminate(true);
progressMonitor.setProgress(0);
final FileManager fileManager = currentCase.getServices().getFileManager();
String[] paths = dataSourcePath.split(LocalFilesPanel.FILES_SEP);
List<String> absLocalPaths = new ArrayList<String>();
for (String path : paths) {
absLocalPaths.add(path);
}
newContents.add(fileManager.addLocalFilesDirs(absLocalPaths, progUpdater));
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Errors occurred while running add logical files. ", ex);
hasCritError = true;
errorList.add(ex.getMessage());
} finally {
}
// handle done
postProcess();
return;
}
/**
*
* (called by EventDispatch Thread after doInBackground finishes)
*/
protected void postProcess() {
if (cancelled || hasCritError) {
logger.log(Level.WARNING, "Handling errors or interruption that occured in logical files process");
}
if (!errorList.isEmpty()) {
//data error (non-critical)
logger.log(Level.WARNING, "Handling non-critical errors that occured in logical files process");
}
if (!(cancelled || hasCritError)) {
progressMonitor.setProgress(100);
progressMonitor.setIndeterminate(false);
}
// invoke the callBack, unless the caller cancelled
if (!cancelled) {
doCallBack();
}
}
/*
* Call the callback with results, new content, and errors, if any
*/
private void doCallBack()
{
DSPCallback.DSP_Result result;
if (hasCritError) {
result = DSPCallback.DSP_Result.CRITICAL_ERRORS;
}
else if (!errorList.isEmpty()) {
result = DSPCallback.DSP_Result.NONCRITICAL_ERRORS;
}
else {
result = DSPCallback.DSP_Result.NO_ERRORS;
}
// invoke the callback, passing it the result, list of new contents, and list of errors
callbackObj.done(result, errorList, newContents);
}
/*
* cancel the files addition, if possible
*/
public void cancelTask() {
cancelled = true;
}
/**
* Updates the wizard status with logical file/folder
*/
private class LocalFilesAddProgressUpdater implements FileManager.FileAddProgressUpdater {
private int count = 0;
private DSPProgressMonitor progressMonitor;
LocalFilesAddProgressUpdater(DSPProgressMonitor progressMonitor) {
this.progressMonitor = progressMonitor;
}
@Override
public void fileAdded(final AbstractFile newFile) {
if (count++ % 10 == 0) {
progressMonitor.setProgressText("Adding: " + newFile.getParentPath() + "/" + newFile.getName());
}
}
}
}

View File

@@ -115,7 +115,6 @@ ImageFilePanel.browseButton.text=Browse
ImageFilePanel.pathTextField.text=
LocalDiskPanel.diskLabel.text=Select a local disk:
MissingImageDialog.selectButton.text=Select Image
MissingImageDialog.typeTabel.text=Select input type to add:
MissingImageDialog.titleLabel.text=Search for missing image
MissingImageDialog.cancelButton.text=Cancel
LocalDiskPanel.errorLabel.text=Error Label
@@ -133,18 +132,23 @@ LocalFilesPanel.localFileChooser.approveButtonToolTipText=
LocalFilesPanel.selectButton.actionCommand=Add
AddImageWizardIngestConfigVisual.subtitleLabel.text=Configure the ingest modules you would like to run on this data source.
AddImageWizardIngestConfigVisual.titleLabel.text=Configure Ingest Modules
AddImageWizardAddingProgressVisual.statusLabel.text=File system has been added to the local database. Files are being analyzed.
AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.toolTipText=
AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.text=Ignore orphan files in FAT file systems
AddImageWizardChooseDataSourceVisual.descLabel.text=(faster results, although some data will not be searched)
AddImageWizardAddingProgressVisual.statusLabel.text=Data source has been added to the local database. Files are being analyzed.
AddImageWizardChooseDataSourceVisual.typeTabel.text=Select source type to add:
AddImageWizardChooseDataSourceVisual.jLabel2.text=jLabel2
AddImageWizardChooseDataSourceVisual.timeZoneLabel.text=Please select the input timezone:
AddImageWizardChooseDataSourceVisual.nextLabel.text=<html> Press 'Next' to analyze the input data, extract volume and file system data, and populate a local database.</html>
AddImageWizardChooseDataSourceVisual.imgInfoLabel.text=Enter Data Source Information:
AddImageWizardAddingProgressVisual.progressLabel.text=<progress>
AddImageWizardAddingProgressVisual.TextArea_CurrentDirectory.border.title=Currently Adding:
AddImageWizardAddingProgressVisual.viewLogButton.text=View Log
AddImageWizardAddingProgressVisual.titleLabel.text=Adding Data Source
AddImageWizardAddingProgressVisual.subTitle1Label.text=File system information is being added to a local database. File analysis will start when this finishes.
AddImageWizardAddingProgressVisual.subTitle2Label.text=Processing Data Source and Adding to Database
AddImageWizardAddingProgressVisual.subTitle1Label.text=Processing data source and adding it to a local database. File analysis will start when this finishes.
ImageFilePanel.timeZoneLabel.text=Please select the input timezone:
ImageFilePanel.noFatOrphansCheckbox.text=Ignore orphan files in FAT file systems
ImageFilePanel.noFatOrphansCheckbox.toolTipText=
ImageFilePanel.descLabel.text=(faster results, although some data will not be searched)
LocalDiskPanel.timeZoneLabel.text=Please select the input timezone:
LocalDiskPanel.noFatOrphansCheckbox.toolTipText=
LocalDiskPanel.noFatOrphansCheckbox.text=Ignore orphan files in FAT file systems
LocalDiskPanel.descLabel.text=(faster results, although some data will not be searched)
MissingImageDialog.browseButton.text=Browse
MissingImageDialog.pathNameTextField.text=
AddImageWizardAddingProgressVisual.progressTextArea.border.title=Status

View File

@@ -384,7 +384,9 @@ public class Case implements SleuthkitCase.ErrorObserver {
+ "\nPlease note that you will still be able to browse directories and generate reports\n"
+ "if you choose No, but you will not be able to view file content or run the ingest process.", "Missing Image", JOptionPane.YES_NO_OPTION);
if (ret == JOptionPane.YES_OPTION) {
MissingImageDialog.makeDialog(obj_id, db);
} else {
logger.log(Level.WARNING, "Selected image files don't match old files!");
}
@@ -401,6 +403,7 @@ public class Case implements SleuthkitCase.ErrorObserver {
* @param imgId the ID of the image that being added
* @param timeZone the timeZone of the image where it's added
*/
@Deprecated
public Image addImage(String imgPath, long imgId, String timeZone) throws CaseActionException {
logger.log(Level.INFO, "Adding image to Case. imgPath: {0} ID: {1} TimeZone: {2}", new Object[]{imgPath, imgId, timeZone});
@@ -420,11 +423,23 @@ public class Case implements SleuthkitCase.ErrorObserver {
*
* @param newDataSource new data source added
*/
@Deprecated
void addLocalDataSource(Content newDataSource) {
pcs.firePropertyChange(CASE_ADD_DATA_SOURCE, null, newDataSource);
CoreComponentControl.openCoreWindows();
}
/**
* Notifies the UI that a new data source has been added.
*
*
* @param newDataSource new data source added
*/
void notifyNewDataSource(Content newDataSource) {
pcs.firePropertyChange(CASE_ADD_DATA_SOURCE, null, newDataSource);
CoreComponentControl.openCoreWindows();
}
/**
* @return The Services object for this case.
*/

View File

@@ -1,72 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.casemodule;
import java.beans.PropertyChangeListener;
import javax.swing.JPanel;
abstract class ContentTypePanel extends JPanel {
public enum ContentType{IMAGE, DISK, LOCAL};
/**
* Returns a list off all the panels extending ImageTypePanel.
* @return list of all ImageTypePanels
*/
public static ContentTypePanel[] getPanels() {
return new ContentTypePanel[] {ImageFilePanel.getDefault(), LocalDiskPanel.getDefault(), LocalFilesPanel.getDefault() };
}
/**
* Return the path of the selected content in this panel.
* @return paths to selected content (one or more if multiselect supported)
*/
abstract public String getContentPaths();
/**
* Set the selected content in this panel to the provided path.
* This function is optional.
* @param s path to selected content
*/
abstract public void setContentPath(String s);
/**
* Get content type (image, disk, local file) of the source this wizard panel is for
* @return ContentType of the source panel
*/
abstract public ContentType getContentType();
/**
* Returns if the next button should be enabled in the current wizard.
* @return true if the next button should be enabled, false otherwise
*/
abstract public boolean enableNext();
/**
* Tells this panel to reset itself
*/
abstract public void reset();
/**
* Tells this panel it has been selected.
*/
abstract public void select();
}

View File

@@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.casemodule;
import java.io.File;
import java.util.List;
import java.util.Arrays;
import javax.swing.filechooser.FileFilter;
/**
@@ -28,6 +29,16 @@ import javax.swing.filechooser.FileFilter;
*/
public class GeneralFilter extends FileFilter{
// Extensions & Descriptions for commonly used filters
public static final List<String> RAW_IMAGE_EXTS = Arrays.asList(new String[]{".img", ".dd", ".001", ".aa", ".raw", ".bin"});
public static final String RAW_IMAGE_DESC = "Raw Images (*.img, *.dd, *.001, *.aa, *.raw, *.bin)";
public static final List<String> ENCASE_IMAGE_EXTS = Arrays.asList(new String[]{".e01"});
public static final String ENCASE_IMAGE_DESC = "Encase Images (*.e01)";
private List<String> extensions;
private String desc;

View File

@@ -0,0 +1,218 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.casemodule;
import java.util.logging.Level;
import javax.swing.JPanel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.filechooser.FileFilter;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
/**
* 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
protected final static String dsType = "Image File";
// The Config UI panel that plugins into the Choose Data Source Wizard
private 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;
DSPCallback 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<String> allExt = new ArrayList<String>();
static {
allExt.addAll(GeneralFilter.RAW_IMAGE_EXTS);
allExt.addAll(GeneralFilter.ENCASE_IMAGE_EXTS);
}
static final String allDesc = "All Supported Types";
static final GeneralFilter allFilter = new GeneralFilter(allExt, allDesc);
static final List<FileFilter> filtersList = new ArrayList<FileFilter>();
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
*/
public ImageDSProcessor() {
// Create the config panel
imageFilePanel = ImageFilePanel.createInstance(ImageDSProcessor.class.getName(), filtersList);
}
/**
* Returns the Data source type (string) handled by this DSP
*
* @return String the data source type
**/
@Override
public String getType() {
return dsType;
}
/**
* Returns the JPanel for collecting the Data source information
*
* @return JPanel the config panel
**/
@Override
public JPanel getPanel() {
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 validatePanel() {
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(DSPProgressMonitor progressMonitor, DSPCallback 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();
return;
}
/**
* Cancel the data source processing
**/
@Override
public void cancel() {
cancelled = true;
addImageTask.cancelTask();
return;
}
/**
* 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;
return;
}
/**
* 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 String 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;
}
}

View File

@@ -31,8 +31,20 @@
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="pathLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="284" max="32767" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="timeZoneLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="timeZoneComboBox" min="-2" pref="215" max="-2" attributes="0"/>
</Group>
<Component id="pathLabel" min="-2" max="-2" attributes="0"/>
<Component id="noFatOrphansCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="21" pref="21" max="-2" attributes="0"/>
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="0" pref="20" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@@ -45,6 +57,16 @@
<Component id="browseButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="pathTextField" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="timeZoneLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="timeZoneComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="noFatOrphansCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@@ -74,5 +96,40 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="timeZoneLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="ImageFilePanel.timeZoneLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="timeZoneComboBox">
<Properties>
<Property name="maximumRowCount" type="int" value="30"/>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
<Component class="javax.swing.JCheckBox" name="noFatOrphansCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="ImageFilePanel.noFatOrphansCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="ImageFilePanel.noFatOrphansCheckbox.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="descLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="ImageFilePanel.descLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Form>

View File

@@ -22,41 +22,71 @@ import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import javax.swing.JFileChooser;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.JPanel;
import javax.swing.filechooser.FileFilter;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
/**
* ImageTypePanel for adding an image file such as .img, .E0x, .00x, etc.
*/
public class ImageFilePanel extends ContentTypePanel implements DocumentListener {
private static ImageFilePanel instance = null;
public class ImageFilePanel extends JPanel implements DocumentListener {
private final String PROP_LASTIMAGE_PATH = "LBL_LastImage_PATH";
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
*/
public ImageFilePanel() {
private ImageFilePanel(String context, List<FileFilter> fileChooserFilters) {
initComponents();
fc.setDragEnabled(false);
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
fc.setMultiSelectionEnabled(false);
fc.addChoosableFileFilter(AddImageWizardChooseDataSourceVisual.rawFilter);
fc.addChoosableFileFilter(AddImageWizardChooseDataSourceVisual.encaseFilter);
fc.setFileFilter(AddImageWizardChooseDataSourceVisual.allFilter);
boolean firstFilter = true;
for (FileFilter filter: fileChooserFilters ) {
if (firstFilter) { // set the first on the list as the default selection
fc.setFileFilter(filter);
firstFilter = false;
}
else {
fc.addChoosableFileFilter(filter);
}
}
this.contextName = context;
pcs = new PropertyChangeSupport(this);
createTimeZoneList();
}
/**
* Returns the default instance of a ImageFilePanel.
* Creates and returns an instance of a ImageFilePanel.
*/
public static synchronized ImageFilePanel getDefault() {
if (instance == null) {
instance = new ImageFilePanel();
instance.postInit();
}
return instance;
public static synchronized ImageFilePanel createInstance(String context, List<FileFilter> fileChooserFilters) {
ImageFilePanel instance = new ImageFilePanel(context, fileChooserFilters );
instance.postInit();
return instance;
}
//post-constructor initialization to properly initialize listener support
@@ -79,6 +109,10 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
pathLabel = new javax.swing.JLabel();
browseButton = new javax.swing.JButton();
pathTextField = new javax.swing.JTextField();
timeZoneLabel = new javax.swing.JLabel();
timeZoneComboBox = new javax.swing.JComboBox<String>();
noFatOrphansCheckbox = new javax.swing.JCheckBox();
descLabel = new javax.swing.JLabel();
setMinimumSize(new java.awt.Dimension(0, 65));
setPreferredSize(new java.awt.Dimension(403, 65));
@@ -94,6 +128,15 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
pathTextField.setText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.pathTextField.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(timeZoneLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.timeZoneLabel.text")); // NOI18N
timeZoneComboBox.setMaximumRowCount(30);
org.openide.awt.Mnemonics.setLocalizedText(noFatOrphansCheckbox, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.noFatOrphansCheckbox.text")); // NOI18N
noFatOrphansCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.noFatOrphansCheckbox.toolTipText")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(descLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.descLabel.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
@@ -104,8 +147,17 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
.addComponent(browseButton)
.addGap(2, 2, 2))
.addGroup(layout.createSequentialGroup()
.addComponent(pathLabel)
.addGap(0, 284, Short.MAX_VALUE))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(timeZoneLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(pathLabel)
.addComponent(noFatOrphansCheckbox)
.addGroup(layout.createSequentialGroup()
.addGap(21, 21, 21)
.addComponent(descLabel)))
.addGap(0, 20, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@@ -114,7 +166,16 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(browseButton)
.addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(18, 18, 18)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(timeZoneLabel)
.addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(noFatOrphansCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(descLabel)
.addContainerGap(33, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
@@ -131,20 +192,23 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
String path = fc.getSelectedFile().getPath();
pathTextField.setText(path);
}
pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.FOCUS_NEXT.toString(), false, true);
pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.FOCUS_NEXT.toString(), false, true);
}//GEN-LAST:event_browseButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton browseButton;
private javax.swing.JLabel descLabel;
private javax.swing.JCheckBox noFatOrphansCheckbox;
private javax.swing.JLabel pathLabel;
private javax.swing.JTextField pathTextField;
private javax.swing.JComboBox<String> 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
*/
@Override
public String getContentPaths() {
return pathTextField.getText();
}
@@ -152,33 +216,37 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
/**
* Set the path of the image file.
*/
@Override
public void setContentPath(String s) {
pathTextField.setText(s);
}
@Override
public ContentType getContentType() {
return ContentType.IMAGE;
public String getTimeZone() {
String tz = timeZoneComboBox.getSelectedItem().toString();
return tz.substring(tz.indexOf(")") + 2).trim();
}
public boolean getNoFatOrphans() {
return noFatOrphansCheckbox.isSelected();
}
@Override
public void reset() {
//nothing to reset
//reset the UI elements to default
pathTextField.setText(null);
}
/**
* Should we enable the next button of the wizard?
* @return true if a proper image has been selected, false otherwise
*/
@Override
public boolean enableNext() {
public boolean validatePanel() {
String path = getContentPaths();
if (path == null || path.isEmpty()) {
return false;
}
boolean isExist = Case.pathExists(path);
boolean isPhysicalDrive = Case.isPhysicalDrive(path);
boolean isPartition = Case.isPartition(path);
@@ -186,6 +254,57 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
return (isExist || isPhysicalDrive || isPartition);
}
public void storeSettings() {
String imagePathName = getContentPaths();
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);
}
}
/**
* Creates the drop down list for the time zones and then makes the local
* machine time zone to be selected.
*/
public void createTimeZoneList() {
// load and add all timezone
String[] ids = SimpleTimeZone.getAvailableIDs();
for (String id : ids) {
TimeZone zone = TimeZone.getTimeZone(id);
int offset = zone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = (offset % 3600) / 60;
String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id);
/*
* DateFormat dfm = new SimpleDateFormat("z");
* dfm.setTimeZone(zone); boolean hasDaylight =
* zone.useDaylightTime(); String first = dfm.format(new Date(2010,
* 1, 1)); String second = dfm.format(new Date(2011, 6, 6)); int mid
* = hour * -1; String result = first + Integer.toString(mid);
* if(hasDaylight){ result = result + second; }
* timeZoneComboBox.addItem(item + " (" + result + ")");
*/
timeZoneComboBox.addItem(item);
}
// get the current timezone
TimeZone thisTimeZone = Calendar.getInstance().getTimeZone();
int thisOffset = thisTimeZone.getRawOffset() / 1000;
int thisHour = thisOffset / 3600;
int thisMinutes = (thisOffset % 3600) / 60;
String formatted = String.format("(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID());
// 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
@@ -194,34 +313,26 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
*/
@Override
public void insertUpdate(DocumentEvent e) {
pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
}
@Override
public void removeUpdate(DocumentEvent e) {
pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
}
@Override
public void changedUpdate(DocumentEvent e) {
pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
}
/**
* Set the focus to the pathTextField.
*/
@Override
public void select() {
pathTextField.requestFocusInWindow();
}
/**
* @return the string form of this panel
*/
@Override
public String toString() {
return "Image File";
}
@Override
public synchronized void addPropertyChangeListener(PropertyChangeListener pcl) {

View File

@@ -0,0 +1,184 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.casemodule;
import javax.swing.JPanel;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.coreutils.Logger;
@ServiceProvider(service = DataSourceProcessor.class)
public class LocalDiskDSProcessor implements DataSourceProcessor {
static final Logger logger = Logger.getLogger(ImageDSProcessor.class.getName());
// Data source type handled by this processor
static protected final String dsType = "Local Disk";
// The Config UI panel that plugins into the Choose Data Source Wizard
private 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;
DSPCallback 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
*/
public LocalDiskDSProcessor() {
// Create the config panel
localDiskPanel = LocalDiskPanel.getDefault();
}
/**
* Returns the Data source type (string) handled by this DSP
*
* @return String the data source type
**/
@Override
public String getType() {
return dsType;
}
/**
* Returns the JPanel for collecting the Data source information
*
* @return JPanel the config panel
**/
@Override
public JPanel getPanel() {
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 validatePanel() {
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(DSPProgressMonitor progressMonitor, DSPCallback 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();
return;
}
/**
* Cancel the data source processing
**/
@Override
public void cancel() {
cancelled = true;
addDiskTask.cancelTask();
return;
}
/**
* 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;
return;
}
/**
* 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 String timeZone
* @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;
}
}

View File

@@ -29,8 +29,18 @@
<Component id="diskLabel" min="-2" max="-2" attributes="0"/>
<Component id="diskComboBox" min="-2" pref="345" max="-2" attributes="0"/>
<Component id="errorLabel" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<Component id="timeZoneLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="timeZoneComboBox" min="-2" pref="215" max="-2" attributes="0"/>
</Group>
<Component id="noFatOrphansCheckbox" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<EmptySpace min="21" pref="21" max="-2" attributes="0"/>
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="0" pref="140" max="32767" attributes="0"/>
<EmptySpace min="0" pref="102" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@@ -40,8 +50,18 @@
<Component id="diskLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="diskComboBox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<EmptySpace min="-2" pref="13" max="-2" attributes="0"/>
<Component id="errorLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="timeZoneLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="timeZoneComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="noFatOrphansCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@@ -71,5 +91,40 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="timeZoneLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LocalDiskPanel.timeZoneLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="timeZoneComboBox">
<Properties>
<Property name="maximumRowCount" type="int" value="30"/>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
<Component class="javax.swing.JCheckBox" name="noFatOrphansCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LocalDiskPanel.noFatOrphansCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LocalDiskPanel.noFatOrphansCheckbox.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="descLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LocalDiskPanel.descLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Form>

View File

@@ -25,7 +25,10 @@ import java.awt.Font;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import java.util.concurrent.CancellationException;
import java.util.logging.Level;
import javax.swing.ComboBoxModel;
@@ -37,13 +40,16 @@ import javax.swing.ListCellRenderer;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListDataListener;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
/**
* ImageTypePanel for adding a local disk or partition such as PhysicalDrive0 or C:.
*/
public class LocalDiskPanel extends ContentTypePanel {
public class LocalDiskPanel extends JPanel {
private static final Logger logger = Logger.getLogger(LocalDiskPanel.class.getName());
private static LocalDiskPanel instance;
private PropertyChangeSupport pcs = null;
private List<LocalDisk> disks = new ArrayList<LocalDisk>();
@@ -56,6 +62,9 @@ public class LocalDiskPanel extends ContentTypePanel {
public LocalDiskPanel() {
initComponents();
customInit();
createTimeZoneList();
}
/**
@@ -73,8 +82,10 @@ public class LocalDiskPanel extends ContentTypePanel {
model = new LocalDiskModel();
diskComboBox.setModel(model);
diskComboBox.setRenderer(model);
errorLabel.setText("");
diskComboBox.setEnabled(false);
}
/**
@@ -89,6 +100,10 @@ public class LocalDiskPanel extends ContentTypePanel {
diskLabel = new javax.swing.JLabel();
diskComboBox = new javax.swing.JComboBox();
errorLabel = new javax.swing.JLabel();
timeZoneLabel = new javax.swing.JLabel();
timeZoneComboBox = new javax.swing.JComboBox<String>();
noFatOrphansCheckbox = new javax.swing.JCheckBox();
descLabel = new javax.swing.JLabel();
setMinimumSize(new java.awt.Dimension(0, 65));
setPreferredSize(new java.awt.Dimension(485, 65));
@@ -98,6 +113,15 @@ public class LocalDiskPanel extends ContentTypePanel {
errorLabel.setForeground(new java.awt.Color(255, 0, 0));
org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.errorLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(timeZoneLabel, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.timeZoneLabel.text")); // NOI18N
timeZoneComboBox.setMaximumRowCount(30);
org.openide.awt.Mnemonics.setLocalizedText(noFatOrphansCheckbox, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.noFatOrphansCheckbox.text")); // NOI18N
noFatOrphansCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.noFatOrphansCheckbox.toolTipText")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(descLabel, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.descLabel.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
@@ -106,8 +130,16 @@ public class LocalDiskPanel extends ContentTypePanel {
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(diskLabel)
.addComponent(diskComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 345, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(errorLabel))
.addGap(0, 140, Short.MAX_VALUE))
.addComponent(errorLabel)
.addGroup(layout.createSequentialGroup()
.addComponent(timeZoneLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(noFatOrphansCheckbox)
.addGroup(layout.createSequentialGroup()
.addGap(21, 21, 21)
.addComponent(descLabel)))
.addGap(0, 102, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@@ -115,21 +147,34 @@ public class LocalDiskPanel extends ContentTypePanel {
.addComponent(diskLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(diskComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(13, 13, 13)
.addComponent(errorLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(timeZoneLabel)
.addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(18, 18, 18)
.addComponent(noFatOrphansCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(errorLabel))
.addComponent(descLabel)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel descLabel;
private javax.swing.JComboBox diskComboBox;
private javax.swing.JLabel diskLabel;
private javax.swing.JLabel errorLabel;
private javax.swing.JCheckBox noFatOrphansCheckbox;
private javax.swing.JComboBox<String> timeZoneComboBox;
private javax.swing.JLabel timeZoneLabel;
// End of variables declaration//GEN-END:variables
/**
* Return the currently selected disk path.
* @return String selected disk path
*/
@Override
//@Override
public String getContentPaths() {
if(disks.size() > 0) {
LocalDisk selected = (LocalDisk) diskComboBox.getSelectedItem();
@@ -143,7 +188,7 @@ public class LocalDiskPanel extends ContentTypePanel {
/**
* Set the selected disk.
*/
@Override
// @Override
public void setContentPath(String s) {
for(int i=0; i<disks.size(); i++) {
if(disks.get(i).getPath().equals(s)) {
@@ -152,9 +197,14 @@ public class LocalDiskPanel extends ContentTypePanel {
}
}
@Override
public ContentType getContentType() {
return ContentType.DISK;
public String getTimeZone() {
String tz = timeZoneComboBox.getSelectedItem().toString();
return tz.substring(tz.indexOf(")") + 2).trim();
}
boolean getNoFatOrphans() {
return noFatOrphansCheckbox.isSelected();
}
/**
@@ -162,31 +212,27 @@ public class LocalDiskPanel extends ContentTypePanel {
* Always return true because we control the possible selections.
* @return true
*/
@Override
public boolean enableNext() {
//@Override
public boolean validatePanel() {
return enableNext;
}
@Override
//@Override
public void reset() {
//nothing to reset
}
/**
* @return the representation of this panel as a String.
*/
@Override
public String toString() {
return "Local Disk";
}
/**
* Set the focus to the diskComboBox and refreshes the list of disks.
*/
@Override
// @Override
public void select() {
diskComboBox.requestFocusInWindow();
model.loadDisks();
model.loadDisks();
}
@Override
@@ -207,16 +253,61 @@ public class LocalDiskPanel extends ContentTypePanel {
pcs.removePropertyChangeListener(pcl);
}
/**
* Creates the drop down list for the time zones and then makes the local
* machine time zone to be selected.
*/
public void createTimeZoneList() {
// load and add all timezone
String[] ids = SimpleTimeZone.getAvailableIDs();
for (String id : ids) {
TimeZone zone = TimeZone.getTimeZone(id);
int offset = zone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = (offset % 3600) / 60;
String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id);
/*
* DateFormat dfm = new SimpleDateFormat("z");
* dfm.setTimeZone(zone); boolean hasDaylight =
* zone.useDaylightTime(); String first = dfm.format(new Date(2010,
* 1, 1)); String second = dfm.format(new Date(2011, 6, 6)); int mid
* = hour * -1; String result = first + Integer.toString(mid);
* if(hasDaylight){ result = result + second; }
* timeZoneComboBox.addItem(item + " (" + result + ")");
*/
timeZoneComboBox.addItem(item);
}
// get the current timezone
TimeZone thisTimeZone = Calendar.getInstance().getTimeZone();
int thisOffset = thisTimeZone.getRawOffset() / 1000;
int thisHour = thisOffset / 3600;
int thisMinutes = (thisOffset % 3600) / 60;
String formatted = String.format("(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID());
// set the selected timezone
timeZoneComboBox.setSelectedItem(formatted);
}
private class LocalDiskModel implements ComboBoxModel, ListCellRenderer {
private Object selected;
private boolean ready = false;
private volatile boolean loadingDisks = false;
List<LocalDisk> physical = new ArrayList<LocalDisk>();
List<LocalDisk> partitions = new ArrayList<LocalDisk>();
//private String SELECT = "Select a local disk:";
private String LOADING = "Loading local disks...";
LocalDiskThread worker = null;
private void loadDisks() {
// if there is a worker already building the lists, then cancel it first.
if (loadingDisks && worker != null) {
worker.cancel(false);
}
// Clear the lists
errorLabel.setText("");
disks = new ArrayList<LocalDisk>();
@@ -224,9 +315,13 @@ public class LocalDiskPanel extends ContentTypePanel {
partitions = new ArrayList<LocalDisk>();
diskComboBox.setEnabled(false);
ready = false;
LocalDiskThread worker = new LocalDiskThread();
enableNext = false;
loadingDisks = true;
worker = new LocalDiskThread();
worker.execute();
}
@Override
@@ -234,7 +329,7 @@ public class LocalDiskPanel extends ContentTypePanel {
if(ready) {
selected = anItem;
enableNext = true;
pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
}
}
@@ -260,7 +355,7 @@ public class LocalDiskPanel extends ContentTypePanel {
@Override
public void removeListDataListener(ListDataListener l) {
}
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
JPanel panel = new JPanel(new BorderLayout());
@@ -300,8 +395,6 @@ public class LocalDiskPanel extends ContentTypePanel {
// Populate the lists
physical = PlatformUtil.getPhysicalDrives();
partitions = PlatformUtil.getPartitions();
disks.addAll(physical);
disks.addAll(partitions);
return null;
}
@@ -337,6 +430,11 @@ public class LocalDiskPanel extends ContentTypePanel {
enableNext = false;
displayErrors();
ready = true;
worker = null;
loadingDisks = false;
disks.addAll(physical);
disks.addAll(partitions);
if(disks.size() > 0) {
diskComboBox.setEnabled(true);

View File

@@ -0,0 +1,167 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.casemodule;
import javax.swing.JPanel;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
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
protected static final String dsType = "Logical Files";
// The Config UI panel that plugins into the Choose Data Source Wizard
private 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;
DSPCallback 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
*/
public LocalFilesDSProcessor() {
// Create the config panel
localFilesPanel = LocalFilesPanel.getDefault();
}
/**
* Returns the Data source type (string) handled by this DSP
*
* @return String the data source type
**/
@Override
public String getType() {
return dsType;
}
/**
* Returns the JPanel for collecting the Data source information
*
* @return JPanel the config panel
**/
@Override
public JPanel getPanel() {
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 validatePanel() {
return localFilesPanel.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(DSPProgressMonitor progressMonitor, DSPCallback 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();
return;
}
/**
* Cancel the data source processing
**/
@Override
public void cancel() {
cancelled = true;
addFilesTask.cancelTask();
return;
}
/**
* Reset the data source processor
**/
@Override
public void reset() {
// reset the config panel
localFilesPanel.reset();
// reset state
localFilesOptionsSet = false;
localFilesPath = null;
return;
}
/**
* 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) {
this.localFilesPath = filesPath;
localFilesOptionsSet = true;
}
}

View File

@@ -24,11 +24,13 @@ import java.io.File;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
/**
* Add input wizard subpanel for adding local files / dirs to the case
*/
public class LocalFilesPanel extends ContentTypePanel {
public class LocalFilesPanel extends JPanel {
private PropertyChangeSupport pcs = null;
private Set<File> currentFiles = new TreeSet<File>(); //keep currents in a set to disallow duplicates per add
@@ -57,7 +59,7 @@ public class LocalFilesPanel extends ContentTypePanel {
}
@Override
//@Override
public String getContentPaths() {
//TODO consider interface change to return list of paths instead
@@ -72,36 +74,37 @@ public class LocalFilesPanel extends ContentTypePanel {
return b.toString();
}
@Override
//@Override
public void setContentPath(String s) {
//for the local file panel we don't need to restore the last paths used
//when the wizard restarts
}
@Override
public ContentType getContentType() {
return ContentType.LOCAL;
//@Override
public String getContentType() {
return "LOCAL";
}
@Override
public boolean enableNext() {
//@Override
public boolean validatePanel() {
return enableNext;
}
@Override
//@Override
public void select() {
reset();
}
@Override
//@Override
public void reset() {
currentFiles.clear();
selectedPaths.setText("");
enableNext = false;
pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
//pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
}
@Override
@Override
public synchronized void addPropertyChangeListener(PropertyChangeListener pcl) {
super.addPropertyChangeListener(pcl);
@@ -231,7 +234,7 @@ public class LocalFilesPanel extends ContentTypePanel {
else {
enableNext = false;
}
pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
}//GEN-LAST:event_selectButtonActionPerformed
private void clearButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearButtonActionPerformed

View File

@@ -110,65 +110,49 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="typePanel" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="typeTabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="typeComboBox" pref="298" max="32767" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="pathNameTextField" min="-2" pref="285" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="browseButton" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="83" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="typeTabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="typeComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="pathNameTextField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="browseButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="typePanel" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<EmptySpace pref="62" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JComboBox" name="typeComboBox">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="typeTabel">
<Component class="javax.swing.JTextField" name="pathNameTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MissingImageDialog.typeTabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MissingImageDialog.pathNameTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="pathNameTextFieldActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="browseButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MissingImageDialog.browseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="browseButtonActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JPanel" name="typePanel">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="57" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="titleLabel">

View File

@@ -18,49 +18,71 @@
*/
package org.sleuthkit.autopsy.casemodule;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.logging.Level;
import javax.swing.ComboBoxModel;
import javax.swing.JDialog;
import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.event.ListDataListener;
import org.openide.util.Exceptions;
import org.sleuthkit.autopsy.casemodule.GeneralFilter;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
public class MissingImageDialog extends javax.swing.JDialog {
private static final Logger logger = Logger.getLogger(MissingImageDialog.class.getName());
long obj_id;
SleuthkitCase db;
ContentTypePanel currentPanel;
ImageTypeModel model;
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<String> allExt = new ArrayList<String>();
static {
allExt.addAll(GeneralFilter.RAW_IMAGE_EXTS);
allExt.addAll(GeneralFilter.ENCASE_IMAGE_EXTS);
}
static final String allDesc = "All Supported Types";
static final GeneralFilter allFilter = new GeneralFilter(allExt, allDesc);
private JFileChooser fc = new JFileChooser();
private MissingImageDialog(long obj_id, SleuthkitCase db) {
super(new JFrame(), true);
this.obj_id = obj_id;
this.db = db;
initComponents();
fc.setDragEnabled(false);
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
fc.setMultiSelectionEnabled(false);
fc.addChoosableFileFilter(rawFilter);
fc.addChoosableFileFilter(encaseFilter);
fc.setFileFilter(allFilter);
customInit();
}
/**
* Client call to create a MissingImageDialog.
*
* @param obj_id obj_id of the missing image
* @param db the current SleuthkitCase connected to a db
*/
//
// * Client call to create a MissingImageDialog.
// *
// * @param obj_id obj_id of the missing image
// * @param db the current SleuthkitCase connected to a db
//
static void makeDialog(long obj_id, SleuthkitCase db) {
final MissingImageDialog dialog = new MissingImageDialog(obj_id, db);
dialog.addWindowListener(new WindowAdapter() {
@@ -73,11 +95,8 @@ public class MissingImageDialog extends javax.swing.JDialog {
}
private void customInit() {
model = new ImageTypeModel();
typeComboBox.setModel(model);
typeComboBox.setSelectedIndex(0);
typePanel.setLayout(new BorderLayout());
updateCurrentPanel(ImageFilePanel.getDefault());
selectButton.setEnabled(false);
}
private void display() {
@@ -92,54 +111,31 @@ public class MissingImageDialog extends javax.swing.JDialog {
this.setVisible(true);
}
/**
* Refresh this panel.
* @param panel current typepanel
*/
private void updateCurrentPanel(ContentTypePanel panel) {
currentPanel = panel;
typePanel.removeAll();
typePanel.add((JPanel) currentPanel, BorderLayout.CENTER);
typePanel.validate();
typePanel.repaint();
this.validate();
this.repaint();
currentPanel.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if(evt.getPropertyName().equals(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString())) {
updateSelectButton();
}
if(evt.getPropertyName().equals(AddImageWizardChooseDataSourceVisual.EVENT.FOCUS_NEXT.toString())) {
moveFocusToSelect();
}
}
});
currentPanel.select();
updateSelectButton();
}
/**
* Focuses the select button for easy enter-pressing access.
*/
//
// * Focuses the select button for easy enter-pressing access.
//
private void moveFocusToSelect() {
this.selectButton.requestFocusInWindow();
}
/**
* Enables/disables the select button based off the current panel.
*/
//
// * Enables/disables the select button based off the current panel.
//
private void updateSelectButton() {
this.selectButton.setEnabled(currentPanel.enableNext());
// Enable this based on whether there is a valid path
if (!pathNameTextField.getText().isEmpty()) {
String filePath = pathNameTextField.getText();
boolean isExist = Case.pathExists(filePath) || Case.driveExists(filePath);
selectButton.setEnabled(isExist);
}
}
/**
* 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")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
@@ -148,9 +144,8 @@ public class MissingImageDialog extends javax.swing.JDialog {
selectButton = new javax.swing.JButton();
cancelButton = new javax.swing.JButton();
containerPanel = new javax.swing.JPanel();
typeComboBox = new javax.swing.JComboBox();
typeTabel = new javax.swing.JLabel();
typePanel = new javax.swing.JPanel();
pathNameTextField = new javax.swing.JTextField();
browseButton = new javax.swing.JButton();
titleLabel = new javax.swing.JLabel();
titleSeparator = new javax.swing.JSeparator();
@@ -191,43 +186,39 @@ public class MissingImageDialog extends javax.swing.JDialog {
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
org.openide.awt.Mnemonics.setLocalizedText(typeTabel, org.openide.util.NbBundle.getMessage(MissingImageDialog.class, "MissingImageDialog.typeTabel.text")); // NOI18N
pathNameTextField.setText(org.openide.util.NbBundle.getMessage(MissingImageDialog.class, "MissingImageDialog.pathNameTextField.text")); // NOI18N
pathNameTextField.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
pathNameTextFieldActionPerformed(evt);
}
});
javax.swing.GroupLayout typePanelLayout = new javax.swing.GroupLayout(typePanel);
typePanel.setLayout(typePanelLayout);
typePanelLayout.setHorizontalGroup(
typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 0, Short.MAX_VALUE)
);
typePanelLayout.setVerticalGroup(
typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 57, Short.MAX_VALUE)
);
org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(MissingImageDialog.class, "MissingImageDialog.browseButton.text")); // NOI18N
browseButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
browseButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout containerPanelLayout = new javax.swing.GroupLayout(containerPanel);
containerPanel.setLayout(containerPanelLayout);
containerPanelLayout.setHorizontalGroup(
containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(containerPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(typePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(containerPanelLayout.createSequentialGroup()
.addComponent(typeTabel)
.addGap(18, 18, 18)
.addComponent(typeComboBox, 0, 298, Short.MAX_VALUE)))
.addContainerGap())
.addContainerGap()
.addComponent(pathNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 285, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(browseButton)
.addContainerGap(83, Short.MAX_VALUE))
);
containerPanelLayout.setVerticalGroup(
containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(containerPanelLayout.createSequentialGroup()
.addGap(0, 0, 0)
.addGap(18, 18, 18)
.addGroup(containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(typeTabel)
.addComponent(typeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(typePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addContainerGap())
.addComponent(pathNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(browseButton))
.addContainerGap(62, Short.MAX_VALUE))
);
titleLabel.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N
@@ -268,7 +259,7 @@ public class MissingImageDialog extends javax.swing.JDialog {
private void selectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectButtonActionPerformed
try {
String newPath = currentPanel.getContentPaths();
String newPath = pathNameTextField.getText();
//TODO handle local files
db.setImagePaths(obj_id, Arrays.asList(new String[]{newPath}));
} catch (TskCoreException ex) {
@@ -281,21 +272,48 @@ public class MissingImageDialog extends javax.swing.JDialog {
cancel();
}//GEN-LAST:event_cancelButtonActionPerformed
private void pathNameTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pathNameTextFieldActionPerformed
// TODO add your handling code here:
updateSelectButton();
}//GEN-LAST:event_pathNameTextFieldActionPerformed
private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
String oldText = pathNameTextField.getText();
// set the current directory of the FileChooser if the ImagePath Field is valid
File currentDir = new File(oldText);
if (currentDir.exists()) {
fc.setCurrentDirectory(currentDir);
}
int retval = fc.showOpenDialog(this);
if (retval == JFileChooser.APPROVE_OPTION) {
String path = fc.getSelectedFile().getPath();
pathNameTextField.setText(path);
}
//pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.FOCUS_NEXT.toString(), false, true);
updateSelectButton();
}//GEN-LAST:event_browseButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton browseButton;
private javax.swing.JPanel buttonPanel;
private javax.swing.JButton cancelButton;
private javax.swing.JPanel containerPanel;
private javax.swing.JTextField pathNameTextField;
private javax.swing.JButton selectButton;
private javax.swing.JLabel titleLabel;
private javax.swing.JSeparator titleSeparator;
private javax.swing.JComboBox typeComboBox;
private javax.swing.JPanel typePanel;
private javax.swing.JLabel typeTabel;
// End of variables declaration//GEN-END:variables
/**
* Verify the user wants to cancel searching for the image.
*/
//
// * Verify the user wants to cancel searching for the image.
//
void cancel() {
int ret = JOptionPane.showConfirmDialog(null,
"No image file has been selected, are you sure you\n" +
@@ -306,40 +324,5 @@ public class MissingImageDialog extends javax.swing.JDialog {
}
}
/**
* ComboBoxModel to control typeComboBox and supply ImageTypePanels.
*/
private class ImageTypeModel implements ComboBoxModel {
ContentTypePanel selected;
ContentTypePanel[] types = ContentTypePanel.getPanels();
@Override
public void setSelectedItem(Object anItem) {
selected = (ContentTypePanel) anItem;
updateCurrentPanel(selected);
}
@Override
public Object getSelectedItem() {
return selected;
}
@Override
public int getSize() {
return types.length;
}
@Override
public Object getElementAt(int index) {
return types[index];
}
@Override
public void addListDataListener(ListDataListener l) {
}
@Override
public void removeListDataListener(ListDataListener l) {
}
}
}
}

View File

@@ -2,7 +2,7 @@
*
* Autopsy Forensic Browser
*
* Copyright 2012 Basis Technology Corp.
* Copyright 2012-2013 Basis Technology Corp.
*
* Copyright 2012 42six Solutions.
* Contact: aebadirad <at> 42six <dot> com
@@ -37,21 +37,29 @@ public class Services implements Closeable {
// NOTE: all new services added to Services class must be added to this list
// of services.
private List<Closeable> services = new ArrayList<Closeable>();
private List<Closeable> services = new ArrayList<>();
// services
private FileManager fileManager;
private TagsManager tagsManager;
public Services(SleuthkitCase tskCase) {
this.tskCase = tskCase;
//create and initialize FileManager as early as possibly in the new/opened Case
fileManager = new FileManager(tskCase);
services.add(fileManager);
tagsManager = new TagsManager(tskCase);
services.add(tagsManager);
}
public FileManager getFileManager() {
return fileManager;
}
public TagsManager getTagsManager() {
return tagsManager;
}
@Override
public void close() throws IOException {

View File

@@ -0,0 +1,464 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.casemodule.services;
import java.io.Closeable;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
/**
* A per case instance of this class functions as an Autopsy service that
* manages the creation, updating, and deletion of tags applied to content and
* blackboard artifacts by users.
*/
public class TagsManager implements Closeable {
private static final String TAGS_SETTINGS_NAME = "Tags";
private static final String TAG_NAMES_SETTING_KEY = "TagNames";
private final SleuthkitCase tskCase;
private final HashMap<String, TagName> uniqueTagNames = new HashMap<>();
private boolean tagNamesInitialized = false; // @@@ This is part of a work around to be removed when database access on the EDT is correctly synchronized.
// Use this exception and the member hash map to manage uniqueness of hash
// names. This is deemed more proactive and informative than leaving this to
// the UNIQUE constraint on the display_name field of the tag_names table in
// the case database.
public class TagNameAlreadyExistsException extends Exception {
}
/**
* Package-scope constructor for use of the Services class. An instance of
* TagsManager should be created for each case that is opened.
* @param [in] tskCase The SleuthkitCase object for the current case.
*/
TagsManager(SleuthkitCase tskCase) {
this.tskCase = tskCase;
// @@@ The removal of this call is a work around until database access on the EDT is correctly synchronized.
// getExistingTagNames();
}
/**
* Gets a list of all tag names currently available for tagging content or
* blackboard artifacts.
* @return A list, possibly empty, of TagName data transfer objects (DTOs).
* @throws TskCoreException
*/
public synchronized List<TagName> getAllTagNames() throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.getAllTagNames();
}
/**
* Gets a list of all tag names currently used for tagging content or
* blackboard artifacts.
* @return A list, possibly empty, of TagName data transfer objects (DTOs).
* @throws TskCoreException
*/
public synchronized List<TagName> getTagNamesInUse() throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.getTagNamesInUse();
}
/**
* Checks whether a tag name with a given display name exists.
* @param [in] tagDisplayName The display name for which to check.
* @return True if the tag name exists, false otherwise.
*/
public synchronized boolean tagNameExists(String tagDisplayName) {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return uniqueTagNames.containsKey(tagDisplayName);
}
/**
* Adds a new tag name to the current case and to the tags settings.
* @param [in] displayName The display name for the new tag name.
* @return A TagName data transfer object (DTO) representing the new tag name.
* @throws TagNameAlreadyExistsException, TskCoreException
*/
public TagName addTagName(String displayName) throws TagNameAlreadyExistsException, TskCoreException {
return addTagName(displayName, "", TagName.HTML_COLOR.NONE);
}
/**
* Adds a new tag name to the current case and to the tags settings.
* @param [in] displayName The display name for the new tag name.
* @param [in] description The description for the new tag name.
* @return A TagName data transfer object (DTO) representing the new tag name.
* @throws TagNameAlreadyExistsException, TskCoreException
*/
public TagName addTagName(String displayName, String description) throws TagNameAlreadyExistsException, TskCoreException {
return addTagName(displayName, description, TagName.HTML_COLOR.NONE);
}
/**
* Adds a new tag name to the current case and to the tags settings.
* @param [in] displayName The display name for the new tag name.
* @param [in] description The description for the new tag name.
* @param [in] color The HTML color to associate with the new tag name.
* @return A TagName data transfer object (DTO) representing the new tag name.
* @throws TagNameAlreadyExistsException, TskCoreException
*/
public synchronized TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TagNameAlreadyExistsException, TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
if (uniqueTagNames.containsKey(displayName)) {
throw new TagNameAlreadyExistsException();
}
// Add the tag name to the case.
TagName newTagName = tskCase.addTagName(displayName, description, color);
// Add the tag name to the tags settings.
uniqueTagNames.put(newTagName.getDisplayName(), newTagName);
saveTagNamesToTagsSettings();
return newTagName;
}
/**
* Tags a content object.
* @param [in] content The content to tag.
* @param [in] tagName The name to use for the tag.
* @return A ContentTag data transfer object (DTO) representing the new tag.
* @throws TskCoreException
*/
public ContentTag addContentTag(Content content, TagName tagName) throws TskCoreException {
return addContentTag(content, tagName, "", -1, -1);
}
/**
* Tags a content object.
* @param [in] content The content to tag.
* @param [in] tagName The name to use for the tag.
* @param [in] comment A comment to store with the tag.
* @return A ContentTag data transfer object (DTO) representing the new tag.
* @throws TskCoreException
*/
public ContentTag addContentTag(Content content, TagName tagName, String comment) throws TskCoreException {
return addContentTag(content, tagName, comment, -1, -1);
}
/**
* Tags a content object or a section of a content object.
* @param [in] content The content to tag.
* @param [in] tagName The name to use for the tag.
* @param [in] comment A comment to store with the tag.
* @param [in] beginByteOffset Designates the beginning of a tagged section.
* @param [in] endByteOffset Designates the end of a tagged section.
* @return A ContentTag data transfer object (DTO) representing the new tag.
* @throws IllegalArgumentException, TskCoreException
*/
public synchronized ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws IllegalArgumentException, TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
if (beginByteOffset >= 0 && endByteOffset >= 1) {
if (beginByteOffset > content.getSize() - 1) {
throw new IllegalArgumentException("beginByteOffset = " + beginByteOffset + " out of content size range (0 - " + (content.getSize() - 1) + ")");
}
if (endByteOffset > content.getSize() - 1) {
throw new IllegalArgumentException("endByteOffset = " + endByteOffset + " out of content size range (0 - " + (content.getSize() - 1) + ")");
}
if (endByteOffset < beginByteOffset) {
throw new IllegalArgumentException("endByteOffset < beginByteOffset");
}
}
return tskCase.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset);
}
/**
* Deletes a content tag.
* @param [in] tag The tag to delete.
* @throws TskCoreException
*/
public synchronized void deleteContentTag(ContentTag tag) throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
tskCase.deleteContentTag(tag);
}
/**
* Gets all content tags for the current case.
* @return A list, possibly empty, of content tags.
* @throws TskCoreException
*/
public List<ContentTag> getAllContentTags() throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.getAllContentTags();
}
/**
* Gets content tags count by tag name.
* @param [in] tagName The tag name of interest.
* @return A count of the content tags with the specified tag name.
* @throws TskCoreException
*/
public synchronized long getContentTagsCountByTagName(TagName tagName) throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.getContentTagsCountByTagName(tagName);
}
/**
* Gets content tags by tag name.
* @param [in] tagName The tag name of interest.
* @return A list, possibly empty, of the content tags with the specified tag name.
* @throws TskCoreException
*/
public synchronized List<ContentTag> getContentTagsByTagName(TagName tagName) throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.getContentTagsByTagName(tagName);
}
/**
* Gets content tags count by content.
* @param [in] content The content of interest.
* @return A list, possibly empty, of the tags that have been applied to the artifact.
* @throws TskCoreException
*/
public synchronized List<ContentTag> getContentTagsByContent(Content content) throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.getContentTagsByContent(content);
}
/**
* Tags a blackboard artifact object.
* @param [in] artifact The blackboard artifact to tag.
* @param [in] tagName The name to use for the tag.
* @return A BlackboardArtifactTag data transfer object (DTO) representing the new tag.
* @throws TskCoreException
*/
public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName) throws TskCoreException {
return addBlackboardArtifactTag(artifact, tagName, "");
}
/**
* Tags a blackboard artifact object.
* @param [in] artifact The blackboard artifact to tag.
* @param [in] tagName The name to use for the tag.
* @param [in] comment A comment to store with the tag.
* @return A BlackboardArtifactTag data transfer object (DTO) representing the new tag.
* @throws TskCoreException
*/
public synchronized BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.addBlackboardArtifactTag(artifact, tagName, comment);
}
/**
* Deletes a blackboard artifact tag.
* @param [in] tag The tag to delete.
* @throws TskCoreException
*/
public synchronized void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
tskCase.deleteBlackboardArtifactTag(tag);
}
/**
* Gets all blackboard artifact tags for the current case.
* @return A list, possibly empty, of blackboard artifact tags.
* @throws TskCoreException
*/
public List<BlackboardArtifactTag> getAllBlackboardArtifactTags() throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.getAllBlackboardArtifactTags();
}
/**
* Gets blackboard artifact tags count by tag name.
* @param [in] tagName The tag name of interest.
* @return A count of the blackboard artifact tags with the specified tag name.
* @throws TskCoreException
*/
public synchronized long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.getBlackboardArtifactTagsCountByTagName(tagName);
}
/**
* Gets blackboard artifact tags by tag name.
* @param [in] tagName The tag name of interest.
* @return A list, possibly empty, of the blackboard artifact tags with the specified tag name.
* @throws TskCoreException
*/
public synchronized List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.getBlackboardArtifactTagsByTagName(tagName);
}
/**
* Gets blackboard artifact tags for a particular blackboard artifact.
* @param [in] artifact The blackboard artifact of interest.
* @return A list, possibly empty, of the tags that have been applied to the artifact.
* @throws TskCoreException
*/
public synchronized List<BlackboardArtifactTag> getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.getBlackboardArtifactTagsByArtifact(artifact);
}
@Override
public void close() throws IOException {
saveTagNamesToTagsSettings();
}
private void getExistingTagNames() {
getTagNamesFromCurrentCase();
getTagNamesFromTagsSettings();
getPredefinedTagNames();
saveTagNamesToTagsSettings();
tagNamesInitialized = true; // @@@ This is part of a work around to be removed when database access on the EDT is correctly synchronized.
}
private void getTagNamesFromCurrentCase() {
try {
List<TagName> currentTagNames = tskCase.getAllTagNames();
for (TagName tagName : currentTagNames) {
uniqueTagNames.put(tagName.getDisplayName(), tagName);
}
}
catch (TskCoreException ex) {
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag types from the current case", ex);
}
}
private void getTagNamesFromTagsSettings() {
String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY);
if (null != setting && !setting.isEmpty()) {
// Read the tag name setting and break it into tag name tuples.
List<String> tagNameTuples = Arrays.asList(setting.split(";"));
// Parse each tuple and add the tag names to the current case, one
// at a time to gracefully discard any duplicates or corrupt tuples.
for (String tagNameTuple : tagNameTuples) {
String[] tagNameAttributes = tagNameTuple.split(",");
if (!uniqueTagNames.containsKey(tagNameAttributes[0])) {
try {
TagName tagName = tskCase.addTagName(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.getColorByName(tagNameAttributes[2]));
uniqueTagNames.put(tagName.getDisplayName(), tagName);
}
catch (TskCoreException ex) {
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add saved tag name " + tagNameAttributes[0], ex);
}
}
}
}
}
private void getPredefinedTagNames() {
if (!uniqueTagNames.containsKey("Bookmark")) {
try {
TagName tagName = tskCase.addTagName("Bookmark", "", TagName.HTML_COLOR.NONE);
uniqueTagNames.put(tagName.getDisplayName(), tagName);
}
catch (TskCoreException ex) {
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add predefined 'Bookmark' tag name", ex);
}
}
}
private void saveTagNamesToTagsSettings() {
if (!uniqueTagNames.isEmpty()) {
StringBuilder setting = new StringBuilder();
for (TagName tagName : uniqueTagNames.values()) {
if (setting.length() != 0) {
setting.append(";");
}
setting.append(tagName.getDisplayName()).append(",");
setting.append(tagName.getDescription()).append(",");
setting.append(tagName.getColor().name());
}
ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString());
}
}
}

View File

@@ -157,7 +157,7 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer
@Override
public String getToolTip() {
return "";
return "Displays metadata about the file.";
}
@Override

View File

@@ -26,8 +26,8 @@ import javafx.embed.swing.JFXPanel;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.openide.modules.ModuleInstall;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
/**
* Wrapper over Installers in packages in Core module This is the main
@@ -39,6 +39,41 @@ public class Installer extends ModuleInstall {
private static final Logger logger = Logger.getLogger(Installer.class.getName());
private static volatile boolean javaFxInit = false;
static {
loadDynLibraries();
}
private static void loadDynLibraries() {
if (PlatformUtil.isWindowsOS()) {
try {
//on windows force loading ms crt dependencies first
//in case linker can't find them on some systems
//Note: if shipping with a different CRT version, this will only print a warning
//and try to use linker mechanism to find the correct versions of libs.
//We should update this if we officially switch to a new version of CRT/compiler
System.loadLibrary("msvcr100");
System.loadLibrary("msvcp100");
logger.log(Level.INFO, "MS CRT libraries loaded");
} catch (UnsatisfiedLinkError e) {
logger.log(Level.SEVERE, "Error loading ms crt libraries, ", e);
}
try {
System.loadLibrary("zlib");
logger.log(Level.INFO, "ZLIB library loaded loaded");
} catch (UnsatisfiedLinkError e) {
logger.log(Level.SEVERE, "Error loading ZLIB library, ", e);
}
try {
System.loadLibrary("libewf");
logger.log(Level.INFO, "EWF library loaded");
} catch (UnsatisfiedLinkError e) {
logger.log(Level.SEVERE, "Error loading EWF library, ", e);
}
}
}
public Installer() {
logger.log(Level.INFO, "core installer created");
javaFxInit = false;

View File

@@ -0,0 +1,38 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 - 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.corecomponentinterfaces;
import java.util.List;
import javax.swing.Action;
/**
* Implementers of this interface provide Actions that will be added to context
* 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
* org.sleuthkit.datamodel classes of interest to the provider.
* @return A list, possibly empty, of Action objects.
*/
public List<Action> getActions();
}

View File

@@ -0,0 +1,66 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.corecomponentinterfaces;
import java.awt.EventQueue;
import java.util.List;
import org.sleuthkit.datamodel.Content;
/**
* Abstract class for a callback for a DataSourceProcessor.
*
* Ensures that DSP invokes the caller overridden method, doneEDT(),
* in the EDT thread.
*
*/
public abstract class DSPCallback {
public enum DSP_Result
{
NO_ERRORS,
CRITICAL_ERRORS,
NONCRITICAL_ERRORS,
};
/*
* Invoke the caller supplied callback function on the EDT thread
*/
public void done(DSP_Result result, List<String> errList, List<Content> newContents)
{
final DSP_Result resultf = result;
final List<String> errListf = errList;
final List<Content> newContentsf = newContents;
// Invoke doneEDT() that runs on the EDT .
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
doneEDT(resultf, errListf, newContentsf );
}
});
}
/*
* calling code overrides to provide its own calllback
*/
public abstract void doneEDT(DSP_Result result, List<String> errList, List<Content> newContents);
};

View File

@@ -0,0 +1,33 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.corecomponentinterfaces;
/*
* An GUI agnostic DSPProgressMonitor interface for DataSourceProcesssors to
* indicate progress.
* It models after a JProgressbar though it could use any underlying implementation
*/
public interface DSPProgressMonitor {
void setIndeterminate(boolean indeterminate);
void setProgress(int progress);
void setProgressText(String text);
}

View File

@@ -0,0 +1,92 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.corecomponentinterfaces;
import javax.swing.JPanel;
/*
* Defines an interface used by the Add DataSource wizard to discover different
* Data SourceProcessors.
*
* Each data source may have its unique attributes and may need to be processed
* differently.
*
* The DataSourceProcessor interface defines a uniform mechanism for the Autopsy UI
* to:
* - collect details for the data source to be processed.
* - Process the data source in the background
* - Be notified when the processing is complete
*/
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
*/
enum DSP_PANEL_EVENT {
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, floowing the panel.
};
/**
* Returns the type of Data Source it handles.
* This name gets displayed in the drop-down listbox
**/
String getType();
/**
* Returns the picker panel to be displayed along with any other
* runtime options supported by the data source handler.
**/
JPanel getPanel();
/**
* Called to validate the input data in the panel.
* Returns true if no errors, or
* Returns false if there is an error.
**/
boolean validatePanel();
/**
* Called to invoke the handling of Data source in the background.
* Returns after starting the background thread
* @param settings wizard settings to read/store properties
* @param progressPanel progress panel to be updated while processing
*
**/
void run(DSPProgressMonitor progressPanel, DSPCallback dspCallback);
/**
* Called to cancel the background processing.
**/
void cancel();
/**
* Called to reset/reinitialize the DSP.
*
**/
void reset();
}

View File

@@ -299,7 +299,6 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
currentPage = page;
long offset = (currentPage - 1) * pageLength;
// change the cursor to "waiting cursor" for this operation
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
@@ -344,13 +343,13 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
// set the output view
if (errorText == null) {
int showLength = bytesRead < pageLength ? bytesRead : (int) pageLength;
outputViewPane.setText(DataConversion.byteArrayToHex(data, showLength, offset, outputViewPane.getFont()));
outputViewPane.setText(DataConversion.byteArrayToHex(data, showLength, offset));
}
else {
outputViewPane.setText(errorText);
}
outputViewPane.moveCaretPosition(0);
outputViewPane.setCaretPosition(0);
this.setCursor(null);
}

View File

@@ -362,6 +362,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
this.rootNode.addNodeListener(dummyNodeListener);
}
resetTabs(selectedNode);
setupTabs(selectedNode);
if (selectedNode != null) {
@@ -369,58 +370,42 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
this.numberMatchLabel.setText(Integer.toString(childrenCount));
}
this.numberMatchLabel.setVisible(true);
resetTabs(selectedNode);
// set the display on the current active tab
int currentActiveTab = this.dataResultTabbedPanel.getSelectedIndex();
if (currentActiveTab != -1) {
UpdateWrapper drv = viewers.get(currentActiveTab);
drv.setNode(selectedNode);
}
}
private void setupTabs(final Node selectedNode) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
//update/disable tabs based on if supported for this node
int drvC = 0;
for (UpdateWrapper drv : viewers) {
private void setupTabs(Node selectedNode) {
//update/disable tabs based on if supported for this node
int drvC = 0;
for (UpdateWrapper drv : viewers) {
if (drv.isSupported(selectedNode)) {
dataResultTabbedPanel.setEnabledAt(drvC, true);
} else {
dataResultTabbedPanel.setEnabledAt(drvC, false);
}
++drvC;
}
if (drv.isSupported(selectedNode)) {
dataResultTabbedPanel.setEnabledAt(drvC, true);
} else {
dataResultTabbedPanel.setEnabledAt(drvC, false);
}
++drvC;
}
// if the current tab is no longer enabled, then find one that is
boolean hasViewerEnabled = true;
int currentActiveTab = dataResultTabbedPanel.getSelectedIndex();
if ((currentActiveTab == -1) || (dataResultTabbedPanel.isEnabledAt(currentActiveTab) == false)) {
hasViewerEnabled = false;
for (int i = 0; i < dataResultTabbedPanel.getTabCount(); i++) {
if (dataResultTabbedPanel.isEnabledAt(i)) {
currentActiveTab = i;
hasViewerEnabled = true;
break;
}
}
if (hasViewerEnabled) {
dataResultTabbedPanel.setSelectedIndex(currentActiveTab);
}
}
if (hasViewerEnabled) {
viewers.get(currentActiveTab).setNode(selectedNode);
// if the current tab is no longer enabled, then find one that is
boolean hasViewerEnabled = true;
int currentActiveTab = dataResultTabbedPanel.getSelectedIndex();
if ((currentActiveTab == -1) || (dataResultTabbedPanel.isEnabledAt(currentActiveTab) == false)) {
hasViewerEnabled = false;
for (int i = 0; i < dataResultTabbedPanel.getTabCount(); i++) {
if (dataResultTabbedPanel.isEnabledAt(i)) {
currentActiveTab = i;
hasViewerEnabled = true;
break;
}
}
});
if (hasViewerEnabled) {
dataResultTabbedPanel.setSelectedIndex(currentActiveTab);
}
}
if (hasViewerEnabled) {
viewers.get(currentActiveTab).setNode(selectedNode);
}
}
@Override
@@ -622,12 +607,22 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
}
@Override
public void childrenAdded(NodeMemberEvent nme) {
public void childrenAdded(final NodeMemberEvent nme) {
Node[] delta = nme.getDelta();
if (load && containsReal(delta)) {
load = false;
setupTabs(nme.getNode());
updateMatches();
if (SwingUtilities.isEventDispatchThread()) {
setupTabs(nme.getNode());
updateMatches();
} else {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
setupTabs(nme.getNode());
updateMatches();
}
});
}
}
}
@@ -645,14 +640,9 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
*
*/
private void updateMatches() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (rootNode != null && rootNode.getChildren() != null) {
setNumMatches(rootNode.getChildren().getNodesCount());
}
}
});
if (rootNode != null && rootNode.getChildren() != null) {
setNumMatches(rootNode.getChildren().getNodesCount());
}
}
@Override

View File

@@ -215,18 +215,17 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
*/
private void getAllChildPropertyHeadersRec(Node parent, int rows) {
Children children = parent.getChildren();
int total = Math.min(rows, children.getNodesCount());
for (int i = 0; i < total; i++) {
Node child = children.getNodeAt(i);
int childCount = 0;
for (Node child : children.getNodes()) {
if (++childCount > rows) {
break;
}
for (PropertySet ps : child.getPropertySets()) {
//if (ps.getName().equals(Sheet.PROPERTIES)) {
//return ps.getProperties();
final Property[] props = ps.getProperties();
final int propsNum = props.length;
for (int j = 0; j < propsNum; ++j) {
propertiesAcc.add(props[j]);
}
//}
}
getAllChildPropertyHeadersRec(child, rows);
}
@@ -278,137 +277,131 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
* @param root The parent Node of the ContentNodes
*/
private void setupTable(final Node root) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
//wrap to filter out children
//note: this breaks the tree view mode in this generic viewer,
//so wrap nodes earlier if want 1 level view
//if (!(root instanceof TableFilterNode)) {
/// root = new TableFilterNode(root, true);
//}
//wrap to filter out children
//note: this breaks the tree view mode in this generic viewer,
//so wrap nodes earlier if want 1 level view
//if (!(root instanceof TableFilterNode)) {
/// root = new TableFilterNode(root, true);
//}
em.setRootContext(root);
em.setRootContext(root);
final OutlineView ov = ((OutlineView) DataResultViewerTable.this.tableScrollPanel);
final OutlineView ov = ((OutlineView) DataResultViewerTable.this.tableScrollPanel);
if (ov == null) {
return;
}
propertiesAcc.clear();
DataResultViewerTable.this.getAllChildPropertyHeadersRec(root, 100);
List<Node.Property> props = new ArrayList<Node.Property>(propertiesAcc);
if (props.size() > 0) {
Node.Property prop = props.remove(0);
((DefaultOutlineModel) ov.getOutline().getOutlineModel()).setNodesColumnLabel(prop.getDisplayName());
}
// *********** Make the TreeTableView to be sortable ***************
//First property column is sortable, but also sorted initially, so
//initially this one will have the arrow icon:
if (props.size() > 0) {
props.get(0).setValue("TreeColumnTTV", Boolean.TRUE); // Identifies special property representing first (tree) column.
props.get(0).setValue("SortingColumnTTV", Boolean.TRUE); // TreeTableView should be initially sorted by this property column.
}
// The rest of the columns are sortable, but not initially sorted,
// so initially will have no arrow icon:
String[] propStrings = new String[props.size() * 2];
for (int i = 0; i < props.size(); i++) {
props.get(i).setValue("ComparableColumnTTV", Boolean.TRUE);
propStrings[2 * i] = props.get(i).getName();
propStrings[2 * i + 1] = props.get(i).getDisplayName();
}
ov.setPropertyColumns(propStrings);
// *****************************************************************
// // set the first entry
// Children test = root.getChildren();
// Node firstEntryNode = test.getNodeAt(0);
// try {
// this.getExplorerManager().setSelectedNodes(new Node[]{firstEntryNode});
// } catch (PropertyVetoException ex) {}
// show the horizontal scroll panel and show all the content & header
int totalColumns = props.size();
//int scrollWidth = ttv.getWidth();
int margin = 4;
int startColumn = 1;
if (ov == null) {
return;
}
propertiesAcc.clear();
DataResultViewerTable.this.getAllChildPropertyHeadersRec(root, 100);
List<Node.Property> props = new ArrayList<Node.Property>(propertiesAcc);
if (props.size() > 0) {
Node.Property prop = props.remove(0);
((DefaultOutlineModel) ov.getOutline().getOutlineModel()).setNodesColumnLabel(prop.getDisplayName());
}
// *********** Make the TreeTableView to be sortable ***************
//First property column is sortable, but also sorted initially, so
//initially this one will have the arrow icon:
if (props.size() > 0) {
props.get(0).setValue("TreeColumnTTV", Boolean.TRUE); // Identifies special property representing first (tree) column.
props.get(0).setValue("SortingColumnTTV", Boolean.TRUE); // TreeTableView should be initially sorted by this property column.
}
// The rest of the columns are sortable, but not initially sorted,
// so initially will have no arrow icon:
String[] propStrings = new String[props.size() * 2];
for (int i = 0; i < props.size(); i++) {
props.get(i).setValue("ComparableColumnTTV", Boolean.TRUE);
propStrings[2 * i] = props.get(i).getName();
propStrings[2 * i + 1] = props.get(i).getDisplayName();
}
ov.setPropertyColumns(propStrings);
// *****************************************************************
// // set the first entry
// Children test = root.getChildren();
// Node firstEntryNode = test.getNodeAt(0);
// try {
// this.getExplorerManager().setSelectedNodes(new Node[]{firstEntryNode});
// } catch (PropertyVetoException ex) {}
// show the horizontal scroll panel and show all the content & header
int totalColumns = props.size();
//int scrollWidth = ttv.getWidth();
int margin = 4;
int startColumn = 1;
// If there is only one column (which was removed from props above)
// Just let the table resize itself.
ov.getOutline().setAutoResizeMode((props.size() > 0) ? JTable.AUTO_RESIZE_OFF : JTable.AUTO_RESIZE_ALL_COLUMNS);
// If there is only one column (which was removed from props above)
// 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);
// get first 100 rows values for the table
Object[][] content = null;
content = getRowValues(root, 100);
if (content != null) {
// get the fontmetrics
final Graphics graphics = ov.getGraphics();
if (graphics != null) {
final FontMetrics metrics = graphics.getFontMetrics();
if (content != null) {
// get the fontmetrics
final Graphics graphics = ov.getGraphics();
if (graphics != null) {
final FontMetrics metrics = graphics.getFontMetrics();
// for the "Name" column
int nodeColWidth = Math.min(getMaxColumnWidth(0, metrics, margin, 40, firstColumnLabel, content), 250); // Note: 40 is the width of the icon + node lines. Change this value if those values change!
ov.getOutline().getColumnModel().getColumn(0).setPreferredWidth(nodeColWidth);
// for the "Name" column
int nodeColWidth = Math.min(getMaxColumnWidth(0, metrics, margin, 40, firstColumnLabel, content), 250); // Note: 40 is the width of the icon + node lines. Change this value if those values change!
ov.getOutline().getColumnModel().getColumn(0).setPreferredWidth(nodeColWidth);
// get the max for each other column
for (int colIndex = startColumn; colIndex <= totalColumns; colIndex++) {
int colWidth = Math.min(getMaxColumnWidth(colIndex, metrics, margin, 8, props, content), 350);
ov.getOutline().getColumnModel().getColumn(colIndex).setPreferredWidth(colWidth);
}
}
}
// if there's no content just auto resize all columns
if (!(content.length > 0)) {
// turn on the auto resize
ov.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
}
}
});
}
private static Object[][] getRowValues(Node node, int rows) {
// how many rows are we returning
int maxRows = Math.min(rows, node.getChildren().getNodesCount());
Object[][] objs = new Object[maxRows][];
for (int i = 0; i < maxRows; i++) {
PropertySet[] props = node.getChildren().getNodeAt(i).getPropertySets();
if (props.length == 0) //rare special case
{
continue;
}
Property[] property = props[0].getProperties();
objs[i] = new Object[property.length];
for (int j = 0; j < property.length; j++) {
try {
objs[i][j] = property[j].getValue();
} catch (IllegalAccessException ignore) {
objs[i][j] = "n/a";
} catch (InvocationTargetException ignore) {
objs[i][j] = "n/a";
// get the max for each other column
for (int colIndex = startColumn; colIndex <= totalColumns; colIndex++) {
int colWidth = Math.min(getMaxColumnWidth(colIndex, metrics, margin, 8, props, content), 350);
ov.getOutline().getColumnModel().getColumn(colIndex).setPreferredWidth(colWidth);
}
}
}
return objs;
// if there's no content just auto resize all columns
if (!(content.length > 0)) {
// turn on the auto resize
ov.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
}
}
// Populate a two-dimensional array with rows of property values for up
// to maxRows children of the node passed in.
private static Object[][] getRowValues(Node node, int maxRows) {
Object[][] rowValues = new Object[Math.min(maxRows, node.getChildren().getNodesCount())][];
int rowCount = 0;
for (Node child : node.getChildren().getNodes()) {
if (rowCount >= maxRows) {
break;
}
PropertySet[] propertySets = child.getPropertySets();
if (propertySets.length > 0)
{
Property[] properties = propertySets[0].getProperties();
rowValues[rowCount] = new Object[properties.length];
for (int j = 0; j < properties.length; ++j) {
try {
rowValues[rowCount][j] = properties[j].getValue();
}
catch (IllegalAccessException | InvocationTargetException ignore) {
rowValues[rowCount][j] = "n/a";
}
}
}
++rowCount;
}
return rowValues;
}
@Override
@@ -492,11 +485,20 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
}
@Override
public void childrenAdded(NodeMemberEvent nme) {
public void childrenAdded(final NodeMemberEvent nme) {
Node[] delta = nme.getDelta();
if (load && containsReal(delta)) {
load = false;
setupTable(nme.getNode());
if (SwingUtilities.isEventDispatchThread()) {
setupTable(nme.getNode());
} else {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
setupTable(nme.getNode());
}
});
}
}
}

View File

@@ -0,0 +1,50 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 - 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.coreutils;
import org.openide.util.Lookup;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.swing.Action;
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
* ContextMenuActionsProvider interface.
* @return A list, possibly empty, of Action objects.
*/
static public List<Action> getActions() {
ArrayList<Action> actions = new ArrayList<>();
Collection<? extends ContextMenuActionsProvider> actionProviders = Lookup.getDefault().lookupAll(ContextMenuActionsProvider.class);
for (ContextMenuActionsProvider provider : actionProviders) {
List<Action> providerActions = provider.getActions();
if (!providerActions.isEmpty()) {
actions.add(null); // Separator to set off this provider's actions.
actions.addAll(provider.getActions());
actions.add(null); // Separator to set off this provider's actions.
}
}
return actions;
}
}

View File

@@ -146,6 +146,12 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
return "Known";
}
},
HASHSETS {
@Override
public String toString() {
return "In Hashsets";
}
},
MD5HASH {
@Override
public String toString() {
@@ -188,6 +194,7 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
map.put(AbstractFilePropertyType.TYPE_DIR.toString(), content.getDirType().getLabel());
map.put(AbstractFilePropertyType.TYPE_META.toString(), content.getMetaType().toString());
map.put(AbstractFilePropertyType.KNOWN.toString(), content.getKnown().getName());
map.put(AbstractFilePropertyType.HASHSETS.toString(), HashsetHits.getList(content.getSleuthkitCase(), content.getId()));
map.put(AbstractFilePropertyType.MD5HASH.toString(), content.getMd5Hash() == null ? "" : content.getMd5Hash());
}

View File

@@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.datamodel;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children.Keys;
import org.openide.nodes.Node;
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode;
import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.Directory;
@@ -157,8 +156,8 @@ abstract class AbstractContentChildren<T> extends Keys<T> {
}
@Override
public AbstractNode visit(Tags t) {
return t.new TagsRootNode();
public AbstractNode visit(TagsNodeKey tagsNodeKey) {
return new TagsNode();
}
@Override

View File

@@ -128,11 +128,6 @@ public class ArtifactTypeNode extends DisplayableItemNode {
return "artifact-icon.png";
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.META;
}
@Override
public boolean isLeafTypeNode() {
return true;

View File

@@ -52,14 +52,14 @@ public interface AutopsyItemVisitor<T> {
T visit(EmailExtracted ee);
T visit(Tags t);
T visit(TagsNodeKey tagsNodeKey);
T visit(DataSources i);
T visit(Views v);
T visit(Results r);
static abstract public class Default<T> implements AutopsyItemVisitor<T> {
protected abstract T defaultVisit(AutopsyVisitableItem ec);
@@ -135,8 +135,8 @@ public interface AutopsyItemVisitor<T> {
}
@Override
public T visit(Tags t) {
return defaultVisit(t);
public T visit(TagsNodeKey tagsNodeKey) {
return defaultVisit(tagsNodeKey);
}
@Override

View File

@@ -33,6 +33,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskException;
@@ -140,7 +141,12 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
} else {
String dataSource = "";
try {
dataSource = associated.getImage().getName();
Image image = associated.getImage();
if (image != null) {
dataSource = image.getName();
} else {
dataSource = getRootParentName();
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Failed to get image name from " + associated.getName());
}
@@ -153,6 +159,20 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
return s;
}
private String getRootParentName() {
String parentName = associated.getName();
Content parent = associated;
try {
while ((parent = parent.getParent()) != null) {
parentName = parent.getName();
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Failed to get parent name from " + associated.getName());
return "";
}
return parentName;
}
/**
* Add an additional custom node property to that node before it is
@@ -334,11 +354,6 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
return "artifact-icon.png";
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
}
@Override
public boolean isLeafTypeNode() {
return true;

View File

@@ -0,0 +1,94 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.datamodel;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Action;
import org.openide.nodes.Children;
import org.openide.nodes.Sheet;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.actions.DeleteBlackboardArtifactTagAction;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Instances of this class wrap BlackboardArtifactTag objects. In the Autopsy
* presentation of the SleuthKit data model, they are leaf nodes of a sub-tree
* organized as follows: there is a tags root node with tag name child nodes;
* tag name nodes have tag type child nodes; tag type nodes are the parents of
* either content or blackboard artifact tag nodes.
*/
public class BlackboardArtifactTagNode extends DisplayableItemNode {
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/green-tag-icon-16.png";
private final BlackboardArtifactTag tag;
public BlackboardArtifactTagNode(BlackboardArtifactTag tag) {
super(Children.LEAF, Lookups.fixed(tag, tag.getArtifact(), tag.getContent()));
super.setName(tag.getContent().getName());
super.setDisplayName(tag.getContent().getName());
this.setIconBaseWithExtension(ICON_PATH);
this.tag = tag;
}
@Override
protected Sheet createSheet() {
Sheet propertySheet = super.createSheet();
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
if (properties == null) {
properties = Sheet.createPropertiesSet();
propertySheet.put(properties);
}
properties.put(new NodeProperty("Source File", "Source File", "", tag.getContent().getName()));
String contentPath;
try {
contentPath = tag.getContent().getUniquePath();
}
catch (TskCoreException ex) {
Logger.getLogger(ContentTagNode.class.getName()).log(Level.SEVERE, "Failed to get path for content (id = " + tag.getContent().getId() + ")", ex);
contentPath = "Unavailable";
}
properties.put(new NodeProperty("Source File Path", "Source File Path", "", contentPath));
properties.put(new NodeProperty("Result Type", "Result Type", "", tag.getArtifact().getDisplayName()));
properties.put(new NodeProperty("Comment", "Comment", "", tag.getComment()));
return propertySheet;
}
@Override
public Action[] getActions(boolean context) {
List<Action> actions = DataModelActionsFactory.getActions(tag.getContent(), true);
actions.add(null); // Adds a menu item separator.
actions.add(DeleteBlackboardArtifactTagAction.getInstance());
return actions.toArray(new Action[0]);
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
}
@Override
public boolean isLeafTypeNode() {
return true;
}
}

View File

@@ -1,303 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.datamodel;
import java.awt.event.ActionEvent;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.Action;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.Lookup;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.corecomponentinterfaces.BlackboardResultViewer;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Support for bookmark (file and result/artifact) nodes and displaying
* bookmarks in the directory tree Bookmarks are divided into file and result
* children bookmarks.
*
* Bookmarks are specialized tags - TSK_TAG_NAME starts with File Bookmark or
* Result Bookmark
*
* @deprecated cosolidated under Tags
*
* TODO bookmark hierarchy support (TSK_TAG_NAME with slashes)
*/
@Deprecated
public class Bookmarks implements AutopsyVisitableItem {
public static final String NAME = "Bookmarks";
private static final String FILE_BOOKMARKS_LABEL_NAME = "File Bookmarks";
private static final String RESULT_BOOKMARKS_LABEL_NAME = "Result Bookmarks";
//bookmarks are specializations of tags
public static final String BOOKMARK_TAG_NAME = "Bookmark";
private static final String BOOKMARK_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png";
private static final Logger logger = Logger.getLogger(Bookmarks.class.getName());
private SleuthkitCase skCase;
private final Map<BlackboardArtifact.ARTIFACT_TYPE, List<BlackboardArtifact>> data =
new EnumMap<BlackboardArtifact.ARTIFACT_TYPE, List<BlackboardArtifact>>(BlackboardArtifact.ARTIFACT_TYPE.class);
public Bookmarks(SleuthkitCase skCase) {
this.skCase = skCase;
}
@Override
public <T> T accept(AutopsyItemVisitor<T> v) {
return null; //v.visit(this);
}
/**
* bookmarks root node with file/result bookmarks
*/
public class BookmarksRootNode extends DisplayableItemNode {
public BookmarksRootNode() {
super(Children.create(new BookmarksRootChildren(), true), Lookups.singleton(NAME));
super.setName(NAME);
super.setDisplayName(NAME);
this.setIconBaseWithExtension(BOOKMARK_ICON_PATH);
initData();
}
private void initData() {
data.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE, null);
data.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT, null);
try {
//filter out tags that are not bookmarks
//we get bookmarks that have tag names that start with predefined names, preserving the bookmark hierarchy
List<BlackboardArtifact> tagFiles = skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE,
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME,
BOOKMARK_TAG_NAME);
List<BlackboardArtifact> tagArtifacts = skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT,
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME,
BOOKMARK_TAG_NAME);
data.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE, tagFiles);
data.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT, tagArtifacts);
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Count not initialize bookmark nodes, ", ex);
}
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return null; // v.visit(this);
}
@Override
protected Sheet createSheet() {
Sheet s = super.createSheet();
Sheet.Set ss = s.get(Sheet.PROPERTIES);
if (ss == null) {
ss = Sheet.createPropertiesSet();
s.put(ss);
}
ss.put(new NodeProperty("Name",
"Name",
"no description",
getName()));
return s;
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
}
}
/**
* bookmarks root child node creating types of bookmarks nodes
*/
private class BookmarksRootChildren extends ChildFactory<BlackboardArtifact.ARTIFACT_TYPE> {
@Override
protected boolean createKeys(List<BlackboardArtifact.ARTIFACT_TYPE> list) {
for (BlackboardArtifact.ARTIFACT_TYPE artType : data.keySet()) {
list.add(artType);
}
return true;
}
@Override
protected Node createNodeForKey(BlackboardArtifact.ARTIFACT_TYPE key) {
return new BookmarksNodeRoot(key, data.get(key));
}
}
/**
* Bookmarks node representation (file or result)
*/
public class BookmarksNodeRoot extends DisplayableItemNode {
public BookmarksNodeRoot(BlackboardArtifact.ARTIFACT_TYPE bookType, List<BlackboardArtifact> bookmarks) {
super(Children.create(new BookmarksChildrenNode(bookmarks), true), Lookups.singleton(bookType.getDisplayName()));
String name = null;
if (bookType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)) {
name = FILE_BOOKMARKS_LABEL_NAME;
} else if (bookType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT)) {
name = RESULT_BOOKMARKS_LABEL_NAME;
}
super.setName(name);
super.setDisplayName(name + " (" + bookmarks.size() + ")");
this.setIconBaseWithExtension(BOOKMARK_ICON_PATH);
}
@Override
protected Sheet createSheet() {
Sheet s = super.createSheet();
Sheet.Set ss = s.get(Sheet.PROPERTIES);
if (ss == null) {
ss = Sheet.createPropertiesSet();
s.put(ss);
}
ss.put(new NodeProperty("Name",
"Name",
"no description",
getName()));
return s;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return null; //v.visit(this);
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
}
@Override
public boolean isLeafTypeNode() {
return true;
}
}
/**
* Node representing mail folder content (mail messages)
*/
private class BookmarksChildrenNode extends ChildFactory<BlackboardArtifact> {
private List<BlackboardArtifact> bookmarks;
private BookmarksChildrenNode(List<BlackboardArtifact> bookmarks) {
super();
this.bookmarks = bookmarks;
}
@Override
protected boolean createKeys(List<BlackboardArtifact> list) {
list.addAll(bookmarks);
return true;
}
@Override
protected Node createNodeForKey(BlackboardArtifact artifact) {
BlackboardArtifactNode bookmarkNode = null;
int artifactTypeID = artifact.getArtifactTypeID();
if (artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
final BlackboardArtifact sourceResult = Tags.getArtifactFromTag(artifact.getArtifactID());
bookmarkNode = new BlackboardArtifactNode(artifact, BOOKMARK_ICON_PATH) {
@Override
public Action[] getActions(boolean bln) {
//Action [] actions = super.getActions(bln); //To change body of generated methods, choose Tools | Templates.
Action[] actions = new Action[1];
actions[0] = new AbstractAction("View Source Result") {
@Override
public void actionPerformed(ActionEvent e) {
//open the source artifact in dir tree
if (sourceResult != null) {
BlackboardResultViewer v = Lookup.getDefault().lookup(BlackboardResultViewer.class);
v.viewArtifact(sourceResult);
}
}
};
return actions;
}
};
//add custom property
final String NO_DESCR = "no description";
String resultType = sourceResult.getDisplayName();
NodeProperty resultTypeProp = new NodeProperty("Source Result Type",
"Result Type",
NO_DESCR,
resultType);
bookmarkNode.addNodeProperty(resultTypeProp);
} else {
//file bookmark, no additional action
bookmarkNode = new BlackboardArtifactNode(artifact, BOOKMARK_ICON_PATH);
}
return bookmarkNode;
}
}
/**
* Links existing blackboard artifact (a tag) to this artifact. Linkage is
* made using TSK_TAGGED_ARTIFACT attribute.
*/
void addArtifactTag(BlackboardArtifact art, BlackboardArtifact tag) throws TskCoreException {
if (art.equals(tag)) {
throw new TskCoreException("Cannot tag the same artifact: id" + art.getArtifactID());
}
BlackboardAttribute attrLink = new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID(),
"", art.getArtifactID());
tag.addAttribute(attrLink);
}
/**
* Get tag artifacts linked to the artifact
*
* @param art artifact to get tags for
* @return list of children artifacts or an empty list
* @throws TskCoreException exception thrown if a critical error occurs
* within tsk core and child artifact could not be queried
*/
List<BlackboardArtifact> getTagArtifacts(BlackboardArtifact art) throws TskCoreException {
return skCase.getBlackboardArtifacts(ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT, art.getArtifactID());
}
}

View File

@@ -0,0 +1,92 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.datamodel;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Action;
import org.openide.nodes.Children;
import org.openide.nodes.Sheet;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.actions.DeleteContentTagAction;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Instances of this class wrap ContentTag objects. In the Autopsy
* presentation of the SleuthKit data model, they are leaf nodes of a tree
* consisting of content and blackboard artifact tags, grouped first by tag
* type, then by tag name.
*/
public class ContentTagNode extends DisplayableItemNode {
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/blue-tag-icon-16.png";
private final ContentTag tag;
public ContentTagNode(ContentTag tag) {
super(Children.LEAF, Lookups.fixed(tag, tag.getContent()));
super.setName(tag.getContent().getName());
super.setDisplayName(tag.getContent().getName());
this.setIconBaseWithExtension(ICON_PATH);
this.tag = tag;
}
@Override
protected Sheet createSheet() {
Sheet propertySheet = super.createSheet();
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
if (properties == null) {
properties = Sheet.createPropertiesSet();
propertySheet.put(properties);
}
properties.put(new NodeProperty("File", "File", "", tag.getContent().getName()));
String contentPath;
try {
contentPath = tag.getContent().getUniquePath();
}
catch (TskCoreException ex) {
Logger.getLogger(ContentTagNode.class.getName()).log(Level.SEVERE, "Failed to get path for content (id = " + tag.getContent().getId() + ")", ex);
contentPath = "Unavailable";
}
properties.put(new NodeProperty("File Path", "File Path", "", contentPath));
properties.put(new NodeProperty("Comment", "Comment", "", tag.getComment()));
return propertySheet;
}
@Override
public Action[] getActions(boolean context) {
List<Action> actions = DataModelActionsFactory.getActions(tag.getContent(), false);
actions.add(null); // Adds a menu item separator.
actions.add(DeleteContentTagAction.getInstance());
return actions.toArray(new Action[0]);
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
}
@Override
public boolean isLeafTypeNode() {
return true;
}
}

View File

@@ -0,0 +1,108 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.datamodel;
import java.util.List;
import java.util.logging.Level;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Instances of this class are are elements of a directory tree sub-tree
* consisting of content and blackboard artifact tags, grouped first by tag type,
* then by tag name.
*/
public class ContentTagTypeNode extends DisplayableItemNode {
private static final String DISPLAY_NAME = "File Tags";
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
public ContentTagTypeNode(TagName tagName) {
super(Children.create(new ContentTagNodeFactory(tagName), true), Lookups.singleton(tagName.getDisplayName() + " " + DISPLAY_NAME));
long tagsCount = 0;
try {
tagsCount = Case.getCurrentCase().getServices().getTagsManager().getContentTagsCountByTagName(tagName);
}
catch (TskCoreException ex) {
Logger.getLogger(ContentTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get content tags count for " + tagName.getDisplayName() + " tag name", ex);
}
super.setName(DISPLAY_NAME);
super.setDisplayName(DISPLAY_NAME + " (" + tagsCount + ")");
this.setIconBaseWithExtension(ICON_PATH);
}
@Override
protected Sheet createSheet() {
Sheet propertySheet = super.createSheet();
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
if (properties == null) {
properties = Sheet.createPropertiesSet();
propertySheet.put(properties);
}
properties.put(new NodeProperty("Name", "Name", "", getName()));
return propertySheet;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
}
@Override
public boolean isLeafTypeNode() {
return true;
}
private static class ContentTagNodeFactory extends ChildFactory<ContentTag> {
private final TagName tagName;
ContentTagNodeFactory(TagName tagName) {
this.tagName = tagName;
}
@Override
protected boolean createKeys(List<ContentTag> keys) {
// Use the content tags bearing the specified tag name as the keys.
try {
keys.addAll(Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tagName));
}
catch (TskCoreException ex) {
Logger.getLogger(ContentTagTypeNode.ContentTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex);
}
return true;
}
@Override
protected Node createNodeForKey(ContentTag key) {
// The content tags to be wrapped are used as the keys.
return new ContentTagNode(key);
}
}
}

View File

@@ -20,79 +20,106 @@ package org.sleuthkit.autopsy.datamodel;
import java.awt.Font;
import java.util.Arrays;
import java.util.Formatter;
/**
* Helper methods for converting data.
*/
public class DataConversion {
public static String byteArrayToHex(byte[] array, int length, long offset, Font font) {
final private static char[] hexArray = "0123456789ABCDEF".toCharArray();
/**
* Return the hex-dump layout of the passed in byte array.
* Deprecated because we don't need font
* @param array Data to display
* @param length Amount of data in array to display
* @param arrayOffset Offset of where data in array begins as part of a bigger file (used for arrayOffset column)
* @param font Font that will be used to display the text
* @return
*/
@Deprecated
public static String byteArrayToHex(byte[] array, int length, long arrayOffset, Font font) {
return byteArrayToHex(array, length, arrayOffset);
}
/**
* Return the hex-dump layout of the passed in byte array.
* @param array Data to display
* @param length Amount of data in array to display
* @param arrayOffset Offset of where data in array begins as part of a bigger file (used for arrayOffset column)
* @return
*/
public static String byteArrayToHex(byte[] array, int length, long arrayOffset) {
if (array == null) {
return "";
} else {
String base = new String(array, 0, length);
}
else {
StringBuilder outputStringBuilder = new StringBuilder();
// loop through the file in 16-byte increments
for (int curOffset = 0; curOffset < length; curOffset += 16) {
// how many bytes are we displaying on this line
int lineLen = 16;
if (length - curOffset < 16) {
lineLen = length - curOffset;
}
// print the offset column
//outputStringBuilder.append("0x");
outputStringBuilder.append(String.format("0x%08x: ", arrayOffset + curOffset));
//outputStringBuilder.append(": ");
StringBuilder buff = new StringBuilder();
int count = 0;
int extra = base.length() % 16;
String sub = "";
char subchar;
//commented out code can be used as a base for generating hex length based on
//offset/length/file size
//String hex = Long.toHexString(length + offset);
//double hexMax = Math.pow(16, hex.length());
double hexMax = Math.pow(16, 6);
while (count < base.length() - extra) {
buff.append("0x");
buff.append(Long.toHexString((long) (offset + count + hexMax)).substring(1));
buff.append(": ");
// print the hex columns
for (int i = 0; i < 16; i++) {
buff.append(Integer.toHexString((((int) base.charAt(count + i)) & 0xff) + 256).substring(1).toUpperCase());
buff.append(" ");
if (i == 7) {
buff.append(" ");
if (i < lineLen) {
int v = array[curOffset + i] & 0xFF;
outputStringBuilder.append(hexArray[v >>> 4]);
outputStringBuilder.append(hexArray[v & 0x0F]);
}
else {
outputStringBuilder.append(" ");
}
// someday we'll offer the option of these two styles...
if (true) {
outputStringBuilder.append(" ");
if (i % 4 == 3) {
outputStringBuilder.append(" ");
}
if (i == 7) {
outputStringBuilder.append(" ");
}
}
// xxd style
else {
if (i % 2 == 1) {
outputStringBuilder.append(" ");
}
}
}
sub = base.substring(count, count + 16);
outputStringBuilder.append(" ");
// print the ascii columns
String ascii = new String(array, curOffset, lineLen);
for (int i = 0; i < 16; i++) {
subchar = sub.charAt(i);
if (!font.canDisplay(subchar)) {
sub.replace(subchar, '.');
}
// replace all unprintable characters with "."
int dec = (int) subchar;
if (dec < 32 || dec > 126) {
sub = sub.replace(subchar, '.');
char c = ' ';
if (i < lineLen) {
c = ascii.charAt(i);
int dec = (int) c;
if (dec < 32 || dec > 126) {
c = '.';
}
}
outputStringBuilder.append(c);
}
buff.append(" " + sub + "\n");
count += 16;
outputStringBuilder.append("\n");
}
if (base.length() % 16 != 0) {
buff.append("0x" + Long.toHexString((long) (offset + count + hexMax)).substring(1) + ": ");
}
for (int i = 0; i < 16; i++) {
if (i < extra) {
buff.append(Integer.toHexString((((int) base.charAt(count + i)) & 0xff) + 256).substring(1) + " ");
} else {
buff.append(" ");
}
if (i == 7) {
buff.append(" ");
}
}
sub = base.substring(count, count + extra);
for (int i = 0; i < extra; i++) {
subchar = sub.charAt(i);
if (!font.canDisplay(subchar)) {
sub.replace(subchar, '.');
}
}
buff.append(" " + sub);
return buff.toString();
return outputStringBuilder.toString();
}
}

View File

@@ -0,0 +1,182 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.datamodel;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Action;
import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.Directory;
import org.sleuthkit.datamodel.File;
import org.sleuthkit.datamodel.LayoutFile;
import org.sleuthkit.datamodel.LocalFile;
import org.sleuthkit.datamodel.VirtualDirectory;
/**
* This class provides methods for creating sets of actions for data model objects.
*/
// TODO: All of the methods below that deal with classes derived from AbstractFile are the same except for the creation of wrapper nodes to pass to actions.
// 1. Do the types of the wrapper nodes really need to vary? If not, it would mean a single
// static List<Action> getActions(AbstrctFile file, boolean isArtifactSource)
// method could be implemented. If the different nodes are necessary, is it merely because of some misuse of the Visitor pattern somewhere?
// 2. All of this would be much improved by not constructing nodes with actions, but this might be necessary with pushing of nodes rather than use of lookups to
// handle selections.
class DataModelActionsFactory {
static List<Action> getActions(File file, boolean isArtifactSource) {
List<Action> actions = new ArrayList<>();
actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), file));
final FileNode fileNode = new FileNode(file);
actions.add(null); // creates a menu separator
actions.add(new NewWindowViewAction("View in New Window", fileNode));
actions.add(new ExternalViewerAction("Open in External Viewer", fileNode));
actions.add(null); // creates a menu separator
actions.add(ExtractAction.getInstance());
actions.add(new HashSearchAction("Search for files with the same MD5 hash", fileNode));
actions.add(null); // creates a menu separator
actions.add(AddContentTagAction.getInstance());
if (isArtifactSource) {
actions.add(AddBlackboardArtifactTagAction.getInstance());
}
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions;
}
static List<Action> getActions(LayoutFile file, boolean isArtifactSource) {
List<Action> actions = new ArrayList<>();
actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), file));
LayoutFileNode layoutFileNode = new LayoutFileNode(file);
actions.add(null); // creates a menu separator
actions.add(new NewWindowViewAction("View in New Window", layoutFileNode));
actions.add(new ExternalViewerAction("Open in External Viewer", layoutFileNode));
actions.add(null); // creates a menu separator
actions.add(ExtractAction.getInstance());//
actions.add(null); // creates a menu separator
actions.add(AddContentTagAction.getInstance());
if (isArtifactSource) {
actions.add(AddBlackboardArtifactTagAction.getInstance());
}
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions;
}
static List<Action> getActions(Directory directory, boolean isArtifactSource) {
List<Action> actions = new ArrayList<>();
actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), directory));
DirectoryNode directoryNode = new DirectoryNode(directory);
actions.add(null); // creates a menu separator
actions.add(new NewWindowViewAction("View in New Window", directoryNode));
actions.add(new ExternalViewerAction("Open in External Viewer", directoryNode));
actions.add(null); // creates a menu separator
actions.add(ExtractAction.getInstance());
actions.add(null); // creates a menu separator
actions.add(AddContentTagAction.getInstance());
if (isArtifactSource) {
actions.add(AddBlackboardArtifactTagAction.getInstance());
}
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions;
}
static List<Action> getActions(VirtualDirectory directory, boolean isArtifactSource) {
List<Action> actions = new ArrayList<>();
actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), directory));
VirtualDirectoryNode directoryNode = new VirtualDirectoryNode(directory);
actions.add(null); // creates a menu separator
actions.add(new NewWindowViewAction("View in New Window", directoryNode));
actions.add(new ExternalViewerAction("Open in External Viewer", directoryNode));
actions.add(null); // creates a menu separator
actions.add(ExtractAction.getInstance());
actions.add(null); // creates a menu separator
actions.add(AddContentTagAction.getInstance());
if (isArtifactSource) {
actions.add(AddBlackboardArtifactTagAction.getInstance());
}
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions;
}
static List<Action> getActions(LocalFile file, boolean isArtifactSource) {
List<Action> actions = new ArrayList<>();
actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), file));
final LocalFileNode localFileNode = new LocalFileNode(file);
actions.add(null); // creates a menu separator
actions.add(new NewWindowViewAction("View in New Window", localFileNode));
actions.add(new ExternalViewerAction("Open in External Viewer", localFileNode));
actions.add(null); // creates a menu separator
actions.add(ExtractAction.getInstance());
actions.add(null); // creates a menu separator
actions.add(AddContentTagAction.getInstance());
if (isArtifactSource) {
actions.add(AddBlackboardArtifactTagAction.getInstance());
}
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions;
}
static List<Action> getActions(DerivedFile file, boolean isArtifactSource) {
List<Action> actions = new ArrayList<>();
actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), file));
final LocalFileNode localFileNode = new LocalFileNode(file);
actions.add(null); // creates a menu separator
actions.add(new NewWindowViewAction("View in New Window", localFileNode));
actions.add(new ExternalViewerAction("Open in External Viewer", localFileNode));
actions.add(null); // creates a menu separator
actions.add(ExtractAction.getInstance());
actions.add(null); // creates a menu separator
actions.add(AddContentTagAction.getInstance());
if (isArtifactSource) {
actions.add(AddBlackboardArtifactTagAction.getInstance());
}
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions;
}
static List<Action> getActions(Content content, boolean isArtifactSource) {
if (content instanceof File) {
return getActions((File)content, isArtifactSource);
}
else if (content instanceof LayoutFile) {
return getActions((LayoutFile)content, isArtifactSource);
}
else if (content instanceof Directory) {
return getActions((Directory)content, isArtifactSource);
}
else if (content instanceof VirtualDirectory) {
return getActions((VirtualDirectory)content, isArtifactSource);
}
else if (content instanceof LocalFile) {
return getActions((LocalFile)content, isArtifactSource);
}
else if (content instanceof DerivedFile) {
return getActions((DerivedFile)content, isArtifactSource);
}
else {
return new ArrayList<>();
}
}
}

View File

@@ -39,10 +39,10 @@ public class DataSourcesNode extends DisplayableItemNode {
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.CONTENT;
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);

View File

@@ -109,10 +109,10 @@ public class DeletedContent implements AutopsyVisitableItem {
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.META;
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
@@ -199,11 +199,6 @@ public class DeletedContent implements AutopsyVisitableItem {
return s;
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.META;
}
@Override
public boolean isLeafTypeNode() {
return true;

View File

@@ -1,97 +1,99 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.datamodel;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Action;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Directory;
import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
/**
* This class is used to represent the "Node" for the directory. Its children
* are more directories.
*/
public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
public static final String DOTDOTDIR = "[parent folder]";
public static final String DOTDIR = "[current folder]";
public DirectoryNode(Directory dir) {
this(dir, true);
setIcon(dir);
}
public DirectoryNode(AbstractFile dir, boolean directoryBrowseMode) {
super(dir, directoryBrowseMode);
setIcon(dir);
}
private void setIcon(AbstractFile dir) {
// set name, display name, and icon
if (dir.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-deleted.png");
} else {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/Folder-icon.png");
}
}
/**
* Right click action for this node
*
* @param popup
* @return
*/
@Override
public Action[] getActions(boolean popup) {
List<Action> actions = new ArrayList<>();
if (!getDirectoryBrowseMode()) {
actions.add(new ViewContextAction("View File in Directory", this));
actions.add(null); // creates a menu separator
}
actions.add(new NewWindowViewAction("View in New Window", this));
actions.add(null); // creates a menu separator
actions.add(ExtractAction.getInstance());
actions.add(null); // creates a menu separator
actions.add(TagAbstractFileAction.getInstance());
return actions.toArray(new Action[0]);
}
@Override
public <T> T accept(ContentNodeVisitor<T> v) {
return v.visit(this);
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.CONTENT;
}
}
/*
* Autopsy Forensic Browser
*
* Copyright 2011 - 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.datamodel;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Action;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Directory;
import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
/**
* This class is used to represent the "Node" for the directory. Its children
* are more directories.
*/
public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
public static final String DOTDOTDIR = "[parent folder]";
public static final String DOTDIR = "[current folder]";
public DirectoryNode(Directory dir) {
this(dir, true);
setIcon(dir);
}
public DirectoryNode(AbstractFile dir, boolean directoryBrowseMode) {
super(dir, directoryBrowseMode);
setIcon(dir);
}
private void setIcon(AbstractFile dir) {
// set name, display name, and icon
if (dir.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-deleted.png");
} else {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/Folder-icon.png");
}
}
/**
* Right click action for this node
*
* @param popup
* @return
*/
@Override
public Action[] getActions(boolean popup) {
List<Action> actions = new ArrayList<>();
if (!getDirectoryBrowseMode()) {
actions.add(new ViewContextAction("View File in Directory", this));
actions.add(null); // creates a menu separator
}
actions.add(new NewWindowViewAction("View in New Window", this));
actions.add(null); // creates a menu separator
actions.add(ExtractAction.getInstance());
actions.add(null); // creates a menu separator
actions.add(AddContentTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions.toArray(new Action[0]);
}
@Override
public <T> T accept(ContentNodeVisitor<T> v) {
return v.visit(this);
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
}
@Override
public boolean isLeafTypeNode() {
return false;
}
}

View File

@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011 - 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,12 +18,9 @@
*/
package org.sleuthkit.autopsy.datamodel;
import java.awt.datatransfer.Transferable;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.util.Lookup;
import org.openide.util.datatransfer.PasteType;
/**
* Interface for all displayable Nodes
@@ -37,35 +34,7 @@ public abstract class DisplayableItemNode extends AbstractNode {
public DisplayableItemNode(Children children, Lookup lookup) {
super(children, lookup);
}
/**
* Possible sub-implementations
*/
public enum TYPE {
CONTENT, ///< content node, such as file, image
ARTIFACT, ///< artifact data node
META, ///< top-level category node, such as view, filters, etc.
};
/**
* Get possible subtype of the displayable item node
* @return
*/
public abstract TYPE getDisplayableItemNodeType();
public boolean isLeafTypeNode() {
return false;
}
/**
* Visitor pattern support.
*
* @param v visitor
* @return visitor's visit return value
*/
public abstract <T> T accept(DisplayableItemNodeVisitor<T> v);
abstract public boolean isLeafTypeNode();
public abstract <T> T accept(DisplayableItemNodeVisitor<T> v);
}

View File

@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011 - 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,12 +30,10 @@ import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsSetNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsKeywordNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsListNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode;
import org.sleuthkit.autopsy.datamodel.Tags.TagNodeRoot;
import org.sleuthkit.autopsy.datamodel.Tags.TagsNodeRoot;
import org.sleuthkit.autopsy.datamodel.Tags.TagsRootNode;
import org.sleuthkit.autopsy.directorytree.BlackboardArtifactTagTypeNode;
/**
* Visitor pattern for DisplayableItemNodes
* Visitor pattern implementation for DisplayableItemNodes
*/
public interface DisplayableItemNodeVisitor<T> {
@@ -85,11 +83,17 @@ public interface DisplayableItemNodeVisitor<T> {
T visit(EmailExtractedFolderNode eefn);
T visit(TagsRootNode bksrn);
T visit(TagsNode node);
T visit(TagsNodeRoot bksrn);
T visit(TagNameNode node);
T visit(TagNodeRoot tnr);
T visit(ContentTagTypeNode node);
T visit(ContentTagNode node);
T visit(BlackboardArtifactTagTypeNode node);
T visit(BlackboardArtifactTagNode node);
T visit(ViewsNode vn);
@@ -265,18 +269,33 @@ public interface DisplayableItemNodeVisitor<T> {
}
@Override
public T visit(TagsRootNode bksrn) {
return defaultVisit(bksrn);
public T visit(TagsNode node) {
return defaultVisit(node);
}
@Override
public T visit(TagsNodeRoot bksnr) {
return defaultVisit(bksnr);
public T visit(TagNameNode node) {
return defaultVisit(node);
}
@Override
public T visit(TagNodeRoot tnr) {
return defaultVisit(tnr);
public T visit(ContentTagTypeNode node) {
return defaultVisit(node);
}
@Override
public T visit(ContentTagNode node) {
return defaultVisit(node);
}
@Override
public T visit(BlackboardArtifactTagTypeNode node) {
return defaultVisit(node);
}
@Override
public T visit(BlackboardArtifactTagNode node) {
return defaultVisit(node);
}
}
}

View File

@@ -133,10 +133,10 @@ public class EmailExtracted implements AutopsyVisitableItem {
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
//return v.visit(this);
@@ -215,10 +215,10 @@ public class EmailExtracted implements AutopsyVisitableItem {
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
@@ -272,11 +272,6 @@ public class EmailExtracted implements AutopsyVisitableItem {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/account-icon-16.png");
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
}
@Override
protected Sheet createSheet() {
Sheet s = super.createSheet();
@@ -294,6 +289,11 @@ public class EmailExtracted implements AutopsyVisitableItem {
return s;
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
@@ -337,11 +337,6 @@ public class EmailExtracted implements AutopsyVisitableItem {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-16.png");
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
}
@Override
public boolean isLeafTypeNode() {
return true;

View File

@@ -38,6 +38,11 @@ public class ExtractedContentNode extends DisplayableItemNode {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/extracted_content.png");
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
@@ -58,9 +63,4 @@ public class ExtractedContentNode extends DisplayableItemNode {
NAME));
return s;
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
}
}

View File

@@ -1,180 +1,177 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.datamodel;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Action;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
/**
* This class is used to represent the "Node" for the file. It may have derived
* files children.
*/
public class FileNode extends AbstractFsContentNode<AbstractFile> {
/**
* @param file underlying Content
*/
public FileNode(AbstractFile file) {
this(file, true);
setIcon(file);
}
public FileNode(AbstractFile file, boolean directoryBrowseMode) {
super(file, directoryBrowseMode);
setIcon(file);
}
private void setIcon(AbstractFile file) {
// set name, display name, and icon
if (file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
if (file.getType().equals(TSK_DB_FILES_TYPE_ENUM.CARVED)) {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/carved-file-icon-16.png");
} else {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png");
}
} else {
this.setIconBaseWithExtension(getIconForFileType(file));
}
}
/**
* Right click action for this node
*
* @param popup
* @return
*/
@Override
public Action[] getActions(boolean popup) {
List<Action> actionsList = new ArrayList<>();
if (!this.getDirectoryBrowseMode()) {
actionsList.add(new ViewContextAction("View File in Directory", this));
actionsList.add(null); // creates a menu separator
}
actionsList.add(new NewWindowViewAction("View in New Window", this));
actionsList.add(new ExternalViewerAction("Open in External Viewer", this));
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this));
actionsList.add(null); // creates a menu separator
actionsList.add(TagAbstractFileAction.getInstance());
return actionsList.toArray(new Action[0]);
}
@Override
public <T> T accept(ContentNodeVisitor< T> v) {
return v.visit(this);
}
@Override
public <T> T accept(DisplayableItemNodeVisitor< T> v) {
return v.visit(this);
}
// Given a file, returns the correct icon for said
// file based off it's extension
static String getIconForFileType(AbstractFile file) {
// Get the name, extension
String name = file.getName();
int dotIndex = name.lastIndexOf(".");
if (dotIndex == -1) {
return "org/sleuthkit/autopsy/images/file-icon.png";
}
String ext = name.substring(dotIndex).toLowerCase();
// Images
for (String s : FileTypeExtensions.getImageExtensions()) {
if (ext.equals(s)) {
return "org/sleuthkit/autopsy/images/image-file.png";
}
}
// Videos
for (String s : FileTypeExtensions.getVideoExtensions()) {
if (ext.equals(s)) {
return "org/sleuthkit/autopsy/images/video-file.png";
}
}
// Audio Files
for (String s : FileTypeExtensions.getAudioExtensions()) {
if (ext.equals(s)) {
return "org/sleuthkit/autopsy/images/audio-file.png";
}
}
// Documents
for (String s : FileTypeExtensions.getDocumentExtensions()) {
if (ext.equals(s)) {
return "org/sleuthkit/autopsy/images/doc-file.png";
}
}
// Executables / System Files
for (String s : FileTypeExtensions.getExecutableExtensions()) {
if (ext.equals(s)) {
return "org/sleuthkit/autopsy/images/exe-file.png";
}
}
// Text Files
for (String s : FileTypeExtensions.getTextExtensions()) {
if (ext.equals(s)) {
return "org/sleuthkit/autopsy/images/text-file.png";
}
}
// Web Files
for (String s : FileTypeExtensions.getWebExtensions()) {
if (ext.equals(s)) {
return "org/sleuthkit/autopsy/images/web-file.png";
}
}
// PDFs
for (String s : FileTypeExtensions.getPDFExtensions()) {
if (ext.equals(s)) {
return "org/sleuthkit/autopsy/images/pdf-file.png";
}
}
// Archives
for (String s : FileTypeExtensions.getArchiveExtensions()) {
if (ext.equals(s)) {
return "org/sleuthkit/autopsy/images/archive-file.png";
}
}
// Else return the default
return "org/sleuthkit/autopsy/images/file-icon.png";
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.CONTENT;
}
@Override
public boolean isLeafTypeNode() {
return true; //false;
}
}
/*
* Autopsy Forensic Browser
*
* Copyright 2011 - 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.datamodel;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Action;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
/**
* This class is used to represent the "Node" for the file. It may have derived
* files children.
*/
public class FileNode extends AbstractFsContentNode<AbstractFile> {
/**
* @param file underlying Content
*/
public FileNode(AbstractFile file) {
this(file, true);
setIcon(file);
}
public FileNode(AbstractFile file, boolean directoryBrowseMode) {
super(file, directoryBrowseMode);
setIcon(file);
}
private void setIcon(AbstractFile file) {
// set name, display name, and icon
if (file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
if (file.getType().equals(TSK_DB_FILES_TYPE_ENUM.CARVED)) {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/carved-file-icon-16.png");
} else {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png");
}
} else {
this.setIconBaseWithExtension(getIconForFileType(file));
}
}
/**
* Right click action for this node
*
* @param popup
* @return
*/
@Override
public Action[] getActions(boolean popup) {
List<Action> actionsList = new ArrayList<>();
if (!this.getDirectoryBrowseMode()) {
actionsList.add(new ViewContextAction("View File in Directory", this));
actionsList.add(null); // creates a menu separator
}
actionsList.add(new NewWindowViewAction("View in New Window", this));
actionsList.add(new ExternalViewerAction("Open in External Viewer", this));
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this));
actionsList.add(null); // creates a menu separator
actionsList.add(AddContentTagAction.getInstance());
actionsList.addAll(ContextMenuExtensionPoint.getActions());
return actionsList.toArray(new Action[0]);
}
@Override
public <T> T accept(ContentNodeVisitor< T> v) {
return v.visit(this);
}
@Override
public <T> T accept(DisplayableItemNodeVisitor< T> v) {
return v.visit(this);
}
// Given a file, returns the correct icon for said
// file based off it's extension
static String getIconForFileType(AbstractFile file) {
// Get the name, extension
String name = file.getName();
int dotIndex = name.lastIndexOf(".");
if (dotIndex == -1) {
return "org/sleuthkit/autopsy/images/file-icon.png";
}
String ext = name.substring(dotIndex).toLowerCase();
// Images
for (String s : FileTypeExtensions.getImageExtensions()) {
if (ext.equals(s)) {
return "org/sleuthkit/autopsy/images/image-file.png";
}
}
// Videos
for (String s : FileTypeExtensions.getVideoExtensions()) {
if (ext.equals(s)) {
return "org/sleuthkit/autopsy/images/video-file.png";
}
}
// Audio Files
for (String s : FileTypeExtensions.getAudioExtensions()) {
if (ext.equals(s)) {
return "org/sleuthkit/autopsy/images/audio-file.png";
}
}
// Documents
for (String s : FileTypeExtensions.getDocumentExtensions()) {
if (ext.equals(s)) {
return "org/sleuthkit/autopsy/images/doc-file.png";
}
}
// Executables / System Files
for (String s : FileTypeExtensions.getExecutableExtensions()) {
if (ext.equals(s)) {
return "org/sleuthkit/autopsy/images/exe-file.png";
}
}
// Text Files
for (String s : FileTypeExtensions.getTextExtensions()) {
if (ext.equals(s)) {
return "org/sleuthkit/autopsy/images/text-file.png";
}
}
// Web Files
for (String s : FileTypeExtensions.getWebExtensions()) {
if (ext.equals(s)) {
return "org/sleuthkit/autopsy/images/web-file.png";
}
}
// PDFs
for (String s : FileTypeExtensions.getPDFExtensions()) {
if (ext.equals(s)) {
return "org/sleuthkit/autopsy/images/pdf-file.png";
}
}
// Archives
for (String s : FileTypeExtensions.getArchiveExtensions()) {
if (ext.equals(s)) {
return "org/sleuthkit/autopsy/images/archive-file.png";
}
}
// Else return the default
return "org/sleuthkit/autopsy/images/file-icon.png";
}
@Override
public boolean isLeafTypeNode() {
return true;
}
}

View File

@@ -111,10 +111,10 @@ public class FileSize implements AutopsyVisitableItem {
}
@Override
public DisplayableItemNode.TYPE getDisplayableItemNodeType() {
return DisplayableItemNode.TYPE.META;
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
@@ -201,11 +201,6 @@ public class FileSize implements AutopsyVisitableItem {
return s;
}
@Override
public DisplayableItemNode.TYPE getDisplayableItemNodeType() {
return DisplayableItemNode.TYPE.META;
}
@Override
public boolean isLeafTypeNode() {
return true;

View File

@@ -78,11 +78,6 @@ public class FileTypeNode extends DisplayableItemNode {
return s;
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.META;
}
@Override
public boolean isLeafTypeNode() {
return true;

View File

@@ -52,6 +52,11 @@ public class FileTypesNode extends DisplayableItemNode {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png");
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
@@ -72,9 +77,4 @@ public class FileTypesNode extends DisplayableItemNode {
getName()));
return s;
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.META;
}
}

View File

@@ -94,6 +94,43 @@ public class HashsetHits implements AutopsyVisitableItem {
}
}
static public String getList(SleuthkitCase skCase, long objId) {
ResultSet rs = null;
String strList = "";
try {
int setNameId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
int artId = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID();
String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id "
+ "FROM blackboard_attributes,blackboard_artifacts WHERE "
+ "attribute_type_id=" + setNameId
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id"
+ " AND blackboard_artifacts.artifact_type_id=" + artId
+ " AND blackboard_artifacts.obj_id=" + objId;
rs = skCase.runQuery(query);
int i = 0;
while (rs.next()) {
if (i++ > 0) {
strList += ", ";
}
strList += rs.getString("value_text");
}
} catch (SQLException ex) {
logger.log(Level.WARNING, "SQL Exception occurred: ", ex);
}
finally {
if (rs != null) {
try {
skCase.closeRunQuery(rs);
} catch (SQLException ex) {
logger.log(Level.WARNING, "Error closing result set after getting hashset hits", ex);
}
}
}
return strList;
}
@Override
public <T> T accept(AutopsyItemVisitor<T> v) {
return v.visit(this);
@@ -113,10 +150,10 @@ public class HashsetHits implements AutopsyVisitableItem {
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
@@ -163,11 +200,6 @@ public class HashsetHits implements AutopsyVisitableItem {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png");
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
}
@Override
public boolean isLeafTypeNode() {
return true;

View File

@@ -56,11 +56,6 @@ public class ImageNode extends AbstractContentNode<Image> {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hard-drive-icon.jpg");
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.CONTENT;
}
/**
* Right click action for this node
*
@@ -98,6 +93,11 @@ public class ImageNode extends AbstractContentNode<Image> {
return v.visit(this);
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);

View File

@@ -171,16 +171,16 @@ public class KeywordHits implements AutopsyVisitableItem {
//logger.info("Process took " + (finish-start) + " ms" );
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
}
@Override
protected Sheet createSheet() {
Sheet s = super.createSheet();
@@ -231,11 +231,6 @@ public class KeywordHits implements AutopsyVisitableItem {
this.children = children;
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
}
@Override
protected Sheet createSheet() {
Sheet s = super.createSheet();
@@ -259,6 +254,11 @@ public class KeywordHits implements AutopsyVisitableItem {
return s;
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
@@ -312,11 +312,6 @@ public class KeywordHits implements AutopsyVisitableItem {
return v.visit(this);
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
}
@Override
protected Sheet createSheet() {
Sheet s = super.createSheet();

View File

@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011 - 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,10 +24,11 @@ import java.util.List;
import java.util.Map;
import javax.swing.Action;
import org.openide.nodes.Sheet;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.datamodel.LayoutFile;
import org.sleuthkit.datamodel.TskData;
@@ -62,11 +63,6 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
}
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.CONTENT;
}
@Override
protected Sheet createSheet() {
Sheet s = super.createSheet();
@@ -95,6 +91,11 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
return v.visit(this);
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
@@ -102,13 +103,14 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
@Override
public Action[] getActions(boolean context) {
List<Action> actionsList = new ArrayList<Action>();
List<Action> actionsList = new ArrayList<>();
actionsList.add(new NewWindowViewAction("View in New Window", this));
actionsList.add(new ExternalViewerAction("Open in External Viewer", this));
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator
actionsList.add(TagAbstractFileAction.getInstance());
actionsList.add(AddContentTagAction.getInstance());
actionsList.addAll(ContextMenuExtensionPoint.getActions());
return actionsList.toArray(new Action[0]);
}

View File

@@ -25,12 +25,12 @@ import java.util.List;
import java.util.Map;
import javax.swing.Action;
import org.openide.nodes.Sheet;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode.TYPE;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.datamodel.AbstractFile;
/**
@@ -55,11 +55,6 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.CONTENT;
}
@Override
protected Sheet createSheet() {
Sheet s = super.createSheet();
@@ -92,7 +87,8 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
actionsList.add(ExtractAction.getInstance());
actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this));
actionsList.add(null); // creates a menu separator
actionsList.add(TagAbstractFileAction.getInstance());
actionsList.add(AddContentTagAction.getInstance());
actionsList.addAll(ContextMenuExtensionPoint.getActions());
return actionsList.toArray(new Action[0]);
}

View File

@@ -79,11 +79,6 @@ public class RecentFilesFilterNode extends DisplayableItemNode {
return s;
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.META;
}
@Override
public boolean isLeafTypeNode() {
return true;

View File

@@ -42,10 +42,10 @@ public class RecentFilesNode extends DisplayableItemNode {
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.META;
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);

View File

@@ -19,7 +19,6 @@
package org.sleuthkit.autopsy.datamodel;
import java.util.Arrays;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Sheet;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.datamodel.SleuthkitCase;
@@ -36,13 +35,18 @@ public class ResultsNode extends DisplayableItemNode {
new KeywordHits(sleuthkitCase),
new HashsetHits(sleuthkitCase),
new EmailExtracted(sleuthkitCase),
new Tags(sleuthkitCase) //TODO move to the top of the tree
new TagsNodeKey()
)), Lookups.singleton(NAME));
setName(NAME);
setDisplayName(NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/results.png");
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
@@ -63,9 +67,4 @@ public class ResultsNode extends DisplayableItemNode {
NAME));
return s;
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.META;
}
}

View File

@@ -79,19 +79,12 @@ public class RootContentChildren extends AbstractContentChildren<Object> {
case TSK_EMAIL_MSG:
if (o instanceof EmailExtracted)
this.refreshKey(o);
break;
//TODO check
break;
case TSK_TAG_FILE:
if (o instanceof Tags)
case TSK_TAG_ARTIFACT:
if (o instanceof TagsNodeKey)
this.refreshKey(o);
break;
//TODO check
case TSK_TAG_ARTIFACT:
if (o instanceof Tags)
this.refreshKey(o);
break;
break;
default:
if (o instanceof ExtractedContent)
this.refreshKey(o);
@@ -105,7 +98,7 @@ public class RootContentChildren extends AbstractContentChildren<Object> {
this.refreshKey(o);
else if (o instanceof EmailExtracted)
this.refreshKey(o);
else if (o instanceof Tags)
else if (o instanceof TagsNodeKey)
this.refreshKey(o);
else if (o instanceof ExtractedContent)
this.refreshKey(o);

View File

@@ -0,0 +1,123 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.datamodel;
import java.util.List;
import java.util.logging.Level;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.directorytree.BlackboardArtifactTagTypeNode;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Instances of this class are elements of Node hierarchies consisting of
* content and blackboard artifact tags, grouped first by tag type, then by
* tag name.
*/
public class TagNameNode extends DisplayableItemNode {
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
private static final String BOOKMARK_TAG_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png";
private final TagName tagName;
public TagNameNode(TagName tagName) {
super(Children.create(new TagTypeNodeFactory(tagName), true), Lookups.singleton(tagName.getDisplayName() + " Tags"));
this.tagName = tagName;
long tagsCount = 0;
try {
tagsCount = Case.getCurrentCase().getServices().getTagsManager().getContentTagsCountByTagName(tagName);
tagsCount += Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName);
}
catch (TskCoreException ex) {
Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "Failed to get tags count for " + tagName.getDisplayName() + " tag name", ex);
}
super.setName(tagName.getDisplayName());
super.setDisplayName(tagName.getDisplayName() + " (" + tagsCount + ")");
if (tagName.getDisplayName().equals("Bookmark")) {
setIconBaseWithExtension(BOOKMARK_TAG_ICON_PATH);
}
else {
setIconBaseWithExtension(ICON_PATH);
}
}
@Override
protected Sheet createSheet() {
Sheet propertySheet = super.createSheet();
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
if (properties == null) {
properties = Sheet.createPropertiesSet();
propertySheet.put(properties);
}
properties.put(new NodeProperty("Name", "Name", tagName.getDescription(), getName()));
return propertySheet;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
// See classes derived from DisplayableItemNodeVisitor<AbstractNode>
// for behavior added using the Visitor pattern.
return v.visit(this);
}
@Override
public boolean isLeafTypeNode() {
return false;
}
private static class TagTypeNodeFactory extends ChildFactory<String> {
private static final String CONTENT_TAG_TYPE_NODE_KEY = "Content Tags";
private static final String BLACKBOARD_ARTIFACT_TAG_TYPE_NODE_KEY = "Result Tags";
private final TagName tagName;
TagTypeNodeFactory(TagName tagName) {
this.tagName = tagName;
}
@Override
protected boolean createKeys(List<String> keys) {
keys.add(CONTENT_TAG_TYPE_NODE_KEY);
keys.add(BLACKBOARD_ARTIFACT_TAG_TYPE_NODE_KEY);
return true;
}
@Override
protected Node createNodeForKey(String key) {
switch (key) {
case CONTENT_TAG_TYPE_NODE_KEY:
return new ContentTagTypeNode(tagName);
case BLACKBOARD_ARTIFACT_TAG_TYPE_NODE_KEY:
return new BlackboardArtifactTagTypeNode(tagName);
default:
Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "{0} not a recognized key", key);
return null;
}
}
}
}

View File

@@ -1,711 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.datamodel;
import java.awt.event.ActionEvent;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.Action;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.Lookup;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.corecomponentinterfaces.BlackboardResultViewer;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
*
* Support for tags in the directory tree. Tag nodes representing file and
* result tags, encapsulate TSK_TAG_FILE and TSK_TAG_ARTIFACT typed artifacts.
*
* The class implements querying of data model and populating node hierarchy
* using child factories.
*
*/
public class Tags implements AutopsyVisitableItem {
private static final Logger logger = Logger.getLogger(Tags.class.getName());
private static final String FILE_TAG_LABEL_NAME = "File Tags";
private static final String RESULT_TAG_LABEL_NAME = "Result Tags";
private SleuthkitCase skCase;
public static final String NAME = "Tags";
private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
//bookmarks are specializations of tags
public static final String BOOKMARK_TAG_NAME = "Bookmark";
private static final String BOOKMARK_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png";
private Map<BlackboardArtifact.ARTIFACT_TYPE, Map<String, List<BlackboardArtifact>>> tags;
private static final String EMPTY_COMMENT = "";
private static final String APP_SETTINGS_FILE_NAME = "app"; // @@@ TODO: Need a general app settings or user preferences file, this will do for now.
private static final String TAG_NAMES_SETTING_KEY = "tag_names";
private static final HashSet<String> appSettingTagNames = new HashSet<>();
private static final StringBuilder tagNamesAppSetting = new StringBuilder();
// When this class is loaded, either create an new app settings file or
// get the tag names setting from the existing app settings file.
static {
String setting = ModuleSettings.getConfigSetting(APP_SETTINGS_FILE_NAME, TAG_NAMES_SETTING_KEY);
if (null != setting && !setting.isEmpty()) {
// Make a speedy lookup for the tag names in the setting to aid in the
// detection of new tag names.
List<String> tagNamesFromAppSettings = Arrays.asList(setting.split(","));
for (String tagName : tagNamesFromAppSettings) {
appSettingTagNames.add(tagName);
}
// Load the raw comma separated values list from the setting into a
// string builder to facilitate adding new tag names to the list and writing
// it back to the app settings file.
tagNamesAppSetting.append(setting);
}
}
Tags(SleuthkitCase skCase) {
this.skCase = skCase;
}
@Override
public <T> T accept(AutopsyItemVisitor<T> v) {
return v.visit(this);
}
/**
* Root of all Tag nodes. This node is shown directly under Results in the
* directory tree.
*/
public class TagsRootNode extends DisplayableItemNode {
public TagsRootNode() {
super(Children.create(new Tags.TagsRootChildren(), true), Lookups.singleton(NAME));
super.setName(NAME);
super.setDisplayName(NAME);
this.setIconBaseWithExtension(TAG_ICON_PATH);
initData();
}
private void initData() {
try {
// Get all file and artifact tags
//init data
tags = new EnumMap<>(BlackboardArtifact.ARTIFACT_TYPE.class);
tags.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE, new HashMap<String, List<BlackboardArtifact>>());
tags.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT, new HashMap<String, List<BlackboardArtifact>>());
//populate
for (BlackboardArtifact.ARTIFACT_TYPE artType : tags.keySet()) {
final Map<String, List<BlackboardArtifact>> artTags = tags.get(artType);
for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(artType)) {
for (BlackboardAttribute attribute : artifact.getAttributes()) {
if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()) {
String tagName = attribute.getValueString();
if (artTags.containsKey(tagName)) {
List<BlackboardArtifact> artifacts = artTags.get(tagName);
artifacts.add(artifact);
} else {
List<BlackboardArtifact> artifacts = new ArrayList<>();
artifacts.add(artifact);
artTags.put(tagName, artifacts);
}
break;
}
}
}
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Count not initialize tag nodes", ex);
}
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
}
@Override
protected Sheet createSheet() {
Sheet s = super.createSheet();
Sheet.Set ss = s.get(Sheet.PROPERTIES);
if (ss == null) {
ss = Sheet.createPropertiesSet();
s.put(ss);
}
ss.put(new NodeProperty("Name",
"Name",
"no description",
getName()));
return s;
}
@Override
public DisplayableItemNode.TYPE getDisplayableItemNodeType() {
return DisplayableItemNode.TYPE.ARTIFACT;
}
}
/**
* bookmarks root child node creating types of bookmarks nodes
*/
private class TagsRootChildren extends ChildFactory<BlackboardArtifact.ARTIFACT_TYPE> {
@Override
protected boolean createKeys(List<BlackboardArtifact.ARTIFACT_TYPE> list) {
for (BlackboardArtifact.ARTIFACT_TYPE artType : tags.keySet()) {
list.add(artType);
}
return true;
}
@Override
protected Node createNodeForKey(BlackboardArtifact.ARTIFACT_TYPE key) {
return new TagsNodeRoot(key, tags.get(key));
}
}
/**
* Tag node representation (file or result)
*/
public class TagsNodeRoot extends DisplayableItemNode {
TagsNodeRoot(BlackboardArtifact.ARTIFACT_TYPE tagType, Map<String, List<BlackboardArtifact>> subTags) {
super(Children.create(new TagRootChildren(tagType, subTags), true), Lookups.singleton(tagType.getDisplayName()));
String name = null;
if (tagType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)) {
name = FILE_TAG_LABEL_NAME;
} else if (tagType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT)) {
name = RESULT_TAG_LABEL_NAME;
}
super.setName(name);
super.setDisplayName(name + " (" + subTags.values().size() + ")");
this.setIconBaseWithExtension(TAG_ICON_PATH);
}
@Override
protected Sheet createSheet() {
Sheet s = super.createSheet();
Sheet.Set ss = s.get(Sheet.PROPERTIES);
if (ss == null) {
ss = Sheet.createPropertiesSet();
s.put(ss);
}
ss.put(new NodeProperty("Name",
"Name",
"no description",
getName()));
return s;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.META;
}
@Override
public boolean isLeafTypeNode() {
return false;
}
}
/**
* Child factory to add all the Tag artifacts to a TagsRootNode with the tag
* name.
*/
private class TagRootChildren extends ChildFactory<String> {
private Map<String, List<BlackboardArtifact>> subTags;
private BlackboardArtifact.ARTIFACT_TYPE tagType;
TagRootChildren(BlackboardArtifact.ARTIFACT_TYPE tagType, Map<String, List<BlackboardArtifact>> subTags) {
super();
this.tagType = tagType;
this.subTags = subTags;
}
@Override
protected boolean createKeys(List<String> list) {
list.addAll(subTags.keySet());
return true;
}
@Override
protected Node createNodeForKey(String key) {
return new Tags.TagNodeRoot(tagType, key, subTags.get(key));
}
}
/**
* Node for each unique tag name. Shown directly under Results > Tags.
*/
public class TagNodeRoot extends DisplayableItemNode {
TagNodeRoot(BlackboardArtifact.ARTIFACT_TYPE tagType, String tagName, List<BlackboardArtifact> artifacts) {
super(Children.create(new Tags.TagsChildrenNode(tagType, tagName, artifacts), true), Lookups.singleton(tagName));
super.setName(tagName);
super.setDisplayName(tagName + " (" + artifacts.size() + ")");
if (tagName.equals(BOOKMARK_TAG_NAME)) {
this.setIconBaseWithExtension(BOOKMARK_ICON_PATH);
} else {
this.setIconBaseWithExtension(TAG_ICON_PATH);
}
}
@Override
protected Sheet createSheet() {
Sheet s = super.createSheet();
Sheet.Set ss = s.get(Sheet.PROPERTIES);
if (ss == null) {
ss = Sheet.createPropertiesSet();
s.put(ss);
}
ss.put(new NodeProperty("Name",
"Name",
"no description",
getName()));
return s;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
}
@Override
public DisplayableItemNode.TYPE getDisplayableItemNodeType() {
return DisplayableItemNode.TYPE.ARTIFACT;
}
@Override
public boolean isLeafTypeNode() {
return true;
}
}
/**
* Node representing an individual Tag artifact. For each TagsNodeRoot under
* Results > Tags, this is one of the nodes listed in the result viewer.
*/
private class TagsChildrenNode extends ChildFactory<BlackboardArtifact> {
private List<BlackboardArtifact> artifacts;
private BlackboardArtifact.ARTIFACT_TYPE tagType;
private String tagName;
private TagsChildrenNode(BlackboardArtifact.ARTIFACT_TYPE tagType, String tagName, List<BlackboardArtifact> artifacts) {
super();
this.tagType = tagType;
this.tagName = tagName;
this.artifacts = artifacts;
}
@Override
protected boolean createKeys(List<BlackboardArtifact> list) {
list.addAll(artifacts);
return true;
}
@Override
protected Node createNodeForKey(final BlackboardArtifact artifact) {
//create node with action
BlackboardArtifactNode tagNode = null;
String iconPath;
if (tagName.equals(BOOKMARK_TAG_NAME)) {
iconPath = BOOKMARK_ICON_PATH;
} else {
iconPath = TAG_ICON_PATH;
}
//create actions here where Tag logic belongs
//instead of DataResultFilterNode w/visitors, which is much less pluggable and cluttered
if (tagType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT)) {
//in case of result tag, add a action by sublcassing bb art node
//this action will be merged with other actions set DataResultFIlterNode
//otherwise in case of
tagNode = new BlackboardArtifactNode(artifact, iconPath) {
@Override
public Action[] getActions(boolean bln) {
//Action [] actions = super.getActions(bln); //To change body of generated methods, choose Tools | Templates.
Action[] actions = new Action[1];
actions[0] = new AbstractAction("View Source Result") {
@Override
public void actionPerformed(ActionEvent e) {
//open the source artifact in dir tree
BlackboardArtifact sourceArt = Tags.getArtifactFromTag(artifact.getArtifactID());
if (sourceArt != null) {
BlackboardResultViewer v = Lookup.getDefault().lookup(BlackboardResultViewer.class);
v.viewArtifact(sourceArt);
}
}
};
return actions;
}
};
} else {
//for file tag, don't subclass to add the additional actions
tagNode = new BlackboardArtifactNode(artifact, iconPath);
}
//add some additional node properties
int artifactTypeID = artifact.getArtifactTypeID();
final String NO_DESCR = "no description";
if (artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
BlackboardArtifact sourceResult = Tags.getArtifactFromTag(artifact.getArtifactID());
String resultType = sourceResult.getDisplayName();
NodeProperty resultTypeProp = new NodeProperty("Source Result Type",
"Result Type",
NO_DESCR,
resultType);
tagNode.addNodeProperty(resultTypeProp);
}
return tagNode;
}
}
/**
* Create a tag for a file with TSK_TAG_NAME as tagName.
*
* @param file to create tag for
* @param tagName TSK_TAG_NAME
* @param comment the tag comment, or null if not present
*/
public static void createTag(AbstractFile file, String tagName, String comment) {
try {
final BlackboardArtifact bookArt = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE);
List<BlackboardAttribute> attrs = new ArrayList<>();
BlackboardAttribute attr1 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID(),
"", tagName);
attrs.add(attr1);
if (comment != null && !comment.isEmpty()) {
BlackboardAttribute attr2 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID(),
"", comment);
attrs.add(attr2);
}
bookArt.addAttributes(attrs);
updateTagNamesAppSetting(tagName);
}
catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to create tag for " + file.getName(), ex);
}
}
/**
* Create a tag for an artifact with TSK_TAG_NAME as tagName.
*
* @param artifact to create tag for
* @param tagName TSK_TAG_NAME
* @param comment the tag comment or null if not present
*/
public static void createTag(BlackboardArtifact artifact, String tagName, String comment) {
try {
Case currentCase = Case.getCurrentCase();
SleuthkitCase skCase = currentCase.getSleuthkitCase();
AbstractFile file = skCase.getAbstractFileById(artifact.getObjectID());
final BlackboardArtifact bookArt = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT);
List<BlackboardAttribute> attrs = new ArrayList<>();
BlackboardAttribute attr1 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID(),
"", tagName);
if (comment != null && !comment.isEmpty()) {
BlackboardAttribute attr2 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID(),
"", comment);
attrs.add(attr2);
}
BlackboardAttribute attr3 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID(),
"", artifact.getArtifactID());
attrs.add(attr1);
attrs.add(attr3);
bookArt.addAttributes(attrs);
updateTagNamesAppSetting(tagName);
}
catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to create tag for artifact " + artifact.getArtifactID(), ex);
}
}
private static void updateTagNamesAppSetting(String tagName) {
// If this tag name is not in the current tag names app setting...
if (!appSettingTagNames.contains(tagName)) {
// Add it to the lookup.
appSettingTagNames.add(tagName);
// Add it to the setting and write the setting back to the app settings file.
if (tagNamesAppSetting.length() != 0) {
tagNamesAppSetting.append(",");
}
tagNamesAppSetting.append(tagName);
ModuleSettings.setConfigSetting(APP_SETTINGS_FILE_NAME, TAG_NAMES_SETTING_KEY, tagNamesAppSetting.toString());
}
}
/**
* Create a bookmark tag for a file.
*
* @param file to create bookmark tag for
* @param comment the bookmark comment
*/
public static void createBookmark(AbstractFile file, String comment) {
createTag(file, Tags.BOOKMARK_TAG_NAME, comment);
}
/**
* Create a bookmark tag for an artifact.
*
* @param artifact to create bookmark tag for
* @param comment the bookmark comment
*/
public static void createBookmark(BlackboardArtifact artifact, String comment) {
createTag(artifact, Tags.BOOKMARK_TAG_NAME, comment);
}
/**
* Get a list of all the bookmarks.
*
* @return a list of all bookmark artifacts
*/
static List<BlackboardArtifact> getBookmarks() {
try {
Case currentCase = Case.getCurrentCase();
SleuthkitCase skCase = currentCase.getSleuthkitCase();
return skCase.getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME, Tags.BOOKMARK_TAG_NAME);
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to get list of artifacts from the case", ex);
}
return new ArrayList<>();
}
/**
* Get a list of all the unique tag names associated with the current case plus any
* tag names stored in the application settings file.
*
* @return A collection of tag names.
*/
public static TreeSet<String> getAllTagNames() {
// Use a TreeSet<> so the union of the tag names from the two sources will be sorted.
TreeSet<String> tagNames = getTagNamesFromCurrentCase();
tagNames.addAll(appSettingTagNames);
// Make sure the book mark tag is always included.
tagNames.add(BOOKMARK_TAG_NAME);
return tagNames;
}
/**
* Get a list of all the unique tag names associated with the current case.
* Uses a custom query for speed when dealing with thousands of tags.
*
* @return A collection of tag names.
*/
@SuppressWarnings("deprecation")
public static TreeSet<String> getTagNamesFromCurrentCase() {
TreeSet<String> tagNames = new TreeSet<>();
ResultSet rs = null;
SleuthkitCase skCase = null;
try {
skCase = Case.getCurrentCase().getSleuthkitCase();
rs = skCase.runQuery("SELECT value_text"
+ " FROM blackboard_attributes"
+ " WHERE attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()
+ " GROUP BY value_text"
+ " ORDER BY value_text");
while (rs.next()) {
tagNames.add(rs.getString("value_text"));
}
}
catch (IllegalStateException ex) {
// Case.getCurrentCase() throws IllegalStateException if there is no current autopsy case.
}
catch (SQLException ex) {
logger.log(Level.SEVERE, "Failed to query the blackboard for tag names", ex);
}
finally {
if (null != skCase && null != rs) {
try {
skCase.closeRunQuery(rs);
} catch (SQLException ex) {
logger.log(Level.SEVERE, "Failed to close the query for blackboard for tag names", ex);
}
}
}
// Make sure the book mark tag is always included.
tagNames.add(BOOKMARK_TAG_NAME);
return tagNames;
}
/**
* Get the tag comment for a specified tag.
*
* @param tagArtifactId artifact id of the tag
* @return the tag comment
*/
static String getCommentFromTag(long tagArtifactId) {
try {
Case currentCase = Case.getCurrentCase();
SleuthkitCase skCase = currentCase.getSleuthkitCase();
BlackboardArtifact artifact = skCase.getBlackboardArtifact(tagArtifactId);
if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|| artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
List<BlackboardAttribute> attributes = artifact.getAttributes();
for (BlackboardAttribute att : attributes) {
if (att.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID()) {
return att.getValueString();
}
}
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to get artifact " + tagArtifactId + " from case", ex);
}
return EMPTY_COMMENT;
}
/**
* Get the artifact for a result tag.
*
* @param tagArtifactId artifact id of the tag
* @return the tag's artifact
*/
static BlackboardArtifact getArtifactFromTag(long tagArtifactId) {
try {
Case currentCase = Case.getCurrentCase();
SleuthkitCase skCase = currentCase.getSleuthkitCase();
BlackboardArtifact artifact = skCase.getBlackboardArtifact(tagArtifactId);
if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|| artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
List<BlackboardAttribute> attributes = artifact.getAttributes();
for (BlackboardAttribute att : attributes) {
if (att.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID()) {
return skCase.getBlackboardArtifact(att.getValueLong());
}
}
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to get artifact " + tagArtifactId + " from case.");
}
return null;
}
/**
* Looks up the tag names associated with either a tagged artifact or a tag artifact.
*
* @param artifact The artifact
* @return A set of unique tag names
*/
public static HashSet<String> getUniqueTagNamesForArtifact(BlackboardArtifact artifact) {
return getUniqueTagNamesForArtifact(artifact.getArtifactID(), artifact.getArtifactTypeID());
}
/**
* Looks up the tag names associated with either a tagged artifact or a tag artifact.
*
* @param artifactID The ID of the artifact
* @param artifactTypeID The ID of the artifact type
* @return A set of unique tag names
*/
public static HashSet<String> getUniqueTagNamesForArtifact(long artifactID, int artifactTypeID) {
HashSet<String> tagNames = new HashSet<>();
try {
ArrayList<Long> tagArtifactIDs = new ArrayList<>();
if (artifactTypeID == ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() ||
artifactTypeID == ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
tagArtifactIDs.add(artifactID);
} else {
List<BlackboardArtifact> tags = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifacts(ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT, artifactID);
for (BlackboardArtifact tag : tags) {
tagArtifactIDs.add(tag.getArtifactID());
}
}
for (Long tagArtifactID : tagArtifactIDs) {
String whereClause = "WHERE artifact_id = " + tagArtifactID + " AND attribute_type_id = " + ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID();
List<BlackboardAttribute> attributes = Case.getCurrentCase().getSleuthkitCase().getMatchingAttributes(whereClause);
for (BlackboardAttribute attr : attributes) {
tagNames.add(attr.getValueString());
}
}
}
catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to get tags for artifact " + artifactID, ex);
}
return tagNames;
}
}

View File

@@ -0,0 +1,91 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.datamodel;
import java.util.List;
import java.util.logging.Level;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Instances of this class are the root nodes of tree that is a sub-tree of the
* Autopsy presentation of the SleuthKit data model. The sub-tree consists of
* content and blackboard artifact tags, grouped first by tag type, then by
* tag name.
*/
public class TagsNode extends DisplayableItemNode {
private static final String DISPLAY_NAME = "Tags";
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
public TagsNode() {
super(Children.create(new TagNameNodeFactory(), true), Lookups.singleton(DISPLAY_NAME));
super.setName(DISPLAY_NAME);
super.setDisplayName(DISPLAY_NAME);
this.setIconBaseWithExtension(ICON_PATH);
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
}
@Override
protected Sheet createSheet() {
Sheet propertySheet = super.createSheet();
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
if (properties == null) {
properties = Sheet.createPropertiesSet();
propertySheet.put(properties);
}
properties.put(new NodeProperty("Name", "Name", "", getName()));
return propertySheet;
}
private static class TagNameNodeFactory extends ChildFactory<TagName> {
@Override
protected boolean createKeys(List<TagName> keys) {
try {
keys.addAll(Case.getCurrentCase().getServices().getTagsManager().getTagNamesInUse());
}
catch (TskCoreException ex) {
Logger.getLogger(TagNameNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex);
}
return true;
}
@Override
protected Node createNodeForKey(TagName key) {
return new TagNameNode(key);
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.datamodel;
/**
* Instances of this class act as keys for use by instances of the
* RootContentChildren class. RootContentChildren is a NetBeans child node
* factory built on top of the NetBeans Children.Keys class.
*/
public class TagsNodeKey implements AutopsyVisitableItem {
// Creation of a TagsNode object corresponding to a TagsNodeKey object is done
// by a CreateAutopsyNodeVisitor dispatched from the AbstractContentChildren
// override of Children.Keys<T>.createNodes().
@Override
public <T> T accept(AutopsyItemVisitor<T> v) {
return v.visit(this);
}
}

View File

@@ -45,6 +45,11 @@ public class ViewsNode extends DisplayableItemNode {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/views.png");
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
@@ -65,9 +70,4 @@ public class ViewsNode extends DisplayableItemNode {
NAME));
return s;
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.META;
}
}

View File

@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011 - 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,10 +24,10 @@ import java.util.List;
import java.util.Map;
import javax.swing.Action;
import org.openide.nodes.Sheet;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
import org.sleuthkit.datamodel.VirtualDirectory;
import org.sleuthkit.datamodel.TskData;
@@ -81,7 +81,7 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode<VirtualDirect
actions.add(null); // creates a menu separator
actions.add(ExtractAction.getInstance());
actions.add(null); // creates a menu separator
actions.add(TagAbstractFileAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions.toArray(new Action[0]);
}
@@ -118,11 +118,6 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode<VirtualDirect
return v.visit(this);
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.CONTENT;
}
@Override
public boolean isLeafTypeNode() {
return true;

View File

@@ -100,13 +100,13 @@ public class VolumeNode extends AbstractContentNode<Volume> {
return v.visit(this);
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.CONTENT;
}
}

View File

@@ -0,0 +1,113 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.directorytree;
import java.util.List;
import java.util.logging.Level;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactTagNode;
import org.sleuthkit.autopsy.datamodel.ContentTagTypeNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Instances of this class are elements in a sub-tree of the Autopsy
* presentation of the SleuthKit data model. The sub-tree consists of content
* and blackboard artifact tags, grouped first by tag type, then by tag name.
*/
public class BlackboardArtifactTagTypeNode extends DisplayableItemNode {
private static final String DISPLAY_NAME = "Result Tags";
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
public BlackboardArtifactTagTypeNode(TagName tagName) {
super(Children.create(new BlackboardArtifactTagNodeFactory(tagName), true), Lookups.singleton(tagName.getDisplayName() + " " + DISPLAY_NAME));
long tagsCount = 0;
try {
tagsCount = Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName);
}
catch (TskCoreException ex) {
Logger.getLogger(BlackboardArtifactTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get blackboard artifact tags count for " + tagName.getDisplayName() + " tag name", ex);
}
super.setName(DISPLAY_NAME);
super.setDisplayName(DISPLAY_NAME + " (" + tagsCount + ")");
this.setIconBaseWithExtension(ICON_PATH);
}
@Override
protected Sheet createSheet() {
Sheet propertySheet = super.createSheet();
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
if (properties == null) {
properties = Sheet.createPropertiesSet();
propertySheet.put(properties);
}
properties.put(new NodeProperty("Name", "Name", "", getName()));
return propertySheet;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
}
@Override
public boolean isLeafTypeNode() {
return true;
}
private static class BlackboardArtifactTagNodeFactory extends ChildFactory<BlackboardArtifactTag> {
private final TagName tagName;
BlackboardArtifactTagNodeFactory(TagName tagName) {
this.tagName = tagName;
}
@Override
protected boolean createKeys(List<BlackboardArtifactTag> keys) {
try {
// Use the blackboard artifact tags bearing the specified tag name as the keys.
keys.addAll(Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName));
}
catch (TskCoreException ex) {
Logger.getLogger(BlackboardArtifactTagTypeNode.BlackboardArtifactTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex);
}
return true;
}
@Override
protected Node createNodeForKey(BlackboardArtifactTag key) {
// The blackboard artifact tags to be wrapped are used as the keys.
return new BlackboardArtifactTagNode(key);
}
}
}

View File

@@ -47,17 +47,3 @@ ImageDetailsPanel.imgSectorSizeLabel.text=Sector Size:
ImageDetailsPanel.imgSectorSizeValue.text=...
DirectoryTreeTopComponent.backButton.text=
DirectoryTreeTopComponent.forwardButton.text=
CreateTagDialog.cancelButton.text=Cancel
CreateTagDialog.okButton.text=OK
CreateTagDialog.tagNameField.text=
CreateTagDialog.tagNameLabel.text=Tag Name:
CreateTagDialog.preexistingLabel.text=Pre-existing Tags:
CreateTagDialog.newTagPanel.border.title=New Tag
TagAndCommentDialog.tagLabel.text=Tag:
TagAndCommentDialog.tagCombo.toolTipText=Select tag to use
TagAndCommentDialog.cancelButton.text=Cancel
TagAndCommentDialog.okButton.text=OK
TagAndCommentDialog.commentText.toolTipText=Enter an optional tag comment or leave blank
TagAndCommentDialog.commentText.text=
TagAndCommentDialog.commentLabel.text=Comment:
TagAndCommentDialog.newTagButton.text=New Tag

View File

@@ -18,6 +18,8 @@
*/
package org.sleuthkit.autopsy.directorytree;
import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import java.awt.event.ActionEvent;
import java.beans.PropertyVetoException;
import java.util.ArrayList;
@@ -33,10 +35,12 @@ import org.openide.nodes.AbstractNode;
import org.openide.nodes.FilterNode;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFilePropertyType;
import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode;
import org.sleuthkit.autopsy.datamodel.ArtifactTypeNode;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.ContentTagTypeNode;
import org.sleuthkit.autopsy.datamodel.LocalFileNode;
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.DeletedContentNode;
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
@@ -61,8 +65,7 @@ import org.sleuthkit.autopsy.datamodel.LayoutFileNode;
import org.sleuthkit.autopsy.datamodel.RecentFilesFilterNode;
import org.sleuthkit.autopsy.datamodel.RecentFilesNode;
import org.sleuthkit.autopsy.datamodel.FileTypesNode;
import org.sleuthkit.autopsy.datamodel.Tags.TagNodeRoot;
import org.sleuthkit.autopsy.datamodel.Tags.TagsNodeRoot;
import org.sleuthkit.autopsy.datamodel.TagNameNode;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
@@ -168,6 +171,8 @@ public class DataResultFilterNode extends FilterNode {
//set up actions for artifact node based on its Content object
//TODO all actions need to be consolidated in single place!
//they should be set in individual Node subclass and using a utility to get Actions per Content sub-type
// TODO UPDATE: There is now a DataModelActionsFactory utility; also tags are no longer artifacts so conditionals
// can be removed.
List<Action> actions = new ArrayList<>();
@@ -182,10 +187,13 @@ public class DataResultFilterNode extends FilterNode {
|| artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
actions.add(new ViewContextAction("View File in Directory", ban));
} else {
// if the artifact links to another file, add an action to go to
// that file
Content c = findLinked(ban);
if (c != null) {
actions.add(new ViewContextAction("View File in Directory", c));
}
// action to go to the source file of the artifact
actions.add(new ViewContextAction("View Source File in Directory", ban));
}
File f = ban.getLookup().lookup(File.class);
@@ -206,8 +214,9 @@ public class DataResultFilterNode extends FilterNode {
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
actions.add(null); // creates a menu separator
actions.add(TagAbstractFileAction.getInstance());
actions.add(TagBlackboardArtifactAction.getInstance());
actions.add(AddContentTagAction.getInstance());
actions.add(AddBlackboardArtifactTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions());
}
}
if ((d = ban.getLookup().lookup(Directory.class)) != null) {
@@ -222,8 +231,9 @@ public class DataResultFilterNode extends FilterNode {
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
actions.add(null); // creates a menu separator
actions.add(TagAbstractFileAction.getInstance());
actions.add(TagBlackboardArtifactAction.getInstance());
actions.add(AddContentTagAction.getInstance());
actions.add(AddBlackboardArtifactTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions());
}
}
if ((vd = ban.getLookup().lookup(VirtualDirectory.class)) != null) {
@@ -238,8 +248,9 @@ public class DataResultFilterNode extends FilterNode {
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
actions.add(null); // creates a menu separator
actions.add(TagAbstractFileAction.getInstance());
actions.add(TagBlackboardArtifactAction.getInstance());
actions.add(AddContentTagAction.getInstance());
actions.add(AddBlackboardArtifactTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions());
}
} else if ((lf = ban.getLookup().lookup(LayoutFile.class)) != null) {
LayoutFileNode lfn = new LayoutFileNode(lf);
@@ -253,8 +264,9 @@ public class DataResultFilterNode extends FilterNode {
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
actions.add(null); // creates a menu separator
actions.add(TagAbstractFileAction.getInstance());
actions.add(TagBlackboardArtifactAction.getInstance());
actions.add(AddContentTagAction.getInstance());
actions.add(AddBlackboardArtifactTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions());
}
} else if ((locF = ban.getLookup().lookup(LocalFile.class)) != null
|| (locF = ban.getLookup().lookup(DerivedFile.class)) != null) {
@@ -269,8 +281,9 @@ public class DataResultFilterNode extends FilterNode {
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
actions.add(null); // creates a menu separator
actions.add(TagAbstractFileAction.getInstance());
actions.add(TagBlackboardArtifactAction.getInstance());
actions.add(AddContentTagAction.getInstance());
actions.add(AddBlackboardArtifactTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions());
}
}
@@ -404,15 +417,20 @@ public class DataResultFilterNode extends FilterNode {
}
@Override
public AbstractAction visit(TagNodeRoot tnr) {
return openChild(tnr);
public AbstractAction visit(TagNameNode node) {
return openChild(node);
}
@Override
public AbstractAction visit(TagsNodeRoot tnr) {
return openChild(tnr);
public AbstractAction visit(ContentTagTypeNode node) {
return openChild(node);
}
@Override
public AbstractAction visit(BlackboardArtifactTagTypeNode node) {
return openChild(node);
}
@Override
public AbstractAction visit(DirectoryNode dn) {
if (dn.getDisplayName().equals(DirectoryNode.DOTDOTDIR)) {

View File

@@ -27,6 +27,7 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
@@ -804,7 +805,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
* Refreshes the nodes in the tree to reflect updates in the database should
* be called in the gui thread
*/
void refreshTree(final BlackboardArtifact.ARTIFACT_TYPE... types) {
public void refreshTree(final BlackboardArtifact.ARTIFACT_TYPE... types) {
//save current selection
Node selectedNode = getSelectedNode();
final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
@@ -856,38 +857,53 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
}
/**
* Set selected node using the previously saved selection path to the
* selected node
* Set the selected node using a path to a previously selected node.
*
* @param path node path with node names
* @param rootNodeName name of the root node to match or null if any
* @param previouslySelectedNodePath Path to a previously selected node.
* @param rootNodeName Name of the root node to match, may be null.
*/
private void setSelectedNode(final String[] path, final String rootNodeName) {
if (path == null) {
private void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName) {
if (previouslySelectedNodePath == null) {
return;
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (path.length > 0 && (rootNodeName == null || path[0].equals(rootNodeName))) {
try {
Node newSelection = NodeOp.findPath(em.getRootContext(), path);
if (newSelection != null) {
if (rootNodeName != null) {
//called from tree auto refresh context
//remove last from backlist, because auto select will result in duplication
backList.pollLast();
}
em.setExploredContextAndSelection(newSelection, new Node[]{newSelection});
if (previouslySelectedNodePath.length > 0 && (rootNodeName == null || previouslySelectedNodePath[0].equals(rootNodeName))) {
Node selectedNode = null;
ArrayList<String> selectedNodePath = new ArrayList<>(Arrays.asList(previouslySelectedNodePath));
while (null == selectedNode && !selectedNodePath.isEmpty()) {
try {
selectedNode = NodeOp.findPath(em.getRootContext(), selectedNodePath.toArray(new String[0]));
}
catch (NodeNotFoundException ex) {
// The selected node may have been deleted (e.g., a deleted tag), so truncate the path and try again.
if (selectedNodePath.size() > 1) {
selectedNodePath.remove(selectedNodePath.size() - 1);
}
else {
StringBuilder nodePath = new StringBuilder();
for (int i = 0; i < previouslySelectedNodePath.length; ++i) {
nodePath.append(previouslySelectedNodePath[i]).append("/");
}
logger.log(Level.WARNING, "Failed to find any nodes to select on path " + nodePath.toString(), ex);
break;
}
}
}
if (null != selectedNode) {
if (rootNodeName != null) {
//called from tree auto refresh context
//remove last from backlist, because auto select will result in duplication
backList.pollLast();
}
try {
em.setExploredContextAndSelection(selectedNode, new Node[]{selectedNode});
}
catch (PropertyVetoException ex) {
logger.log(Level.WARNING, "Property veto from ExplorerManager setting selection to " + selectedNode.getName(), ex);
}
// We need to set the selection, which will refresh dataresult and get rid of the oob exception
} catch (NodeNotFoundException ex) {
logger.log(Level.WARNING, "Node not found", ex);
} catch (PropertyVetoException ex) {
logger.log(Level.WARNING, "Property Veto", ex);
}
}
}

View File

@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011 - 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,6 +18,7 @@
*/
package org.sleuthkit.autopsy.directorytree;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import java.awt.Toolkit;
import java.awt.Dimension;
import java.awt.Font;
@@ -35,6 +36,7 @@ import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentVisitor;
@@ -100,40 +102,44 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
@Override
public List<? extends Action> visit(final Directory d) {
List<Action> actions = new ArrayList<Action>();
actions.add(TagAbstractFileAction.getInstance());
List<Action> actions = new ArrayList<>();
actions.add(AddContentTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions;
}
@Override
public List<? extends Action> visit(final VirtualDirectory d) {
List<Action> actions = new ArrayList<Action>();
List<Action> actions = new ArrayList<>();
actions.add(ExtractAction.getInstance());
actions.add(TagAbstractFileAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions;
}
@Override
public List<? extends Action> visit(final DerivedFile d) {
List<Action> actions = new ArrayList<Action>();
List<Action> actions = new ArrayList<>();
actions.add(ExtractAction.getInstance());
actions.add(TagAbstractFileAction.getInstance());
actions.add(AddContentTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions;
}
@Override
public List<? extends Action> visit(final LocalFile d) {
List<Action> actions = new ArrayList<Action>();
List<Action> actions = new ArrayList<>();
actions.add(ExtractAction.getInstance());
actions.add(TagAbstractFileAction.getInstance());
actions.add(AddContentTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions;
}
@Override
public List<? extends Action> visit(final org.sleuthkit.datamodel.File d) {
List<Action> actions = new ArrayList<Action>();
List<Action> actions = new ArrayList<>();
actions.add(ExtractAction.getInstance());
actions.add(TagAbstractFileAction.getInstance());
actions.add(AddContentTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions;
}

View File

@@ -1,70 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.directorytree;
import java.awt.event.ActionEvent;
import java.util.Collection;
import javax.swing.AbstractAction;
import javax.swing.JMenuItem;
import org.openide.util.Utilities;
import org.openide.util.actions.Presenter;
import org.sleuthkit.autopsy.datamodel.Tags;
import org.sleuthkit.datamodel.AbstractFile;
public class TagAbstractFileAction extends AbstractAction implements Presenter.Popup {
// 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 TagAbstractFileAction instance;
public static synchronized TagAbstractFileAction getInstance() {
if (null == instance) {
instance = new TagAbstractFileAction();
}
return instance;
}
private TagAbstractFileAction() {
}
@Override
public JMenuItem getPopupPresenter() {
return new TagAbstractFileMenu();
}
@Override
public void actionPerformed(ActionEvent e) {
// Do nothing - this action should never be performed.
// Submenu actions are invoked instead.
}
private static class TagAbstractFileMenu extends TagMenu {
public TagAbstractFileMenu() {
super(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class).size() > 1 ? "Tag Files" : "Tag File");
}
@Override
protected void applyTag(String tagName, String comment) {
Collection<? extends AbstractFile> selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class);
for (AbstractFile file : selectedFiles) {
Tags.createTag(file, tagName, comment);
}
}
}
}

View File

@@ -1,71 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.directorytree;
import java.awt.event.ActionEvent;
import java.util.Collection;
import javax.swing.AbstractAction;
import javax.swing.JMenuItem;
import org.openide.util.Utilities;
import org.openide.util.actions.Presenter;
import org.sleuthkit.autopsy.datamodel.Tags;
import org.sleuthkit.datamodel.BlackboardArtifact;
public class TagBlackboardArtifactAction extends AbstractAction implements Presenter.Popup {
// 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 TagBlackboardArtifactAction instance;
public static synchronized TagBlackboardArtifactAction getInstance() {
if (null == instance) {
instance = new TagBlackboardArtifactAction();
}
return instance;
}
private TagBlackboardArtifactAction() {
}
@Override
public JMenuItem getPopupPresenter() {
return new TagBlackboardArtifactMenu();
}
@Override
public void actionPerformed(ActionEvent e) {
// Do nothing - this action should never be performed.
// Submenu actions are invoked instead.
}
private static class TagBlackboardArtifactMenu extends TagMenu {
public TagBlackboardArtifactMenu() {
super(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class).size() > 1 ? "Tag Results" : "Tag Result");
}
@Override
protected void applyTag(String tagName, String comment) {
Collection<? extends BlackboardArtifact> selectedArtifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class);
for (BlackboardArtifact artifact : selectedArtifacts) {
Tags.createTag(artifact, tagName, comment);
}
}
}
}

View File

@@ -1,100 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.
*/
package org.sleuthkit.autopsy.directorytree;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.TreeSet;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import org.sleuthkit.autopsy.datamodel.Tags;
import org.sleuthkit.datamodel.BlackboardArtifact;
/**
* The menu that results when one right-clicks on a file or artifact.
*/
public abstract class TagMenu extends JMenu {
public TagMenu(String menuItemText) {
super(menuItemText);
// Create the 'Quick Tag' sub-menu and add it to the tag menu.
JMenu quickTagMenu = new JMenu("Quick Tag");
add(quickTagMenu);
// Get the existing tag names.
TreeSet<String> tagNames = Tags.getAllTagNames();
if (tagNames.isEmpty()) {
JMenuItem empty = new JMenuItem("No tags");
empty.setEnabled(false);
quickTagMenu.add(empty);
}
// Add a menu item for each existing tag name to the 'Quick Tag' menu.
for (final String tagName : tagNames) {
JMenuItem tagNameItem = new JMenuItem(tagName);
tagNameItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
applyTag(tagName, "");
refreshDirectoryTree();
}
});
quickTagMenu.add(tagNameItem);
}
quickTagMenu.addSeparator();
// Create the 'New Tag' menu item and add it to the 'Quick Tag' menu.
JMenuItem newTagMenuItem = new JMenuItem("New Tag");
newTagMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String tagName = CreateTagDialog.getNewTagNameDialog(null);
if (tagName != null) {
applyTag(tagName, "");
refreshDirectoryTree();
}
}
});
quickTagMenu.add(newTagMenuItem);
// Create the 'Tag and Comment' menu item and add it to the tag menu.
JMenuItem tagAndCommentItem = new JMenuItem("Tag and Comment");
tagAndCommentItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
TagAndCommentDialog.CommentedTag commentedTag = TagAndCommentDialog.doDialog();
if (null != commentedTag) {
applyTag(commentedTag.getName(), commentedTag.getComment());
refreshDirectoryTree();
}
}
});
add(tagAndCommentItem);
}
private void refreshDirectoryTree() {
//TODO instead should send event to node children, which will call its refresh() / refreshKeys()
DirectoryTreeTopComponent viewer = DirectoryTreeTopComponent.findInstance();
viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE);
viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT);
}
protected abstract void applyTag(String tagName, String comment);
}

View File

@@ -24,12 +24,14 @@ import java.beans.PropertyVetoException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.AbstractAction;
import javax.swing.SwingWorker;
import org.openide.nodes.AbstractNode;
import org.openide.explorer.ExplorerManager;
import org.openide.explorer.view.TreeView;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
@@ -44,7 +46,14 @@ import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.VolumeSystem;
/**
* View the directory content associated with the given Artifact
* View the directory content associated with the given Artifact in the DataResultViewer.
*
* 1. Expands the Directory Tree to the location of the parent Node of the
* associated Content.
* 2. Selects the parent Node of the associated Content in the Directory Tree,
* which causes the parent Node's Children to be visible in the DataResultViewer.
* 3. Waits for all the Children to be contentNode in the DataResultViewer and
* selects the Node that represents the Content.
*/
public class ViewContextAction extends AbstractAction {
@@ -81,61 +90,116 @@ public class ViewContextAction extends AbstractAction {
Node generated = new DirectoryTreeFilterNode(new AbstractNode(new RootContentChildren(hierarchy)), true);
Children genChilds = generated.getChildren();
final DirectoryTreeTopComponent directoryTree = DirectoryTreeTopComponent.findInstance();
TreeView tree = directoryTree.getTree();
ExplorerManager man = directoryTree.getExplorerManager();
Node dirRoot = man.getRootContext();
Children dirChilds = dirRoot.getChildren();
Node imagesRoot = dirChilds.findChild(DataSourcesNode.NAME);
dirChilds = imagesRoot.getChildren();
final DirectoryTreeTopComponent dirTree = DirectoryTreeTopComponent.findInstance();
TreeView dirTreeView = dirTree.getTree();
ExplorerManager dirTreeExplorerManager = dirTree.getExplorerManager();
Node dirTreeRootNode = dirTreeExplorerManager.getRootContext();
Children dirChilds = dirTreeRootNode.getChildren();
Children currentChildren = dirChilds.findChild(DataSourcesNode.NAME).getChildren();
Node dirExplored = null;
// Find the parent node of the content in the directory tree
for (int i = 0; i < genChilds.getNodesCount() - 1; i++) {
Node currentGeneratedNode = genChilds.getNodeAt(i);
for (int j = 0; j < dirChilds.getNodesCount(); j++) {
Node currentDirectoryTreeNode = dirChilds.getNodeAt(j);
for (int j = 0; j < currentChildren.getNodesCount(); j++) {
Node currentDirectoryTreeNode = currentChildren.getNodeAt(j);
if (currentGeneratedNode.getDisplayName().equals(currentDirectoryTreeNode.getDisplayName())) {
dirExplored = currentDirectoryTreeNode;
tree.expandNode(dirExplored);
dirChilds = currentDirectoryTreeNode.getChildren();
dirTreeView.expandNode(dirExplored);
currentChildren = currentDirectoryTreeNode.getChildren();
break;
}
}
}
// Set the parent node of the content as the selection in the
// directory tree
try {
if (dirExplored != null) {
tree.expandNode(dirExplored);
man.setExploredContextAndSelection(dirExplored, new Node[]{dirExplored});
dirTreeView.expandNode(dirExplored);
dirTreeExplorerManager.setExploredContextAndSelection(dirExplored, new Node[]{dirExplored});
}
} catch (PropertyVetoException ex) {
logger.log(Level.WARNING, "Couldn't set selected node", ex);
}
// Another thread is needed because we have to wait for dataResult to populate
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
DataResultTopComponent dataResult = directoryTree.getDirectoryListing();
Node resultRoot = dataResult.getRootNode();
Children resultChilds = resultRoot.getChildren();
Node generated = content.accept(new RootContentChildren.CreateSleuthkitNodeVisitor());
for (int i = 0; i < resultChilds.getNodesCount(); i++) {
Node current = resultChilds.getNodeAt(i);
if (generated.getName().equals(current.getName())) {
dataResult.requestActive();
dataResult.setSelectedNodes(new Node[]{current});
DirectoryTreeTopComponent.getDefault().fireViewerComplete();
break;
}
}
DataResultTopComponent dataResultTC = dirTree.getDirectoryListing();
Node currentRootNodeOfDataResultTC = dataResultTC.getRootNode();
Node contentNode = content.accept(new RootContentChildren.CreateSleuthkitNodeVisitor());
new SelectionWorker(dataResultTC, contentNode.getName(), currentRootNodeOfDataResultTC).execute();
}
});
}
});
}
/**
* Waits for a Node's children to be generated, regardless of whether they
* are lazily loaded, then sets the correct selection in a specified
* DataResultTopComponent.
*/
private class SelectionWorker extends SwingWorker<Node[], Integer> {
DataResultTopComponent dataResultTC;
String nameOfNodeToSelect;
Node originalRootNodeOfDataResultTC;
SelectionWorker(DataResultTopComponent dataResult, String nameToSelect, Node originalRoot) {
this.dataResultTC = dataResult;
this.nameOfNodeToSelect = nameToSelect;
this.originalRootNodeOfDataResultTC = originalRoot;
}
@Override
protected Node[] doInBackground() throws Exception {
// Calls to Children::getNodes(true) block until all child Nodes have
// been created, regardless of whether they are created lazily.
// This means that this call will return the actual child Nodes
// and will *NEVER* return a proxy wait Node. This is done on the
// background thread to ensure we are not hanging the ui as it could
// be a lengthy operation.
return originalRootNodeOfDataResultTC.getChildren().getNodes(true);
}
@Override
protected void done() {
Node[] nodesDisplayedInDataResultViewer;
try {
nodesDisplayedInDataResultViewer = get();
} catch (InterruptedException | ExecutionException ex) {
logger.log(Level.WARNING, "Failed to get nodes in selection worker.", ex);
return;
}
// It is possible the user selected a different Node to be displayed
// in the DataResultViewer while the child Nodes were being generated.
// In that case, we don't want to set the selection because it the
// nodes returned from get() won't be in the DataResultTopComponent's
// ExplorerManager. If we did call setSelectedNodes, it would clear
// the current selection, which is not good.
if (dataResultTC.getRootNode().equals(originalRootNodeOfDataResultTC) == false) {
return;
}
// Find the correct node to select from the nodes that are displayed
// in the data result viewer and set it as the selection of the
// DataResultTopComponent.
for (Node node : nodesDisplayedInDataResultViewer) {
if (nameOfNodeToSelect.equals(node.getName())) {
dataResultTC.requestActive();
dataResultTC.setSelectedNodes(new Node[]{node});
DirectoryTreeTopComponent.getDefault().fireViewerComplete();
break;
}
}
}
}
/**
* The ReverseHierarchyVisitor class is designed to return a list of Content

View File

@@ -24,7 +24,7 @@ FileSearchTopComponent.dateCheckBox1.text=Date:
FileSearchTopComponent.dateFiltersButton1.text=Date Filters
KnownStatusSearchPanel.knownCheckBox.text=Known Status:
KnownStatusSearchPanel.knownBadOptionCheckBox.text=Known bad
KnownStatusSearchPanel.knownOptionCheckBox.text=Known (NSRL)
KnownStatusSearchPanel.knownOptionCheckBox.text=Known (NSRL or other)
KnownStatusSearchPanel.unknownOptionCheckBox.text=Unknown
DateSearchPanel.dateCheckBox.text=Date:
DateSearchPanel.jLabel4.text=Timezone:

View File

@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011 - 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -55,7 +55,7 @@ class KnownStatusSearchFilter extends AbstractFileSearchFilter<KnownStatusSearch
String expr = "0";
if (unknown) {
expr += " or " + predicateHelper(FileKnown.UKNOWN);
expr += " or " + predicateHelper(FileKnown.UNKNOWN);
}
if (known) {
expr += " or " + predicateHelper(FileKnown.KNOWN);

View File

@@ -1,4 +1,4 @@
<?xml version="1.1" encoding="UTF-8" ?>
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
@@ -64,6 +64,9 @@
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="KnownStatusSearchPanel.knownOptionCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="knownOptionCheckBoxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="knownBadOptionCheckBox">
<Properties>

View File

@@ -74,6 +74,11 @@ class KnownStatusSearchPanel extends javax.swing.JPanel {
knownOptionCheckBox.setSelected(true);
knownOptionCheckBox.setText(org.openide.util.NbBundle.getMessage(KnownStatusSearchPanel.class, "KnownStatusSearchPanel.knownOptionCheckBox.text")); // NOI18N
knownOptionCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
knownOptionCheckBoxActionPerformed(evt);
}
});
knownBadOptionCheckBox.setSelected(true);
knownBadOptionCheckBox.setText(org.openide.util.NbBundle.getMessage(KnownStatusSearchPanel.class, "KnownStatusSearchPanel.knownBadOptionCheckBox.text")); // NOI18N
@@ -102,6 +107,11 @@ class KnownStatusSearchPanel extends javax.swing.JPanel {
.addComponent(knownBadOptionCheckBox))
);
}// </editor-fold>//GEN-END:initComponents
private void knownOptionCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownOptionCheckBoxActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_knownOptionCheckBoxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JCheckBox knownBadOptionCheckBox;
private javax.swing.JCheckBox knownCheckBox;

Some files were not shown because too many files have changed in this diff Show More