mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-19 11:07:43 +00:00
Merge pull request #3804 from raman-bt/3802_group_tree_by_datasource
3802: Group tree by data source
This commit is contained in:
commit
b856c55ffc
@ -166,6 +166,21 @@ public class TagsManager implements Closeable {
|
||||
return caseDb.getTagNamesInUse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects all of the rows from the tag_names table in the case database for
|
||||
* which there is at least one matching row in the content_tags or
|
||||
* blackboard_artifact_tags tables, for the given data source object id.
|
||||
*
|
||||
* @param dsObjId data source object id
|
||||
*
|
||||
* @return A list, possibly empty, of TagName data transfer objects (DTOs)
|
||||
* for the rows.
|
||||
*
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public List<TagName> getTagNamesInUse(long dsObjId) throws TskCoreException {
|
||||
return caseDb.getTagNamesInUse(dsObjId);
|
||||
}
|
||||
/**
|
||||
* Gets a map of tag display names to tag name entries in the case database.
|
||||
* It has keys for the display names of the standard tag types, the current
|
||||
@ -401,6 +416,24 @@ public class TagsManager implements Closeable {
|
||||
return caseDb.getContentTagsCountByTagName(tagName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets content tags count by tag name, for the given data source
|
||||
*
|
||||
* @param tagName The representation of the desired tag type in the case
|
||||
* database, which can be obtained by calling getTagNames and/or addTagName.
|
||||
*
|
||||
* @param dsObjId data source object id
|
||||
*
|
||||
* @return A count of the content tags with the specified tag name, and for
|
||||
* the given data source
|
||||
*
|
||||
* @throws TskCoreException If there is an error getting the tags count from
|
||||
* the case database.
|
||||
*/
|
||||
public long getContentTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
|
||||
return caseDb.getContentTagsCountByTagName(tagName, dsObjId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a content tag by tag id.
|
||||
*
|
||||
@ -430,6 +463,23 @@ public class TagsManager implements Closeable {
|
||||
return caseDb.getContentTagsByTagName(tagName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets content tags by tag name, for the given data source.
|
||||
*
|
||||
* @param tagName The tag name of interest.
|
||||
*
|
||||
* @param dsObjId data source object id
|
||||
*
|
||||
* @return A list, possibly empty, of the content tags with the specified
|
||||
* tag name, and for the given data source.
|
||||
*
|
||||
* @throws TskCoreException If there is an error getting the tags from the
|
||||
* case database.
|
||||
*/
|
||||
public List<ContentTag> getContentTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
|
||||
return caseDb.getContentTagsByTagName(tagName, dsObjId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets content tags count by content.
|
||||
*
|
||||
@ -531,6 +581,24 @@ public class TagsManager implements Closeable {
|
||||
return caseDb.getBlackboardArtifactTagsCountByTagName(tagName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an artifact tags count by tag name, for the given data source.
|
||||
*
|
||||
* @param tagName The representation of the desired tag type in the case
|
||||
* database, which can be obtained by calling getTagNames
|
||||
* and/or addTagName.
|
||||
* @param dsObjId data source object id
|
||||
*
|
||||
* @return A count of the artifact tags with the specified tag name,
|
||||
* for the given data source.
|
||||
*
|
||||
* @throws TskCoreException If there is an error getting the tags count from
|
||||
* the case database.
|
||||
*/
|
||||
public long getBlackboardArtifactTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
|
||||
return caseDb.getBlackboardArtifactTagsCountByTagName(tagName, dsObjId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an artifact tag by tag id.
|
||||
*
|
||||
@ -562,6 +630,24 @@ public class TagsManager implements Closeable {
|
||||
return caseDb.getBlackboardArtifactTagsByTagName(tagName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets artifact tags by tag name, for specified data source.
|
||||
*
|
||||
* @param tagName The representation of the desired tag type in the case
|
||||
* database, which can be obtained by calling getTagNames
|
||||
* and/or addTagName.
|
||||
* @param dsObjId data source object id
|
||||
*
|
||||
* @return A list, possibly empty, of the artifact tags with the specified
|
||||
* tag name, for the specified data source.
|
||||
*
|
||||
* @throws TskCoreException If there is an error getting the tags from the
|
||||
* case database.
|
||||
*/
|
||||
public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
|
||||
return caseDb.getBlackboardArtifactTagsByTagName(tagName, dsObjId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets artifact tags for a particular artifact.
|
||||
*
|
||||
|
@ -69,6 +69,7 @@ public final class UserPreferences {
|
||||
private static final String MODE = "AutopsyMode"; // NON-NLS
|
||||
private static final String MAX_NUM_OF_LOG_FILE = "MaximumNumberOfLogFiles";
|
||||
private static final int LOG_FILE_NUM_INT = 10;
|
||||
public static final String GROUP_ITEMS_IN_TREE_BY_DATASOURCE = "GroupItemsInTreeByDataSource"; //NON-NLS
|
||||
|
||||
// Prevent instantiation.
|
||||
private UserPreferences() {
|
||||
@ -187,6 +188,14 @@ public final class UserPreferences {
|
||||
preferences.putInt(NUMBER_OF_FILE_INGEST_THREADS, value);
|
||||
}
|
||||
|
||||
public static boolean groupItemsInTreeByDatasource() {
|
||||
return preferences.getBoolean(GROUP_ITEMS_IN_TREE_BY_DATASOURCE, false);
|
||||
}
|
||||
|
||||
public static void setGroupItemsInTreeByDatasource(boolean value) {
|
||||
preferences.putBoolean(GROUP_ITEMS_IN_TREE_BY_DATASOURCE, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads persisted case database connection info.
|
||||
*
|
||||
|
@ -162,12 +162,12 @@ abstract class AbstractContentChildren<T> extends Keys<T> {
|
||||
|
||||
@Override
|
||||
public AbstractNode visit(DeletedContent dc) {
|
||||
return new DeletedContent.DeletedContentsNode(dc.getSleuthkitCase());
|
||||
return new DeletedContent.DeletedContentsNode(dc.getSleuthkitCase(), dc.filteringDataSourceObjId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNode visit(FileSize dc) {
|
||||
return new FileSize.FileSizeRootNode(dc.getSleuthkitCase());
|
||||
return new FileSize.FileSizeRootNode(dc.getSleuthkitCase(), dc.filteringDataSourceObjId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -192,22 +192,27 @@ abstract class AbstractContentChildren<T> extends Keys<T> {
|
||||
|
||||
@Override
|
||||
public AbstractNode visit(Tags tagsNodeKey) {
|
||||
return tagsNodeKey.new RootNode();
|
||||
return tagsNodeKey.new RootNode(tagsNodeKey.filteringDataSourceObjId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNode visit(DataSources i) {
|
||||
return new DataSourcesNode();
|
||||
return new DataSourcesNode(i.filteringDataSourceObjId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNode visit(DataSourceGrouping datasourceGrouping) {
|
||||
return new DataSourceGroupingNode(datasourceGrouping.getDataSource());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNode visit(Views v) {
|
||||
return new ViewsNode(v.getSleuthkitCase());
|
||||
return new ViewsNode(v.getSleuthkitCase(), v.filteringDataSourceObjId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNode visit(Results r) {
|
||||
return new ResultsNode(r.getSleuthkitCase());
|
||||
public AbstractNode visit(Results results) {
|
||||
return new ResultsNode(results.getSleuthkitCase(), results.filteringDataSourceObjId() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -29,6 +29,8 @@ public interface AutopsyItemVisitor<T> {
|
||||
|
||||
T visit(DataSources i);
|
||||
|
||||
T visit(DataSourceGrouping datasourceGrouping);
|
||||
|
||||
T visit(Views v);
|
||||
|
||||
T visit(FileTypesByExtension sf);
|
||||
@ -173,6 +175,11 @@ public interface AutopsyItemVisitor<T> {
|
||||
return defaultVisit(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(DataSourceGrouping datasourceGrouping) {
|
||||
return defaultVisit(datasourceGrouping);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(Results r) {
|
||||
return defaultVisit(r);
|
||||
|
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2018 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.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Node;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.SleuthkitVisitableItem;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
|
||||
/**
|
||||
* Child factory to create the top level children of the autopsy tree
|
||||
*
|
||||
*/
|
||||
public class AutopsyTreeChildrenFactory extends ChildFactory.Detachable<Object> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AutopsyTreeChildrenFactory.class.getName());
|
||||
private final SleuthkitCase tskCase;
|
||||
|
||||
/**
|
||||
* Constructs the child factory
|
||||
* @param tskCase
|
||||
*/
|
||||
public AutopsyTreeChildrenFactory(SleuthkitCase tskCase) {
|
||||
this.tskCase = tskCase;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener for handling DATA_SOURCE_ADDED events.
|
||||
*/
|
||||
private final PropertyChangeListener pcl = new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
|
||||
refreshChildren();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void addNotify() {
|
||||
super.addNotify();
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED), pcl);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeNotify() {
|
||||
super.removeNotify();
|
||||
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED), pcl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates keys for the top level children.
|
||||
*
|
||||
* @param list list of keys created
|
||||
* @return true, indicating that the key list is complete
|
||||
*/
|
||||
@Override
|
||||
protected boolean createKeys(List<Object> list) {
|
||||
|
||||
try {
|
||||
if (UserPreferences.groupItemsInTreeByDatasource()) {
|
||||
List<DataSource> dataSources = tskCase.getDataSources();
|
||||
List<DataSourceGrouping> keys = new ArrayList<>();
|
||||
dataSources.forEach((datasource) -> {
|
||||
keys.add(new DataSourceGrouping(datasource));
|
||||
});
|
||||
list.addAll(keys);
|
||||
|
||||
list.add(new Reports());
|
||||
} else {
|
||||
|
||||
List<AutopsyVisitableItem> keys = new ArrayList<>(Arrays.asList(
|
||||
new DataSources(),
|
||||
new Views(tskCase),
|
||||
new Results(tskCase),
|
||||
new Tags(),
|
||||
new Reports()));
|
||||
|
||||
list.addAll(keys);
|
||||
}
|
||||
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
logger.log(Level.SEVERE, "Error getting datas sources list from the database.", tskCoreException);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates nodes for the top level Key
|
||||
*
|
||||
* @param key
|
||||
*
|
||||
* @return Node for the key, null if key is unknown.
|
||||
*/
|
||||
@Override
|
||||
protected Node createNodeForKey(Object key) {
|
||||
|
||||
if (key instanceof SleuthkitVisitableItem) {
|
||||
return ((SleuthkitVisitableItem) key).accept(new RootContentChildren.CreateSleuthkitNodeVisitor());
|
||||
} else if (key instanceof AutopsyVisitableItem) {
|
||||
return ((AutopsyVisitableItem) key).accept(new RootContentChildren.CreateAutopsyNodeVisitor());
|
||||
}
|
||||
else {
|
||||
logger.log(Level.SEVERE, "Unknown key type ", key.getClass().getName());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the children
|
||||
*/
|
||||
public void refreshChildren() {
|
||||
refresh(true);
|
||||
}
|
||||
}
|
@ -56,6 +56,7 @@ DataModelActionsFactory.viewNewWin.text=View in New Window
|
||||
DataModelActionsFactory.openExtViewer.text=Open in External Viewer
|
||||
DataModelActionsFactory.srfFileSameMD5.text=Search for files with the same MD5 hash
|
||||
DataSourcesNode.name=Data Sources
|
||||
DataSourcesNode.group_by_datasource.name=Data Source Files
|
||||
DataSourcesNode.createSheet.name.name=Name
|
||||
DataSourcesNode.createSheet.name.displayName=Name
|
||||
DataSourcesNode.createSheet.name.desc=no description
|
||||
|
@ -57,6 +57,7 @@ DataModelActionsFactory.viewNewWin.text=\u65b0\u898f\u30a6\u30a3\u30f3\u30c9\u30
|
||||
DataModelActionsFactory.openExtViewer.text=\u5916\u90e8\u30d3\u30e5\u30fc\u30a2\u306b\u8868\u793a
|
||||
DataModelActionsFactory.srfFileSameMD5.text=\u540c\u3058MD5\u30cf\u30c3\u30b7\u30e5\u3092\u6301\u3064\u30d5\u30a1\u30a4\u30eb\u3092\u691c\u7d22
|
||||
DataSourcesNode.name=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9
|
||||
DataSourcesNode.group_by_datasource.name=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb
|
||||
DataSourcesNode.createSheet.name.name=\u540d\u524d
|
||||
DataSourcesNode.createSheet.name.displayName=\u540d\u524d
|
||||
DataSourcesNode.createSheet.name.desc=\u8aac\u660e\u304c\u3042\u308a\u307e\u305b\u3093
|
||||
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2018 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 org.sleuthkit.datamodel.DataSource;
|
||||
|
||||
/**
|
||||
* A top level UI grouping of Files, Views, Results, Tags
|
||||
* for 'Group by Data Source' view of the tree.
|
||||
*
|
||||
*/
|
||||
public class DataSourceGrouping implements AutopsyVisitableItem {
|
||||
|
||||
private final DataSource dataSource;
|
||||
|
||||
public DataSourceGrouping(DataSource dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
DataSource getDataSource() {
|
||||
return this.dataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(AutopsyItemVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2018 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.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.Image;
|
||||
import org.sleuthkit.datamodel.LocalFilesDataSource;
|
||||
|
||||
|
||||
/**
|
||||
* Data source grouping node - an optional grouping node in the data tree view
|
||||
*
|
||||
*/
|
||||
class DataSourceGroupingNode extends DisplayableItemNode {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DataSourceGroupingNode.class.getName());
|
||||
|
||||
/**
|
||||
* Creates a data source grouping node for the given data source.
|
||||
*
|
||||
* @param dataSource specifies the data source
|
||||
*/
|
||||
DataSourceGroupingNode(DataSource dataSource) {
|
||||
|
||||
super (Optional.ofNullable(createDSGroupingNodeChildren(dataSource))
|
||||
.orElse(new RootContentChildren(Arrays.asList(Collections.EMPTY_LIST))));
|
||||
|
||||
if (dataSource instanceof Image) {
|
||||
Image image = (Image) dataSource;
|
||||
|
||||
super.setName(image.getName());
|
||||
super.setDisplayName(image.getName());
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/image.png");
|
||||
} else if (dataSource instanceof LocalFilesDataSource) {
|
||||
LocalFilesDataSource localFilesDataSource = (LocalFilesDataSource) dataSource;
|
||||
|
||||
super.setName(localFilesDataSource.getName());
|
||||
super.setDisplayName(localFilesDataSource.getName());
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static RootContentChildren createDSGroupingNodeChildren(DataSource dataSource) {
|
||||
|
||||
long dsObjId = dataSource.getId();
|
||||
try {
|
||||
return new RootContentChildren(Arrays.asList(
|
||||
new DataSources(dsObjId),
|
||||
new Views(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId),
|
||||
new Results(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId),
|
||||
new Tags(dsObjId) )
|
||||
|
||||
);
|
||||
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
logger.log(Level.SEVERE, "Error getting open case.", ex); //NON-NLS
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
@ -23,7 +23,18 @@ package org.sleuthkit.autopsy.datamodel;
|
||||
*/
|
||||
public class DataSources implements AutopsyVisitableItem {
|
||||
|
||||
private final long datasourceObjId;
|
||||
|
||||
public DataSources() {
|
||||
this(0);
|
||||
}
|
||||
|
||||
public DataSources(long datasourceObjId) {
|
||||
this.datasourceObjId = datasourceObjId;
|
||||
}
|
||||
|
||||
long filteringDataSourceObjId() {
|
||||
return this.datasourceObjId;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
@ -33,6 +34,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskDataException;
|
||||
|
||||
/**
|
||||
* Nodes for the images
|
||||
@ -40,22 +42,27 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
public class DataSourcesNode extends DisplayableItemNode {
|
||||
|
||||
public static final String NAME = NbBundle.getMessage(DataSourcesNode.class, "DataSourcesNode.name");
|
||||
private final String displayName;
|
||||
|
||||
// NOTE: The images passed in via argument will be ignored.
|
||||
@Deprecated
|
||||
public DataSourcesNode(List<Content> images) {
|
||||
super(new DataSourcesNodeChildren(), Lookups.singleton(NAME));
|
||||
init();
|
||||
this(0);
|
||||
}
|
||||
|
||||
public DataSourcesNode() {
|
||||
super(new DataSourcesNodeChildren(), Lookups.singleton(NAME));
|
||||
this(0);
|
||||
}
|
||||
|
||||
public DataSourcesNode(long dsObjId) {
|
||||
super(new DataSourcesNodeChildren(dsObjId), Lookups.singleton(NAME));
|
||||
displayName = (dsObjId > 0) ? NbBundle.getMessage(DataSourcesNode.class, "DataSourcesNode.group_by_datasource.name") : NAME;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setName(NAME);
|
||||
setDisplayName(NAME);
|
||||
setDisplayName(displayName);
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/image.png"); //NON-NLS
|
||||
}
|
||||
|
||||
@ -70,12 +77,18 @@ public class DataSourcesNode extends DisplayableItemNode {
|
||||
public static class DataSourcesNodeChildren extends AbstractContentChildren<Content> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DataSourcesNodeChildren.class.getName());
|
||||
private final long datasourceObjId;
|
||||
|
||||
List<Content> currentKeys;
|
||||
|
||||
public DataSourcesNodeChildren() {
|
||||
this(0);
|
||||
}
|
||||
|
||||
public DataSourcesNodeChildren(long dsObjId) {
|
||||
super();
|
||||
this.currentKeys = new ArrayList<>();
|
||||
this.datasourceObjId = dsObjId;
|
||||
}
|
||||
|
||||
private final PropertyChangeListener pcl = new PropertyChangeListener() {
|
||||
@ -103,9 +116,15 @@ public class DataSourcesNode extends DisplayableItemNode {
|
||||
|
||||
private void reloadKeys() {
|
||||
try {
|
||||
if (datasourceObjId == 0) {
|
||||
currentKeys = Case.getCurrentCaseThrows().getDataSources();
|
||||
}
|
||||
else {
|
||||
Content content = Case.getCurrentCaseThrows().getSleuthkitCase().getDataSource(datasourceObjId);
|
||||
currentKeys = new ArrayList<>(Arrays.asList(content));
|
||||
}
|
||||
setKeys(currentKeys);
|
||||
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||
} catch (TskCoreException | NoCurrentCaseException | TskDataException ex) {
|
||||
logger.log(Level.SEVERE, "Error getting data sources: {0}", ex.getMessage()); // NON-NLS
|
||||
setKeys(Collections.<Content>emptySet());
|
||||
}
|
||||
|
@ -61,6 +61,7 @@ import org.sleuthkit.datamodel.TskData;
|
||||
public class DeletedContent implements AutopsyVisitableItem {
|
||||
|
||||
private SleuthkitCase skCase;
|
||||
private final long datasourceObjId;
|
||||
|
||||
@NbBundle.Messages({"DeletedContent.fsDelFilter.text=File System",
|
||||
"DeletedContent.allDelFilter.text=All"})
|
||||
@ -101,7 +102,16 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
public DeletedContent(SleuthkitCase skCase) {
|
||||
this(skCase, 0);
|
||||
}
|
||||
|
||||
public DeletedContent(SleuthkitCase skCase, long dsObjId) {
|
||||
this.skCase = skCase;
|
||||
this.datasourceObjId = dsObjId;
|
||||
}
|
||||
|
||||
long filteringDataSourceObjId() {
|
||||
return this.datasourceObjId;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -118,8 +128,8 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
@NbBundle.Messages("DeletedContent.deletedContentsNode.name=Deleted Files")
|
||||
private static final String NAME = Bundle.DeletedContent_deletedContentsNode_name();
|
||||
|
||||
DeletedContentsNode(SleuthkitCase skCase) {
|
||||
super(Children.create(new DeletedContentsChildren(skCase), true), Lookups.singleton(NAME));
|
||||
DeletedContentsNode(SleuthkitCase skCase, long datasourceObjId) {
|
||||
super(Children.create(new DeletedContentsChildren(skCase, datasourceObjId), true), Lookups.singleton(NAME));
|
||||
super.setName(NAME);
|
||||
super.setDisplayName(NAME);
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS
|
||||
@ -164,11 +174,13 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
|
||||
private SleuthkitCase skCase;
|
||||
private Observable notifier;
|
||||
private final long datasourceObjId;
|
||||
// true if we have already told user that not all files will be shown
|
||||
private static volatile boolean maxFilesDialogShown = false;
|
||||
|
||||
public DeletedContentsChildren(SleuthkitCase skCase) {
|
||||
public DeletedContentsChildren(SleuthkitCase skCase, long dsObjId) {
|
||||
this.skCase = skCase;
|
||||
this.datasourceObjId = dsObjId;
|
||||
this.notifier = new DeletedContentsChildrenObservable();
|
||||
}
|
||||
|
||||
@ -257,24 +269,27 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(DeletedContent.DeletedContentFilter key) {
|
||||
return new DeletedContentNode(skCase, key, notifier);
|
||||
return new DeletedContentNode(skCase, key, notifier, datasourceObjId);
|
||||
}
|
||||
|
||||
public class DeletedContentNode extends DisplayableItemNode {
|
||||
|
||||
private final DeletedContent.DeletedContentFilter filter;
|
||||
private final long datasourceObjId;
|
||||
|
||||
// Use version that has observer for updates
|
||||
@Deprecated
|
||||
DeletedContentNode(SleuthkitCase skCase, DeletedContent.DeletedContentFilter filter) {
|
||||
super(Children.create(new DeletedContentChildren(filter, skCase, null), true), Lookups.singleton(filter.getDisplayName()));
|
||||
DeletedContentNode(SleuthkitCase skCase, DeletedContent.DeletedContentFilter filter, long dsObjId) {
|
||||
super(Children.create(new DeletedContentChildren(filter, skCase, null, dsObjId ), true), Lookups.singleton(filter.getDisplayName()));
|
||||
this.filter = filter;
|
||||
this.datasourceObjId = dsObjId;
|
||||
init();
|
||||
}
|
||||
|
||||
DeletedContentNode(SleuthkitCase skCase, DeletedContent.DeletedContentFilter filter, Observable o) {
|
||||
super(Children.create(new DeletedContentChildren(filter, skCase, o), true), Lookups.singleton(filter.getDisplayName()));
|
||||
DeletedContentNode(SleuthkitCase skCase, DeletedContent.DeletedContentFilter filter, Observable o, long dsObjId) {
|
||||
super(Children.create(new DeletedContentChildren(filter, skCase, o, dsObjId), true), Lookups.singleton(filter.getDisplayName()));
|
||||
this.filter = filter;
|
||||
this.datasourceObjId = dsObjId;
|
||||
init();
|
||||
o.addObserver(new DeletedContentNodeObserver());
|
||||
}
|
||||
@ -299,7 +314,7 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
|
||||
private void updateDisplayName() {
|
||||
//get count of children without preloading all children nodes
|
||||
final long count = DeletedContentChildren.calculateItems(skCase, filter);
|
||||
final long count = DeletedContentChildren.calculateItems(skCase, filter, datasourceObjId);
|
||||
//final long count = getChildren().getNodesCount(true);
|
||||
super.setDisplayName(filter.getDisplayName() + " (" + count + ")");
|
||||
}
|
||||
@ -351,11 +366,13 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
private static final Logger logger = Logger.getLogger(DeletedContentChildren.class.getName());
|
||||
private static final int MAX_OBJECTS = 10001;
|
||||
private final Observable notifier;
|
||||
private final long datasourceObjId;
|
||||
|
||||
DeletedContentChildren(DeletedContent.DeletedContentFilter filter, SleuthkitCase skCase, Observable o) {
|
||||
DeletedContentChildren(DeletedContent.DeletedContentFilter filter, SleuthkitCase skCase, Observable o, long datasourceObjId) {
|
||||
this.skCase = skCase;
|
||||
this.filter = filter;
|
||||
this.notifier = o;
|
||||
this.datasourceObjId = datasourceObjId;
|
||||
}
|
||||
|
||||
private final Observer observer = new DeletedContentChildrenObserver();
|
||||
@ -405,7 +422,7 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
return true;
|
||||
}
|
||||
|
||||
static private String makeQuery(DeletedContent.DeletedContentFilter filter) {
|
||||
static private String makeQuery(DeletedContent.DeletedContentFilter filter, long filteringDSObjId) {
|
||||
String query = "";
|
||||
switch (filter) {
|
||||
case FS_DELETED_FILTER:
|
||||
@ -443,6 +460,10 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
+ " OR known IS NULL)"; //NON-NLS
|
||||
}
|
||||
|
||||
if (UserPreferences.groupItemsInTreeByDatasource()) {
|
||||
query += " AND data_source_obj_id = " + filteringDSObjId;
|
||||
}
|
||||
|
||||
query += " LIMIT " + MAX_OBJECTS; //NON-NLS
|
||||
return query;
|
||||
}
|
||||
@ -450,7 +471,7 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
private List<AbstractFile> runFsQuery() {
|
||||
List<AbstractFile> ret = new ArrayList<>();
|
||||
|
||||
String query = makeQuery(filter);
|
||||
String query = makeQuery(filter, datasourceObjId);
|
||||
try {
|
||||
ret = skCase.findAllFilesWhere(query);
|
||||
} catch (TskCoreException e) {
|
||||
@ -469,9 +490,9 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static long calculateItems(SleuthkitCase sleuthkitCase, DeletedContent.DeletedContentFilter filter) {
|
||||
static long calculateItems(SleuthkitCase sleuthkitCase, DeletedContent.DeletedContentFilter filter, long datasourceObjId) {
|
||||
try {
|
||||
return sleuthkitCase.countFilesWhere(makeQuery(filter));
|
||||
return sleuthkitCase.countFilesWhere(makeQuery(filter, datasourceObjId));
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error getting deleted files search view count", ex); //NON-NLS
|
||||
return 0;
|
||||
|
@ -61,6 +61,8 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
*/
|
||||
T visit(ViewsNode vn);
|
||||
|
||||
T visit(DataSourceGroupingNode dataSourceGroupingNode);
|
||||
|
||||
T visit(org.sleuthkit.autopsy.datamodel.FileTypesByExtension.FileExtensionNode fsfn);
|
||||
|
||||
T visit(DeletedContentNode dcn);
|
||||
@ -336,6 +338,11 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
return defaultVisit(vn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(DataSourceGroupingNode dataSourceGroupingNode) {
|
||||
return defaultVisit(dataSourceGroupingNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(ResultsNode rn) {
|
||||
return defaultVisit(rn);
|
||||
|
@ -40,6 +40,7 @@ import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||
@ -86,10 +87,29 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
}
|
||||
private SleuthkitCase skCase;
|
||||
private final EmailResults emailResults;
|
||||
private final long datasourceObjId;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param skCase Case DB
|
||||
*/
|
||||
public EmailExtracted(SleuthkitCase skCase) {
|
||||
this(skCase, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param skCase Case DB
|
||||
* @param objId Object id of the data source
|
||||
*
|
||||
*/
|
||||
public EmailExtracted(SleuthkitCase skCase, long objId) {
|
||||
this.skCase = skCase;
|
||||
this.datasourceObjId = objId;
|
||||
emailResults = new EmailResults();
|
||||
}
|
||||
|
||||
@ -141,6 +161,9 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
+ "attribute_type_id=" + pathAttrId //NON-NLS
|
||||
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
|
||||
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
|
||||
if (UserPreferences.groupItemsInTreeByDatasource()) {
|
||||
query += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId;
|
||||
}
|
||||
|
||||
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
|
||||
ResultSet resultSet = dbQuery.getResultSet();
|
||||
|
@ -35,9 +35,11 @@ import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||
import org.sleuthkit.datamodel.Blackboard;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT;
|
||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG;
|
||||
@ -57,10 +59,29 @@ import org.sleuthkit.datamodel.TskException;
|
||||
public class ExtractedContent implements AutopsyVisitableItem {
|
||||
|
||||
private SleuthkitCase skCase; // set to null after case has been closed
|
||||
private Blackboard blackboard;
|
||||
public static final String NAME = NbBundle.getMessage(RootNode.class, "ExtractedContentNode.name.text");
|
||||
private final long datasourceObjId;
|
||||
|
||||
/**
|
||||
* Constructs extracted content object
|
||||
*
|
||||
* @param skCase Case DB
|
||||
*/
|
||||
public ExtractedContent(SleuthkitCase skCase) {
|
||||
this(skCase, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs extracted content object
|
||||
*
|
||||
* @param skCase Case DB
|
||||
* @param objId Object id of the parent datasource
|
||||
*/
|
||||
public ExtractedContent(SleuthkitCase skCase, long objId) {
|
||||
this.skCase = skCase;
|
||||
this.datasourceObjId = objId;
|
||||
this.blackboard = skCase.getBlackboard();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -270,7 +291,10 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
||||
//TEST COMMENT
|
||||
if (skCase != null) {
|
||||
try {
|
||||
List<BlackboardArtifact.Type> types = skCase.getArtifactTypesInUse();
|
||||
List<BlackboardArtifact.Type> types = (UserPreferences.groupItemsInTreeByDatasource()) ?
|
||||
blackboard.getArtifactTypesInUse(datasourceObjId) :
|
||||
skCase.getArtifactTypesInUse() ;
|
||||
|
||||
types.removeAll(doNotShow);
|
||||
Collections.sort(types,
|
||||
new Comparator<BlackboardArtifact.Type>() {
|
||||
@ -332,7 +356,9 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
||||
// a performance increase might be had by adding a
|
||||
// "getBlackboardArtifactCount()" method to skCase
|
||||
try {
|
||||
this.childCount = skCase.getBlackboardArtifactsTypeCount(type.getTypeID());
|
||||
this.childCount = UserPreferences.groupItemsInTreeByDatasource() ?
|
||||
blackboard.getArtifactsCount(type.getTypeID(), datasourceObjId) :
|
||||
skCase.getBlackboardArtifactsTypeCount(type.getTypeID());
|
||||
} catch (TskException ex) {
|
||||
Logger.getLogger(TypeNode.class.getName())
|
||||
.log(Level.WARNING, "Error getting child count", ex); //NON-NLS
|
||||
@ -454,7 +480,10 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
||||
protected boolean createKeys(List<BlackboardArtifact> list) {
|
||||
if (skCase != null) {
|
||||
try {
|
||||
List<BlackboardArtifact> arts = skCase.getBlackboardArtifacts(type.getTypeID());
|
||||
List<BlackboardArtifact> arts =
|
||||
UserPreferences.groupItemsInTreeByDatasource() ?
|
||||
blackboard.getArtifacts(type.getTypeID(), datasourceObjId) :
|
||||
skCase.getBlackboardArtifacts(type.getTypeID());
|
||||
list.addAll(arts);
|
||||
} catch (TskException ex) {
|
||||
Logger.getLogger(ArtifactFactory.class.getName()).log(Level.SEVERE, "Couldn't get blackboard artifacts from database", ex); //NON-NLS
|
||||
|
@ -61,6 +61,7 @@ import org.sleuthkit.datamodel.VirtualDirectory;
|
||||
public class FileSize implements AutopsyVisitableItem {
|
||||
|
||||
private SleuthkitCase skCase;
|
||||
private final long datasourceObjId;
|
||||
|
||||
public enum FileSizeFilter implements AutopsyVisitableItem {
|
||||
|
||||
@ -97,7 +98,12 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
public FileSize(SleuthkitCase skCase) {
|
||||
this(skCase, 0);
|
||||
}
|
||||
|
||||
public FileSize(SleuthkitCase skCase, long dsObjId) {
|
||||
this.skCase = skCase;
|
||||
this.datasourceObjId = dsObjId;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -109,6 +115,9 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
return this.skCase;
|
||||
}
|
||||
|
||||
long filteringDataSourceObjId() {
|
||||
return this.datasourceObjId;
|
||||
}
|
||||
/*
|
||||
* Root node. Children are nodes for specific sizes.
|
||||
*/
|
||||
@ -116,8 +125,8 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
|
||||
private static final String NAME = NbBundle.getMessage(FileSize.class, "FileSize.fileSizeRootNode.name");
|
||||
|
||||
FileSizeRootNode(SleuthkitCase skCase) {
|
||||
super(Children.create(new FileSizeRootChildren(skCase), true), Lookups.singleton(NAME));
|
||||
FileSizeRootNode(SleuthkitCase skCase, long datasourceObjId) {
|
||||
super(Children.create(new FileSizeRootChildren(skCase, datasourceObjId), true), Lookups.singleton(NAME));
|
||||
super.setName(NAME);
|
||||
super.setDisplayName(NAME);
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-size-16.png"); //NON-NLS
|
||||
@ -161,10 +170,12 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
public static class FileSizeRootChildren extends ChildFactory<org.sleuthkit.autopsy.datamodel.FileSize.FileSizeFilter> {
|
||||
|
||||
private SleuthkitCase skCase;
|
||||
private final long datasourceObjId;
|
||||
private Observable notifier;
|
||||
|
||||
public FileSizeRootChildren(SleuthkitCase skCase) {
|
||||
public FileSizeRootChildren(SleuthkitCase skCase, long datasourceObjId) {
|
||||
this.skCase = skCase;
|
||||
this.datasourceObjId = datasourceObjId;
|
||||
notifier = new FileSizeRootChildrenObservable();
|
||||
}
|
||||
|
||||
@ -248,7 +259,7 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(FileSizeFilter key) {
|
||||
return new FileSizeNode(skCase, key, notifier);
|
||||
return new FileSizeNode(skCase, key, notifier, datasourceObjId);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -257,12 +268,14 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
public class FileSizeNode extends DisplayableItemNode {
|
||||
|
||||
private FileSizeFilter filter;
|
||||
private final long datasourceObjId;
|
||||
|
||||
// use version with observer instead so that it updates
|
||||
@Deprecated
|
||||
FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter) {
|
||||
super(Children.create(new FileSizeChildren(filter, skCase, null), true), Lookups.singleton(filter.getDisplayName()));
|
||||
FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter, long datasourceObjId) {
|
||||
super(Children.create(new FileSizeChildren(filter, skCase, null, datasourceObjId), true), Lookups.singleton(filter.getDisplayName()));
|
||||
this.filter = filter;
|
||||
this.datasourceObjId = datasourceObjId;
|
||||
init();
|
||||
}
|
||||
|
||||
@ -272,10 +285,12 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
* @param filter
|
||||
* @param o Observable that provides updates when events are
|
||||
* fired
|
||||
* @param datasourceObjId filter by data source, if configured in user preferences
|
||||
*/
|
||||
FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter, Observable o) {
|
||||
super(Children.create(new FileSizeChildren(filter, skCase, o), true), Lookups.singleton(filter.getDisplayName()));
|
||||
FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter, Observable o, long datasourceObjId) {
|
||||
super(Children.create(new FileSizeChildren(filter, skCase, o, datasourceObjId), true), Lookups.singleton(filter.getDisplayName()));
|
||||
this.filter = filter;
|
||||
this.datasourceObjId = datasourceObjId;
|
||||
init();
|
||||
o.addObserver(new FileSizeNodeObserver());
|
||||
}
|
||||
@ -309,7 +324,7 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
private void updateDisplayName() {
|
||||
final long numVisibleChildren = FileSizeChildren.calculateItems(skCase, filter);
|
||||
final long numVisibleChildren = FileSizeChildren.calculateItems(skCase, filter, datasourceObjId);
|
||||
super.setDisplayName(filter.getDisplayName() + " (" + numVisibleChildren + ")");
|
||||
}
|
||||
|
||||
@ -349,6 +364,7 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
private final SleuthkitCase skCase;
|
||||
private final FileSizeFilter filter;
|
||||
private final Observable notifier;
|
||||
private final long datasourceObjId;
|
||||
private static final Logger logger = Logger.getLogger(FileSizeChildren.class.getName());
|
||||
|
||||
/**
|
||||
@ -358,10 +374,12 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
* @param o Observable that provides updates when new files are
|
||||
* added to case
|
||||
*/
|
||||
FileSizeChildren(FileSizeFilter filter, SleuthkitCase skCase, Observable o) {
|
||||
FileSizeChildren(FileSizeFilter filter, SleuthkitCase skCase, Observable o, long dsObjId) {
|
||||
this.skCase = skCase;
|
||||
this.filter = filter;
|
||||
this.notifier = o;
|
||||
this.datasourceObjId = dsObjId;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -395,7 +413,7 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String makeQuery(FileSizeFilter filter) {
|
||||
private static String makeQuery(FileSizeFilter filter, long filteringDSObjId) {
|
||||
String query;
|
||||
switch (filter) {
|
||||
case SIZE_50_200:
|
||||
@ -427,6 +445,11 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
query += " AND (type != " + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType() + ")"; //NON-NLS
|
||||
}
|
||||
|
||||
// filter by datasource if indicated in user preferences
|
||||
if (UserPreferences.groupItemsInTreeByDatasource()) {
|
||||
query += " AND data_source_obj_id = " + filteringDSObjId;
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
@ -434,7 +457,7 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
List<AbstractFile> ret = new ArrayList<>();
|
||||
|
||||
try {
|
||||
String query = makeQuery(filter);
|
||||
String query = makeQuery(filter, datasourceObjId);
|
||||
|
||||
ret = skCase.findAllFilesWhere(query);
|
||||
} catch (Exception e) {
|
||||
@ -449,9 +472,9 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static long calculateItems(SleuthkitCase sleuthkitCase, FileSizeFilter filter) {
|
||||
static long calculateItems(SleuthkitCase sleuthkitCase, FileSizeFilter filter, long datasourceObjId) {
|
||||
try {
|
||||
return sleuthkitCase.countFilesWhere(makeQuery(filter));
|
||||
return sleuthkitCase.countFilesWhere(makeQuery(filter, datasourceObjId));
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error getting files by size search view count", ex); //NON-NLS
|
||||
return 0;
|
||||
|
@ -72,8 +72,15 @@ public final class FileTypes implements AutopsyVisitableItem {
|
||||
|
||||
private final SleuthkitCase skCase;
|
||||
|
||||
private final long datasourceObjId;
|
||||
|
||||
FileTypes(SleuthkitCase skCase) {
|
||||
this(skCase, 0);
|
||||
}
|
||||
|
||||
FileTypes(SleuthkitCase skCase, long dsObjId) {
|
||||
this.skCase = skCase;
|
||||
this.datasourceObjId = dsObjId;
|
||||
updateShowCounts();
|
||||
}
|
||||
|
||||
@ -86,6 +93,9 @@ public final class FileTypes implements AutopsyVisitableItem {
|
||||
return skCase;
|
||||
}
|
||||
|
||||
long filteringDataSourceObjId() {
|
||||
return this.datasourceObjId;
|
||||
}
|
||||
/**
|
||||
* Check the db to determine if the nodes should show child counts.
|
||||
*/
|
||||
|
@ -69,6 +69,10 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
long filteringDataSourceObjId() {
|
||||
return typesRoot.filteringDataSourceObjId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for case and ingest invest. Updates observers when events are
|
||||
* fired. FileType and FileTypes nodes are all listening to this.
|
||||
@ -359,6 +363,9 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||
+ (UserPreferences.hideKnownFilesInViewsTree()
|
||||
? " AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")"
|
||||
: " ")
|
||||
+ (UserPreferences.groupItemsInTreeByDatasource()
|
||||
? " AND data_source_obj_id = " + filteringDataSourceObjId()
|
||||
: " ")
|
||||
+ " AND (extension IN (" + filter.getFilter().stream()
|
||||
.map(String::toLowerCase)
|
||||
.map(s -> "'"+StringUtils.substringAfter(s, ".")+"'")
|
||||
|
@ -42,6 +42,7 @@ import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import static org.sleuthkit.autopsy.core.UserPreferences.hideKnownFilesInViewsTree;
|
||||
import static org.sleuthkit.autopsy.core.UserPreferences.hideSlackFilesInViewsTree;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
@ -91,7 +92,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
* @return The base expression to be used in the where clause of queries for
|
||||
* files by mime type.
|
||||
*/
|
||||
static private String createBaseWhereExpr() {
|
||||
private String createBaseWhereExpr() {
|
||||
return "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")"
|
||||
+ " AND (type IN ("
|
||||
+ TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal() + ","
|
||||
@ -100,6 +101,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
+ TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()
|
||||
+ (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()))
|
||||
+ "))"
|
||||
+ ( UserPreferences.groupItemsInTreeByDatasource() ? " AND data_source_obj_id = " + this.filteringDataSourceObjId() : " ")
|
||||
+ (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : "");
|
||||
}
|
||||
|
||||
@ -188,6 +190,10 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
long filteringDataSourceObjId() {
|
||||
return typesRoot.filteringDataSourceObjId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to check if the node in question is a ByMimeTypeNode which is
|
||||
* empty.
|
||||
|
@ -42,6 +42,7 @@ import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||
@ -63,9 +64,29 @@ public class HashsetHits implements AutopsyVisitableItem {
|
||||
private static final Logger logger = Logger.getLogger(HashsetHits.class.getName());
|
||||
private SleuthkitCase skCase;
|
||||
private final HashsetResults hashsetResults;
|
||||
private final long datasourceObjId;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param skCase Case DB
|
||||
*
|
||||
*/
|
||||
public HashsetHits(SleuthkitCase skCase) {
|
||||
this(skCase, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param skCase Case DB
|
||||
* @param objId Object id of the data source
|
||||
*
|
||||
*/
|
||||
public HashsetHits(SleuthkitCase skCase, long objId) {
|
||||
this.skCase = skCase;
|
||||
this.datasourceObjId = objId;
|
||||
hashsetResults = new HashsetResults();
|
||||
}
|
||||
|
||||
@ -120,6 +141,9 @@ public class HashsetHits implements AutopsyVisitableItem {
|
||||
+ "attribute_type_id=" + setNameId //NON-NLS
|
||||
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
|
||||
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
|
||||
if (UserPreferences.groupItemsInTreeByDatasource()) {
|
||||
query += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId;
|
||||
}
|
||||
|
||||
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
|
||||
ResultSet resultSet = dbQuery.getResultSet();
|
||||
|
@ -42,6 +42,7 @@ import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||
@ -59,9 +60,28 @@ public class InterestingHits implements AutopsyVisitableItem {
|
||||
private static final Logger logger = Logger.getLogger(InterestingHits.class.getName());
|
||||
private SleuthkitCase skCase;
|
||||
private final InterestingResults interestingResults = new InterestingResults();
|
||||
private final long datasourceObjId;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param skCase Case DB
|
||||
*
|
||||
*/
|
||||
public InterestingHits(SleuthkitCase skCase) {
|
||||
this(skCase, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param skCase Case DB
|
||||
* @param objId Object id of the data source
|
||||
*
|
||||
*/
|
||||
public InterestingHits(SleuthkitCase skCase, long objId) {
|
||||
this.skCase = skCase;
|
||||
this.datasourceObjId = objId;
|
||||
interestingResults.update();
|
||||
}
|
||||
|
||||
@ -112,6 +132,9 @@ public class InterestingHits implements AutopsyVisitableItem {
|
||||
+ "attribute_type_id=" + setNameId //NON-NLS
|
||||
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
|
||||
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
|
||||
if (UserPreferences.groupItemsInTreeByDatasource()) {
|
||||
query += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId;
|
||||
}
|
||||
|
||||
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
|
||||
synchronized (interestingItemsMap) {
|
||||
|
@ -44,6 +44,7 @@ import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import static org.sleuthkit.autopsy.datamodel.Bundle.*;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
@ -73,6 +74,7 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
|
||||
private SleuthkitCase skCase;
|
||||
private final KeywordResults keywordResults;
|
||||
private final long datasourceObjId;
|
||||
|
||||
/**
|
||||
* String used in the instance MAP so that exact matches and substring can
|
||||
@ -81,6 +83,7 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
*/
|
||||
private static final String DEFAULT_INSTANCE_NAME = "DEFAULT_INSTANCE_NAME";
|
||||
|
||||
|
||||
/**
|
||||
* query attributes table for the ones that we need for the tree
|
||||
*/
|
||||
@ -101,8 +104,25 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
return (instances.size() == 1) && (instances.get(0).equals(DEFAULT_INSTANCE_NAME));
|
||||
}
|
||||
|
||||
public KeywordHits(SleuthkitCase skCase) {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param skCase Case DB
|
||||
*/
|
||||
KeywordHits(SleuthkitCase skCase) {
|
||||
this(skCase, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param skCase Case DB
|
||||
* @param objId Object id of the data source
|
||||
*
|
||||
*/
|
||||
public KeywordHits(SleuthkitCase skCase, long objId) {
|
||||
this.skCase = skCase;
|
||||
this.datasourceObjId = objId;
|
||||
keywordResults = new KeywordResults();
|
||||
}
|
||||
|
||||
@ -300,7 +320,12 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
return;
|
||||
}
|
||||
|
||||
try (CaseDbQuery dbQuery = skCase.executeQuery(KEYWORD_HIT_ATTRIBUTES_QUERY)) {
|
||||
String queryStr = KEYWORD_HIT_ATTRIBUTES_QUERY;
|
||||
if (UserPreferences.groupItemsInTreeByDatasource()) {
|
||||
queryStr += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId;
|
||||
}
|
||||
|
||||
try (CaseDbQuery dbQuery = skCase.executeQuery(queryStr)) {
|
||||
ResultSet resultSet = dbQuery.getResultSet();
|
||||
while (resultSet.next()) {
|
||||
long artifactId = resultSet.getLong("artifact_id"); //NON-NLS
|
||||
|
@ -26,9 +26,15 @@ import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
public class Results implements AutopsyVisitableItem {
|
||||
|
||||
private SleuthkitCase skCase;
|
||||
private final long datasourceObjId;
|
||||
|
||||
public Results(SleuthkitCase skCase) {
|
||||
this(skCase, 0);
|
||||
}
|
||||
|
||||
public Results(SleuthkitCase skCase, long dsObjId) {
|
||||
this.skCase = skCase;
|
||||
this.datasourceObjId = dsObjId;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -39,4 +45,8 @@ public class Results implements AutopsyVisitableItem {
|
||||
public SleuthkitCase getSleuthkitCase() {
|
||||
return skCase;
|
||||
}
|
||||
|
||||
long filteringDataSourceObjId() {
|
||||
return datasourceObjId;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -33,17 +33,22 @@ public class ResultsNode extends DisplayableItemNode {
|
||||
@NbBundle.Messages("ResultsNode.name.text=Results")
|
||||
public static final String NAME = Bundle.ResultsNode_name_text();
|
||||
|
||||
|
||||
|
||||
public ResultsNode(SleuthkitCase sleuthkitCase) {
|
||||
super(new RootContentChildren(Arrays.asList(
|
||||
new ExtractedContent(sleuthkitCase),
|
||||
new KeywordHits(sleuthkitCase),
|
||||
new HashsetHits(sleuthkitCase),
|
||||
new EmailExtracted(sleuthkitCase),
|
||||
new InterestingHits(sleuthkitCase),
|
||||
new Accounts(sleuthkitCase)
|
||||
)), Lookups.singleton(NAME));
|
||||
this(sleuthkitCase, 0);
|
||||
}
|
||||
|
||||
public ResultsNode(SleuthkitCase sleuthkitCase, long dsObjId) {
|
||||
super(
|
||||
|
||||
new RootContentChildren(Arrays.asList(
|
||||
new ExtractedContent(sleuthkitCase, dsObjId ),
|
||||
new KeywordHits(sleuthkitCase, dsObjId),
|
||||
new HashsetHits(sleuthkitCase, dsObjId),
|
||||
new EmailExtracted(sleuthkitCase, dsObjId),
|
||||
new InterestingHits(sleuthkitCase, dsObjId ),
|
||||
new Accounts(sleuthkitCase, dsObjId) )
|
||||
),
|
||||
Lookups.singleton(NAME));
|
||||
setName(NAME);
|
||||
setDisplayName(NAME);
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/results.png"); //NON-NLS
|
||||
|
@ -36,6 +36,7 @@ import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||
@ -57,6 +58,20 @@ public class Tags implements AutopsyVisitableItem {
|
||||
private final String DISPLAY_NAME = NbBundle.getMessage(RootNode.class, "TagsNode.displayName.text");
|
||||
private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS
|
||||
|
||||
private final long datasourceObjId;
|
||||
|
||||
Tags() {
|
||||
this(0);
|
||||
}
|
||||
|
||||
Tags(long dsObjId) {
|
||||
this.datasourceObjId = dsObjId;
|
||||
}
|
||||
|
||||
long filteringDataSourceObjId() {
|
||||
return this.datasourceObjId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(AutopsyItemVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
@ -83,11 +98,13 @@ public class Tags implements AutopsyVisitableItem {
|
||||
*/
|
||||
public class RootNode extends DisplayableItemNode {
|
||||
|
||||
public RootNode() {
|
||||
super(Children.create(new TagNameNodeFactory(), true), Lookups.singleton(DISPLAY_NAME));
|
||||
|
||||
public RootNode(long objId) {
|
||||
super(Children.create(new TagNameNodeFactory(objId), true), Lookups.singleton(DISPLAY_NAME));
|
||||
super.setName(DISPLAY_NAME);
|
||||
super.setDisplayName(DISPLAY_NAME);
|
||||
this.setIconBaseWithExtension(ICON_PATH);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -121,6 +138,8 @@ public class Tags implements AutopsyVisitableItem {
|
||||
|
||||
private class TagNameNodeFactory extends ChildFactory.Detachable<TagName> implements Observer {
|
||||
|
||||
private final long datasourceObjId;
|
||||
|
||||
private final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED,
|
||||
Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED,
|
||||
Case.Events.CONTENT_TAG_ADDED,
|
||||
@ -176,6 +195,15 @@ public class Tags implements AutopsyVisitableItem {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param objId data source object id
|
||||
*/
|
||||
TagNameNodeFactory(long objId) {
|
||||
this.datasourceObjId = objId;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addNotify() {
|
||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||
@ -196,7 +224,11 @@ public class Tags implements AutopsyVisitableItem {
|
||||
@Override
|
||||
protected boolean createKeys(List<TagName> keys) {
|
||||
try {
|
||||
List<TagName> tagNamesInUse = Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse();
|
||||
|
||||
List<TagName> tagNamesInUse = UserPreferences.groupItemsInTreeByDatasource() ?
|
||||
Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(datasourceObjId) :
|
||||
Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse()
|
||||
;
|
||||
Collections.sort(tagNamesInUse);
|
||||
keys.addAll(tagNamesInUse);
|
||||
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||
@ -244,8 +276,15 @@ public class Tags implements AutopsyVisitableItem {
|
||||
long tagsCount = 0;
|
||||
try {
|
||||
TagsManager tm = Case.getCurrentCaseThrows().getServices().getTagsManager();
|
||||
if (UserPreferences.groupItemsInTreeByDatasource()) {
|
||||
tagsCount = tm.getContentTagsCountByTagName(tagName, datasourceObjId);
|
||||
tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName, datasourceObjId);
|
||||
}
|
||||
else {
|
||||
tagsCount = tm.getContentTagsCountByTagName(tagName);
|
||||
tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName);
|
||||
}
|
||||
|
||||
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||
Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "Failed to get tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS
|
||||
}
|
||||
@ -348,7 +387,9 @@ public class Tags implements AutopsyVisitableItem {
|
||||
private void updateDisplayName() {
|
||||
long tagsCount = 0;
|
||||
try {
|
||||
tagsCount = Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName);
|
||||
tagsCount = UserPreferences.groupItemsInTreeByDatasource() ?
|
||||
Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName, datasourceObjId) :
|
||||
Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName);
|
||||
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||
Logger.getLogger(ContentTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get content tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS
|
||||
}
|
||||
@ -403,7 +444,11 @@ public class Tags implements AutopsyVisitableItem {
|
||||
protected boolean createKeys(List<ContentTag> keys) {
|
||||
// Use the content tags bearing the specified tag name as the keys.
|
||||
try {
|
||||
keys.addAll(Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName));
|
||||
List<ContentTag> contentTags = UserPreferences.groupItemsInTreeByDatasource() ?
|
||||
Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName, datasourceObjId) :
|
||||
Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName);
|
||||
|
||||
keys.addAll(contentTags);
|
||||
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||
Logger.getLogger(ContentTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS
|
||||
}
|
||||
@ -447,7 +492,9 @@ public class Tags implements AutopsyVisitableItem {
|
||||
private void updateDisplayName() {
|
||||
long tagsCount = 0;
|
||||
try {
|
||||
tagsCount = Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName);
|
||||
tagsCount = UserPreferences.groupItemsInTreeByDatasource() ?
|
||||
Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName, datasourceObjId) :
|
||||
Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName);
|
||||
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||
Logger.getLogger(BlackboardArtifactTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get blackboard artifact tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS
|
||||
}
|
||||
@ -502,7 +549,10 @@ public class Tags implements AutopsyVisitableItem {
|
||||
protected boolean createKeys(List<BlackboardArtifactTag> keys) {
|
||||
try {
|
||||
// Use the blackboard artifact tags bearing the specified tag name as the keys.
|
||||
keys.addAll(Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName));
|
||||
List<BlackboardArtifactTag> artifactTags = UserPreferences.groupItemsInTreeByDatasource() ?
|
||||
Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName, datasourceObjId) :
|
||||
Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName);
|
||||
keys.addAll(artifactTags);
|
||||
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||
Logger.getLogger(BlackboardArtifactTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS
|
||||
}
|
||||
|
@ -26,9 +26,19 @@ import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
public class Views implements AutopsyVisitableItem {
|
||||
|
||||
private SleuthkitCase skCase;
|
||||
private final long datasourceObjId;
|
||||
|
||||
public Views(SleuthkitCase skCase) {
|
||||
this(skCase, 0);
|
||||
}
|
||||
|
||||
public Views(SleuthkitCase skCase, long dsObjId) {
|
||||
this.skCase = skCase;
|
||||
this.datasourceObjId = dsObjId;
|
||||
}
|
||||
|
||||
long filteringDataSourceObjId() {
|
||||
return this.datasourceObjId;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2014 Basis Technology Corp.
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -34,19 +34,28 @@ public class ViewsNode extends DisplayableItemNode {
|
||||
public static final String NAME = NbBundle.getMessage(ViewsNode.class, "ViewsNode.name.text");
|
||||
|
||||
public ViewsNode(SleuthkitCase sleuthkitCase) {
|
||||
super(new RootContentChildren(Arrays.asList(
|
||||
new FileTypes(sleuthkitCase),
|
||||
this(sleuthkitCase, 0);
|
||||
}
|
||||
|
||||
public ViewsNode(SleuthkitCase sleuthkitCase, long dsObjId) {
|
||||
|
||||
super(
|
||||
new RootContentChildren(Arrays.asList(
|
||||
new FileTypes(sleuthkitCase, dsObjId),
|
||||
// June '15: Recent Files was removed because it was not useful w/out filtering
|
||||
// add it back in if we can filter the results to a more managable size.
|
||||
// new RecentFiles(sleuthkitCase),
|
||||
new DeletedContent(sleuthkitCase),
|
||||
new FileSize(sleuthkitCase))),
|
||||
Lookups.singleton(NAME));
|
||||
new DeletedContent(sleuthkitCase, dsObjId),
|
||||
new FileSize(sleuthkitCase, dsObjId))
|
||||
),
|
||||
Lookups.singleton(NAME)
|
||||
);
|
||||
setName(NAME);
|
||||
setDisplayName(NAME);
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/views.png"); //NON-NLS
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
|
@ -58,6 +58,7 @@ import org.openide.util.Utilities;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.AutopsyItemVisitor;
|
||||
@ -94,6 +95,8 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
final public static String NAME = Bundle.AccountsRootNode_name();
|
||||
|
||||
private SleuthkitCase skCase;
|
||||
private final long datasourceObjId;
|
||||
|
||||
private final EventBus reviewStatusBus = new EventBus("ReviewStatusBus");
|
||||
|
||||
/* Should rejected accounts be shown in the accounts section of the tree. */
|
||||
@ -108,12 +111,24 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
* @param skCase The SleuthkitCase object to use for db queries.
|
||||
*/
|
||||
public Accounts(SleuthkitCase skCase) {
|
||||
this(skCase, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param skCase The SleuthkitCase object to use for db queries.
|
||||
* @param objId Object id of the data source
|
||||
*/
|
||||
public Accounts(SleuthkitCase skCase, long objId) {
|
||||
this.skCase = skCase;
|
||||
this.datasourceObjId = objId;
|
||||
|
||||
this.rejectActionInstance = new RejectAccounts();
|
||||
this.approveActionInstance = new ApproveAccounts();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T accept(AutopsyItemVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
@ -130,6 +145,18 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
return showRejected ? " " : " AND blackboard_artifacts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID() + " "; //NON-NLS
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the clause to filter artifacts by data source.
|
||||
*
|
||||
* @return A clause that will or will not filter artifacts by datasource
|
||||
* based on the UserPreferences groupItemsInTreeByDatasource setting
|
||||
*/
|
||||
private String getFilterByDataSourceClause() {
|
||||
return (UserPreferences.groupItemsInTreeByDatasource()) ?
|
||||
" AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId + " "
|
||||
: " ";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a new Action that when invoked toggles showing rejected artifacts on
|
||||
* or off.
|
||||
@ -291,10 +318,14 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<String> list) {
|
||||
try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery(
|
||||
String accountTypesInUseQuery =
|
||||
"SELECT DISTINCT blackboard_attributes.value_text as account_type "
|
||||
+ " FROM blackboard_attributes "
|
||||
+ " WHERE blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID());
|
||||
+ " FROM blackboard_artifacts " //NON-NLS
|
||||
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
|
||||
+ " WHERE blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()
|
||||
+ getFilterByDataSourceClause();
|
||||
|
||||
try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery(accountTypesInUseQuery );
|
||||
ResultSet resultSet = executeQuery.getResultSet()) {
|
||||
while (resultSet.next()) {
|
||||
String accountType = resultSet.getString("account_type");
|
||||
@ -429,6 +460,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
|
||||
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
|
||||
+ " AND blackboard_attributes.value_text = '" + accountType.getTypeName() + "'" //NON-NLS
|
||||
+ getFilterByDataSourceClause()
|
||||
+ getRejectedArtifactFilterClause(); //NON-NLS
|
||||
try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query);
|
||||
ResultSet rs = results.getResultSet();) {
|
||||
@ -739,6 +771,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
+ " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
|
||||
+ " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.getTypeName() + "'" //NON-NLS
|
||||
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
|
||||
+ getFilterByDataSourceClause()
|
||||
+ getRejectedArtifactFilterClause()
|
||||
+ " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS
|
||||
+ " ORDER BY hits DESC "; //NON-NLS
|
||||
@ -807,6 +840,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
+ " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
|
||||
+ " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.getTypeName() + "'" //NON-NLS
|
||||
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
|
||||
+ getFilterByDataSourceClause()
|
||||
+ getRejectedArtifactFilterClause()
|
||||
+ " GROUP BY blackboard_artifacts.obj_id, solr_attribute.value_text ) AS foo";
|
||||
try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query);
|
||||
@ -943,6 +977,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS
|
||||
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
|
||||
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS
|
||||
+ getFilterByDataSourceClause()
|
||||
+ getRejectedArtifactFilterClause()
|
||||
+ " GROUP BY BIN " //NON-NLS
|
||||
+ " ORDER BY BIN "; //NON-NLS
|
||||
@ -1009,6 +1044,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS
|
||||
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
|
||||
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS
|
||||
+ getFilterByDataSourceClause()
|
||||
+ getRejectedArtifactFilterClause(); //NON-NLS
|
||||
try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query);
|
||||
ResultSet resultSet = results.getResultSet();) {
|
||||
@ -1304,6 +1340,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
|
||||
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS
|
||||
+ " AND blackboard_attributes.value_text >= '" + bin.getBINStart() + "' AND blackboard_attributes.value_text < '" + (bin.getBINEnd() + 1) + "'" //NON-NLS
|
||||
+ getFilterByDataSourceClause()
|
||||
+ getRejectedArtifactFilterClause()
|
||||
+ " ORDER BY blackboard_attributes.value_text"; //NON-NLS
|
||||
try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query);
|
||||
@ -1375,6 +1412,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
|
||||
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS
|
||||
+ " AND blackboard_attributes.value_text >= '" + bin.getBINStart() + "' AND blackboard_attributes.value_text < '" + (bin.getBINEnd() + 1) + "'" //NON-NLS
|
||||
+ getFilterByDataSourceClause()
|
||||
+ getRejectedArtifactFilterClause();
|
||||
try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query);
|
||||
ResultSet resultSet = results.getResultSet();) {
|
||||
|
@ -119,3 +119,4 @@ AddExternalViewerRulePanel.browseButton.text=Browse
|
||||
AddExternalViewerRulePanel.exePathTextField.text=
|
||||
AddExternalViewerRulePanel.exePathLabel.text=Path of the program to use for files with this type or extension
|
||||
AddExternalViewerRulePanel.extRadioButton.text=Extension
|
||||
DirectoryTreeTopComponent.groupByDatasourceCheckBox.text=Group by Data Source
|
||||
|
@ -16,14 +16,17 @@
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="treeView" alignment="0" pref="262" max="32767" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
|
||||
<Component id="treeView" alignment="0" max="32767" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="backButton" min="-2" pref="23" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
<Component id="forwardButton" min="-2" pref="23" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="46" max="32767" attributes="0"/>
|
||||
<EmptySpace pref="65" max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="showRejectedCheckBox" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="groupByDatasourceCheckBox" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
@ -31,14 +34,23 @@
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
|
||||
<Component id="showRejectedCheckBox" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="groupByDatasourceCheckBox" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Component id="forwardButton" min="-2" pref="26" max="-2" attributes="1"/>
|
||||
<Component id="backButton" min="-2" pref="26" max="-2" attributes="1"/>
|
||||
<Component id="showRejectedCheckBox" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
||||
<Component id="treeView" pref="854" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="treeView" pref="838" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
@ -130,5 +142,15 @@
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="groupByDatasourceCheckBox">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="DirectoryTreeTopComponent.groupByDatasourceCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="groupByDatasourceCheckBoxActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
|
@ -30,6 +30,7 @@ import java.util.EnumSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.prefs.PreferenceChangeEvent;
|
||||
@ -64,8 +65,6 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.ArtifactNodeSelectionInfo;
|
||||
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
||||
import org.sleuthkit.autopsy.datamodel.CreditCards;
|
||||
import org.sleuthkit.autopsy.datamodel.DataSources;
|
||||
import org.sleuthkit.autopsy.datamodel.DataSourcesNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||
import org.sleuthkit.autopsy.datamodel.EmailExtracted;
|
||||
import org.sleuthkit.autopsy.datamodel.EmptyNode;
|
||||
@ -73,12 +72,8 @@ import org.sleuthkit.autopsy.datamodel.ExtractedContent;
|
||||
import org.sleuthkit.autopsy.datamodel.FileTypesByMimeType;
|
||||
import org.sleuthkit.autopsy.datamodel.InterestingHits;
|
||||
import org.sleuthkit.autopsy.datamodel.KeywordHits;
|
||||
import org.sleuthkit.autopsy.datamodel.Reports;
|
||||
import org.sleuthkit.autopsy.datamodel.Results;
|
||||
import org.sleuthkit.autopsy.datamodel.ResultsNode;
|
||||
import org.sleuthkit.autopsy.datamodel.RootContentChildren;
|
||||
import org.sleuthkit.autopsy.datamodel.Tags;
|
||||
import org.sleuthkit.autopsy.datamodel.Views;
|
||||
import org.sleuthkit.autopsy.datamodel.AutopsyTreeChildrenFactory;
|
||||
import org.sleuthkit.autopsy.datamodel.ViewsNode;
|
||||
import org.sleuthkit.autopsy.datamodel.accounts.Accounts;
|
||||
import org.sleuthkit.autopsy.datamodel.accounts.BINRange;
|
||||
@ -107,7 +102,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
private final LinkedList<String[]> forwardList;
|
||||
private static final String PREFERRED_ID = "DirectoryTreeTopComponent"; //NON-NLS
|
||||
private static final Logger LOGGER = Logger.getLogger(DirectoryTreeTopComponent.class.getName());
|
||||
private RootContentChildren contentChildren;
|
||||
private AutopsyTreeChildrenFactory autopsyTreeChildrenFactory;
|
||||
private Children autopsyTreeChildren;
|
||||
|
||||
/**
|
||||
* the constructor
|
||||
@ -130,6 +126,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
this.forwardList = new LinkedList<>();
|
||||
backButton.setEnabled(false);
|
||||
forwardButton.setEnabled(false);
|
||||
|
||||
groupByDatasourceCheckBox.setSelected(UserPreferences.groupItemsInTreeByDatasource());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -142,6 +140,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
switch (evt.getKey()) {
|
||||
case UserPreferences.HIDE_KNOWN_FILES_IN_DATA_SRCS_TREE:
|
||||
case UserPreferences.HIDE_SLACK_FILES_IN_DATA_SRCS_TREE:
|
||||
case UserPreferences.GROUP_ITEMS_IN_TREE_BY_DATASOURCE:
|
||||
refreshContentTreeSafe();
|
||||
break;
|
||||
case UserPreferences.HIDE_KNOWN_FILES_IN_VIEWS_TREE:
|
||||
@ -182,6 +181,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
backButton = new javax.swing.JButton();
|
||||
forwardButton = new javax.swing.JButton();
|
||||
showRejectedCheckBox = new javax.swing.JCheckBox();
|
||||
groupByDatasourceCheckBox = new javax.swing.JCheckBox();
|
||||
|
||||
treeView.setBorder(null);
|
||||
|
||||
@ -219,30 +219,45 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(showRejectedCheckBox, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.showRejectedCheckBox.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(groupByDatasourceCheckBox, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.groupByDatasourceCheckBox.text")); // NOI18N
|
||||
groupByDatasourceCheckBox.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
groupByDatasourceCheckBoxActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(treeView, javax.swing.GroupLayout.DEFAULT_SIZE, 262, Short.MAX_VALUE)
|
||||
.addComponent(treeView)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(5, 5, 5)
|
||||
.addContainerGap()
|
||||
.addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 46, Short.MAX_VALUE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 65, Short.MAX_VALUE)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(showRejectedCheckBox)
|
||||
.addComponent(groupByDatasourceCheckBox))
|
||||
.addContainerGap())
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(5, 5, 5)
|
||||
.addComponent(showRejectedCheckBox)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(groupByDatasourceCheckBox))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(showRejectedCheckBox))
|
||||
.addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE))))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(treeView, javax.swing.GroupLayout.DEFAULT_SIZE, 854, Short.MAX_VALUE)
|
||||
.addComponent(treeView, javax.swing.GroupLayout.DEFAULT_SIZE, 838, Short.MAX_VALUE)
|
||||
.addGap(0, 0, 0))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
@ -296,9 +311,14 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
this.setCursor(null);
|
||||
}//GEN-LAST:event_forwardButtonActionPerformed
|
||||
|
||||
private void groupByDatasourceCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_groupByDatasourceCheckBoxActionPerformed
|
||||
UserPreferences.setGroupItemsInTreeByDatasource(this.groupByDatasourceCheckBox.isSelected());
|
||||
}//GEN-LAST:event_groupByDatasourceCheckBoxActionPerformed
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton backButton;
|
||||
private javax.swing.JButton forwardButton;
|
||||
private javax.swing.JCheckBox groupByDatasourceCheckBox;
|
||||
private javax.swing.JCheckBox showRejectedCheckBox;
|
||||
private javax.swing.JScrollPane treeView;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
@ -376,13 +396,10 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
} else {
|
||||
// if there's at least one image, load the image and open the top component
|
||||
final SleuthkitCase tskCase = currentCase.getSleuthkitCase();
|
||||
contentChildren = new RootContentChildren(Arrays.asList(
|
||||
new DataSources(),
|
||||
new Views(tskCase),
|
||||
new Results(tskCase),
|
||||
new Tags(),
|
||||
new Reports()));
|
||||
Node root = new AbstractNode(contentChildren) {
|
||||
|
||||
autopsyTreeChildrenFactory = new AutopsyTreeChildrenFactory(tskCase);
|
||||
autopsyTreeChildren = Children.create(autopsyTreeChildrenFactory, true);
|
||||
Node root = new AbstractNode(autopsyTreeChildren) {
|
||||
//JIRA-2807: What is the point of these overrides?
|
||||
/**
|
||||
* to override the right click action in the white blank space
|
||||
@ -422,17 +439,23 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
TreeView tree = getTree();
|
||||
|
||||
Node results = rootChildren.findChild(ResultsNode.NAME);
|
||||
if (!Objects.isNull(results)) {
|
||||
tree.expandNode(results);
|
||||
Children resultsChildren = results.getChildren();
|
||||
Arrays.stream(resultsChildren.getNodes()).forEach(tree::expandNode);
|
||||
|
||||
Accounts accounts = resultsChildren.findChild(Accounts.NAME).getLookup().lookup(Accounts.class);
|
||||
if (!Objects.isNull(accounts)) {
|
||||
showRejectedCheckBox.setAction(accounts.newToggleShowRejectedAction());
|
||||
showRejectedCheckBox.setSelected(false);
|
||||
}
|
||||
}
|
||||
|
||||
Node views = rootChildren.findChild(ViewsNode.NAME);
|
||||
if (!Objects.isNull(views)) {
|
||||
Arrays.stream(views.getChildren().getNodes()).forEach(tree::expandNode);
|
||||
tree.collapseNode(views);
|
||||
}
|
||||
/*
|
||||
* JIRA-2806: What is this supposed to do? Right now it selects
|
||||
* the data sources node, but the comment seems to indicate
|
||||
@ -464,7 +487,10 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
// of changing the selected node fires a handler that tries to make
|
||||
// dataResult active)
|
||||
try {
|
||||
em.setSelectedNodes(get());
|
||||
Node[] selections = get();
|
||||
if (selections != null && selections.length > 0){
|
||||
em.setSelectedNodes(selections);
|
||||
}
|
||||
} catch (PropertyVetoException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error setting default selected node.", ex); //NON-NLS
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
@ -486,7 +512,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
@Override
|
||||
public void componentClosed() {
|
||||
//@@@ push the selection node to null?
|
||||
contentChildren = null;
|
||||
autopsyTreeChildren = null;
|
||||
}
|
||||
|
||||
void writeProperties(java.util.Properties p) {
|
||||
@ -729,7 +755,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
*/
|
||||
String[] currentLast = backList.peekLast();
|
||||
String lastNodeName = null;
|
||||
if (currentLast != null) {
|
||||
if (currentLast != null && currentLast.length > 0) {
|
||||
lastNodeName = currentLast[currentLast.length - 1];
|
||||
}
|
||||
|
||||
@ -773,27 +799,56 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
* Refresh the content node part of the dir tree safely in the EDT thread
|
||||
*/
|
||||
public void refreshContentTreeSafe() {
|
||||
SwingUtilities.invokeLater(this::refreshDataSourceTree);
|
||||
SwingUtilities.invokeLater(this::rebuildTree);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes changed content nodes
|
||||
* Rebuilds the directory tree
|
||||
*/
|
||||
private void refreshDataSourceTree() {
|
||||
Node selectedNode = getSelectedNode();
|
||||
final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
|
||||
Children rootChildren = em.getRootContext().getChildren();
|
||||
Node dataSourcesFilterNode = rootChildren.findChild(DataSourcesNode.NAME);
|
||||
if (dataSourcesFilterNode == null) {
|
||||
LOGGER.log(Level.SEVERE, "Cannot find data sources filter node, won't refresh the content tree"); //NON-NLS
|
||||
return;
|
||||
}
|
||||
Node dataSourcesNode = ((DirectoryTreeFilterNode) dataSourcesFilterNode).getOriginal();
|
||||
DataSourcesNode.DataSourcesNodeChildren contentRootChildren = (DataSourcesNode.DataSourcesNodeChildren) dataSourcesNode.getChildren();
|
||||
contentRootChildren.refreshContentKeys();
|
||||
setSelectedNode(selectedPath, DataSourcesNode.NAME);
|
||||
private void rebuildTree() {
|
||||
|
||||
// refresh all children of the root.
|
||||
autopsyTreeChildrenFactory.refreshChildren();
|
||||
|
||||
// Select the first node and reset the selection history
|
||||
// This should happen on the EDT once the tree has been rebuilt.
|
||||
// hence the SwingWorker that does this in the done() method
|
||||
new SwingWorker<Void, Void>() {
|
||||
|
||||
@Override
|
||||
protected Void doInBackground() throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
super.done();
|
||||
try {
|
||||
get();
|
||||
selectFirstChildNode();
|
||||
resetHistory();
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error selecting tree node.", ex); //NON-NLS
|
||||
} //NON-NLS
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the first node in the tree.
|
||||
*
|
||||
*/
|
||||
private void selectFirstChildNode () {
|
||||
Children rootChildren = em.getRootContext().getChildren();
|
||||
|
||||
if (rootChildren.getNodesCount() > 0) {
|
||||
Node firstNode = rootChildren.getNodeAt(0);
|
||||
if (firstNode != null) {
|
||||
final String[] selectedPath = NodeOp.createPath(firstNode, em.getRootContext());
|
||||
setSelectedNode(selectedPath, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Set the selected node using a path to a previously selected node.
|
||||
*
|
||||
|
@ -24,6 +24,7 @@ import java.beans.PropertyVetoException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import javax.swing.AbstractAction;
|
||||
@ -33,6 +34,8 @@ import org.openide.explorer.view.TreeView;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode;
|
||||
@ -44,9 +47,12 @@ import org.sleuthkit.autopsy.datamodel.RootContentChildren;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.ContentVisitor;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.FileSystem;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
import org.sleuthkit.datamodel.TskDataException;
|
||||
import org.sleuthkit.datamodel.VolumeSystem;
|
||||
|
||||
/**
|
||||
@ -122,7 +128,9 @@ public class ViewContextAction extends AbstractAction {
|
||||
@Override
|
||||
@Messages({
|
||||
"ViewContextAction.errorMessage.cannotFindDirectory=Failed to locate directory.",
|
||||
"ViewContextAction.errorMessage.cannotSelectDirectory=Failed to select directory in tree.",})
|
||||
"ViewContextAction.errorMessage.cannotSelectDirectory=Failed to select directory in tree.",
|
||||
"ViewContextAction.errorMessage.cannotFindNode=Failed to locate data source node in tree."
|
||||
})
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
EventQueue.invokeLater(() -> {
|
||||
/*
|
||||
@ -130,7 +138,40 @@ public class ViewContextAction extends AbstractAction {
|
||||
*/
|
||||
DirectoryTreeTopComponent treeViewTopComponent = DirectoryTreeTopComponent.findInstance();
|
||||
ExplorerManager treeViewExplorerMgr = treeViewTopComponent.getExplorerManager();
|
||||
Node parentTreeViewNode = treeViewExplorerMgr.getRootContext().getChildren().findChild(DataSourcesNode.NAME);
|
||||
|
||||
Node parentTreeViewNode;
|
||||
if (UserPreferences.groupItemsInTreeByDatasource()) { // 'Group by Data Source' view
|
||||
|
||||
SleuthkitCase skCase;
|
||||
String dsname;
|
||||
try {
|
||||
// get the objid/name of the datasource of the selected content.
|
||||
skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
|
||||
long contentDSObjid = content.getDataSource().getId();
|
||||
DataSource datasource = skCase.getDataSource(contentDSObjid);
|
||||
dsname = datasource.getName();
|
||||
|
||||
Children rootChildren = treeViewExplorerMgr.getRootContext().getChildren();
|
||||
Node datasourceGroupingNode = rootChildren.findChild(dsname);
|
||||
if (! Objects.isNull(datasourceGroupingNode) ) {
|
||||
Children dsChildren = datasourceGroupingNode.getChildren();
|
||||
parentTreeViewNode = dsChildren.findChild(DataSourcesNode.NAME);
|
||||
}
|
||||
else {
|
||||
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindNode());
|
||||
logger.log(Level.SEVERE, "Failed to locate data source node in tree."); //NON-NLS
|
||||
return;
|
||||
}
|
||||
} catch (NoCurrentCaseException| TskDataException | TskCoreException ex) {
|
||||
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindNode());
|
||||
logger.log(Level.SEVERE, "Failed to locate data source node in tree.", ex); //NON-NLS
|
||||
return;
|
||||
}
|
||||
} else { // Classic view
|
||||
// Start the search at the DataSourcesNode
|
||||
parentTreeViewNode = treeViewExplorerMgr.getRootContext().getChildren().findChild(DataSourcesNode.NAME);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the parent content for the content to be selected in the
|
||||
* results view. If the parent content is null, then the specified
|
||||
|
Loading…
x
Reference in New Issue
Block a user