diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java index db85e382f3..67cfda93df 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java @@ -22,6 +22,7 @@ import org.openide.nodes.AbstractNode; import org.openide.nodes.Children.Keys; import org.openide.nodes.Node; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesNode; import org.sleuthkit.autopsy.datamodel.accounts.FileTypeExtensionFilters; import org.sleuthkit.autopsy.datamodel.accounts.RecentFiles; import org.sleuthkit.autopsy.datamodel.accounts.Accounts; @@ -131,7 +132,7 @@ abstract class AbstractContentChildren extends Keys { @Override public AbstractNode visit(FileTypeExtensionFilters sf) { - return new FileTypesNode(sf.getSleuthkitCase(), null); + return new FileTypesByExtNode(sf.getSleuthkitCase(), null); } @Override @@ -191,7 +192,7 @@ abstract class AbstractContentChildren extends Keys { @Override public AbstractNode visit(FileTypes ft) { - return new FileTypesNew(ft.getSleuthkitCase()); + return new FileTypesNode(ft.getSleuthkitCase()); } @Override @@ -210,5 +211,10 @@ abstract class AbstractContentChildren extends Keys { NbBundle.getMessage(this.getClass(), "AbstractContentChildren.createAutopsyNodeVisitor.exception.noNodeMsg")); } + + @Override + public AbstractNode visit(FileTypesByMimeType ftByMimeTypeItem) { + return ftByMimeTypeItem.new FileTypesByMimeTypeNode(ftByMimeTypeItem.getSleuthkitCase()); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java index e06e7c9d08..f0d2bcc253 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java @@ -71,7 +71,10 @@ public interface AutopsyItemVisitor { T visit(Accounts accountsItem); - T visit(FileTypes aThis); + T visit(FileTypes fileTypesItem); + + T visit(FileTypesByMimeType aThis); + static abstract public class Default implements AutopsyItemVisitor { @@ -101,7 +104,12 @@ public interface AutopsyItemVisitor { public T visit(FileTypeExtensionFilters.ExecutableFilter ef) { return defaultVisit(ef); } - + + @Override + public T visit(FileTypesByMimeType ftByMimeType) { + return defaultVisit(ftByMimeType); + } + @Override public T visit(DeletedContent dc) { return defaultVisit(dc); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties index 3c24e02283..590f0fa993 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties @@ -124,7 +124,7 @@ FileTypeNode.createSheet.filterType.desc=no description FileTypeNode.createSheet.fileExt.name=File Extensions FileTypeNode.createSheet.fileExt.displayName=File Extensions FileTypeNode.createSheet.fileExt.desc=no description -FileTypesNode.fname.text=File Types +FileTypesNode.fname.text=By Extension FileTypesNode.createSheet.name.name=Name FileTypesNode.createSheet.name.displayName=Name FileTypesNode.createSheet.name.desc=no description diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index 3af8d3c0f8..51b6b5ce11 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -22,6 +22,7 @@ import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.De import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode; import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootChildren.FileSizeNode; import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootNode; +import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesNode; import org.sleuthkit.autopsy.datamodel.accounts.Accounts; /** @@ -54,7 +55,7 @@ public interface DisplayableItemNodeVisitor { */ T visit(ViewsNode vn); - T visit(FileTypeNode fsfn); + T visit(FileTypeByExtNode fsfn); T visit(DeletedContentNode dcn); @@ -64,7 +65,7 @@ public interface DisplayableItemNodeVisitor { T visit(FileSizeNode fsn); - T visit(FileTypesNode sfn); + T visit(FileTypesByExtNode sfn); T visit(RecentFilesNode rfn); @@ -140,7 +141,14 @@ public interface DisplayableItemNodeVisitor { T visit(Accounts.DefaultAccountTypeNode node); - T visit(FileTypesNew fileTypes); + T visit(FileTypes.FileTypesNode fileTypes); + + T visit(FileTypesByMimeType.FileTypesByMimeTypeNode aThis); + + T visit(FileTypesByMimeType.MediaTypeNode aThis); + + T visit(FileTypesByMimeType.MediaSubTypeNode aThis); + /** * Visitor with an implementable default behavior for all types. Override @@ -195,10 +203,21 @@ public interface DisplayableItemNodeVisitor { } @Override - public T visit(FileTypeNode fsfn) { + public T visit(FileTypeByExtNode fsfn) { return defaultVisit(fsfn); } - + @Override + public T visit(FileTypesByMimeType.FileTypesByMimeTypeNode ftByMimeTypeNode) { + return defaultVisit(ftByMimeTypeNode); + } + @Override + public T visit(FileTypesByMimeType.MediaTypeNode ftByMimeTypeMediaTypeNode) { + return defaultVisit(ftByMimeTypeMediaTypeNode); + } + @Override + public T visit(FileTypesByMimeType.MediaSubTypeNode ftByMimeTypeMediaTypeNode) { + return defaultVisit(ftByMimeTypeMediaTypeNode); + } @Override public T visit(DeletedContentNode dcn) { return defaultVisit(dcn); @@ -220,7 +239,7 @@ public interface DisplayableItemNodeVisitor { } @Override - public T visit(FileTypesNode sfn) { + public T visit(FileTypesByExtNode sfn) { return defaultVisit(sfn); } @@ -260,7 +279,7 @@ public interface DisplayableItemNodeVisitor { } @Override - public T visit(FileTypesNew ft) { + public T visit(FileTypesNode ft) { return defaultVisit(ft); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeByExtNode.java similarity index 97% rename from Core/src/org/sleuthkit/autopsy/datamodel/FileTypeNode.java rename to Core/src/org/sleuthkit/autopsy/datamodel/FileTypeByExtNode.java index ce65c82194..9561c3f2ef 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeByExtNode.java @@ -48,14 +48,14 @@ import org.sleuthkit.datamodel.TskData; * Node for a specific file type / extension. Children of it will be the files * of that type. */ -public class FileTypeNode extends DisplayableItemNode { +public class FileTypeByExtNode extends DisplayableItemNode { FileTypeExtensionFilters.SearchFilterInterface filter; SleuthkitCase skCase; // deprecated in favor of the version that takes an observable to provide refresh updates @Deprecated - FileTypeNode(FileTypeExtensionFilters.SearchFilterInterface filter, SleuthkitCase skCase) { + FileTypeByExtNode(FileTypeExtensionFilters.SearchFilterInterface filter, SleuthkitCase skCase) { super(Children.create(new FileTypeChildFactory(filter, skCase), true), Lookups.singleton(filter.getDisplayName())); this.filter = filter; this.skCase = skCase; @@ -69,7 +69,7 @@ public class FileTypeNode extends DisplayableItemNode { * @param o Observable that sends updates when the child factories * should refresh */ - FileTypeNode(FileTypeExtensionFilters.SearchFilterInterface filter, SleuthkitCase skCase, Observable o) { + FileTypeByExtNode(FileTypeExtensionFilters.SearchFilterInterface filter, SleuthkitCase skCase, Observable o) { super(Children.create(new FileTypeChildFactory(filter, skCase, o), true), Lookups.singleton(filter.getDisplayName())); this.filter = filter; this.skCase = skCase; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java index f977a1e797..44b357f12f 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,6 +18,11 @@ */ package org.sleuthkit.autopsy.datamodel; +import java.util.Arrays; +import org.openide.nodes.Sheet; +import org.openide.util.NbBundle; +import org.openide.util.lookup.Lookups; +import org.sleuthkit.autopsy.datamodel.accounts.FileTypeExtensionFilters; import org.sleuthkit.datamodel.SleuthkitCase; /** @@ -27,7 +32,7 @@ public class FileTypes implements AutopsyVisitableItem { private SleuthkitCase skCase; - public FileTypes(SleuthkitCase skCase) { + FileTypes(SleuthkitCase skCase) { this.skCase = skCase; } @@ -36,7 +41,64 @@ public class FileTypes implements AutopsyVisitableItem { return v.visit(this); } - public SleuthkitCase getSleuthkitCase() { + SleuthkitCase getSleuthkitCase() { return skCase; } + + /** + * + * @author wschaefer + */ + public static class FileTypesNode extends DisplayableItemNode { + + @NbBundle.Messages("FileTypesNew.name.text=File Types") + private static final String NAME = Bundle.FileTypesNew_name_text(); + + public FileTypesNode(SleuthkitCase sleuthkitCase) { + super(new RootContentChildren(Arrays.asList( + new FileTypeExtensionFilters(sleuthkitCase), + new FileTypesByMimeType(sleuthkitCase) + )), Lookups.singleton(NAME)); + setName(NAME); + setDisplayName(NAME); + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); + } + + @Override + public boolean isLeafTypeNode() { + return false; + } + + @Override + public T accept(DisplayableItemNodeVisitor v) { + return v.visit(this); + } + + @Override + @NbBundle.Messages({ + "FileTypesNew.createSheet.name.name=Name", + "FileTypesNew.createSheet.name.displayName=Name", + "FileTypesNew.createSheet.name.desc=no description"}) + protected Sheet createSheet() { + Sheet s = super.createSheet(); + Sheet.Set ss = s.get(Sheet.PROPERTIES); + if (ss == null) { + ss = Sheet.createPropertiesSet(); + s.put(ss); + } + + ss.put(new NodeProperty<>(Bundle.FileTypesNew_createSheet_name_name(), + Bundle.FileTypesNew_createSheet_name_displayName(), + Bundle.FileTypesNew_createSheet_name_desc(), + NAME + )); + return s; + } + + @Override + public String getItemType() { + return getClass().getName(); + } + + } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtNode.java similarity index 93% rename from Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java rename to Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtNode.java index daf1a31780..d9ce314ae7 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtNode.java @@ -37,9 +37,9 @@ import org.sleuthkit.datamodel.SleuthkitCase; /** * Node for root of file types view. Children are nodes for specific types. */ -public class FileTypesNode extends DisplayableItemNode { +public class FileTypesByExtNode extends DisplayableItemNode { - private static final String FNAME = NbBundle.getMessage(FileTypesNode.class, "FileTypesNode.fname.text"); + private static final String FNAME = NbBundle.getMessage(FileTypesByExtNode.class, "FileTypesNode.fname.text"); private final FileTypeExtensionFilters.RootFilter filter; /** * @@ -47,7 +47,7 @@ public class FileTypesNode extends DisplayableItemNode { * @param filter null to display root node of file type tree, pass in * something to provide a sub-node. */ - FileTypesNode(SleuthkitCase skCase, FileTypeExtensionFilters.RootFilter filter) { + FileTypesByExtNode(SleuthkitCase skCase, FileTypeExtensionFilters.RootFilter filter) { super(Children.create(new FileTypesChildren(skCase, filter, null), true), Lookups.singleton(filter == null ? FNAME : filter.getName())); this.filter = filter; init(); @@ -60,7 +60,7 @@ public class FileTypesNode extends DisplayableItemNode { * @param o Observable that was created by a higher-level node that * provides updates on events */ - private FileTypesNode(SleuthkitCase skCase, FileTypeExtensionFilters.RootFilter filter, Observable o) { + private FileTypesByExtNode(SleuthkitCase skCase, FileTypeExtensionFilters.RootFilter filter, Observable o) { super(Children.create(new FileTypesChildren(skCase, filter, o), true), Lookups.singleton(filter == null ? FNAME : filter.getName())); this.filter = filter; init(); @@ -220,11 +220,11 @@ public class FileTypesNode extends DisplayableItemNode { protected Node createNodeForKey(FileTypeExtensionFilters.SearchFilterInterface key) { // make new nodes for the sub-nodes if (key.getName().equals(FileTypeExtensionFilters.RootFilter.TSK_DOCUMENT_FILTER.getName())) { - return new FileTypesNode(skCase, FileTypeExtensionFilters.RootFilter.TSK_DOCUMENT_FILTER, notifier); + return new FileTypesByExtNode(skCase, FileTypeExtensionFilters.RootFilter.TSK_DOCUMENT_FILTER, notifier); } else if (key.getName().equals(FileTypeExtensionFilters.RootFilter.TSK_EXECUTABLE_FILTER.getName())) { - return new FileTypesNode(skCase, FileTypeExtensionFilters.RootFilter.TSK_EXECUTABLE_FILTER, notifier); + return new FileTypesByExtNode(skCase, FileTypeExtensionFilters.RootFilter.TSK_EXECUTABLE_FILTER, notifier); } else { - return new FileTypeNode(key, skCase, notifier); + return new FileTypeByExtNode(key, skCase, notifier); } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java new file mode 100644 index 0000000000..59711cf1a0 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java @@ -0,0 +1,407 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2016 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.datamodel; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Observable; +import java.util.Observer; +import java.util.logging.Level; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.ChildFactory; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.core.UserPreferences; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.ContentVisitor; +import org.sleuthkit.datamodel.DerivedFile; +import org.sleuthkit.datamodel.Directory; +import org.sleuthkit.datamodel.File; +import org.sleuthkit.datamodel.LayoutFile; +import org.sleuthkit.datamodel.LocalFile; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; + +/** + * Node for Root of the 'By Mime Type' view located in the File Types view, + * shows all files with a mime type. Will intially be empty until file type + * identification has been performed. + */ +class FileTypesByMimeType extends Observable implements AutopsyVisitableItem { + + static SleuthkitCase skCase; + static final String EMPTY_MIME_TREE_STRING = "Data not available. Run file type identification module."; + /** + * The nodes of this tree will be determined dynamically by the mimetypes + * which exist in the database. This hashmap will store them with the media + * type as the key and a list of media subtypes as the value. + */ + private final HashMap> existingMimeTypes = new HashMap<>(); + private static final Logger LOGGER = Logger.getLogger(FileTypesByMimeType.class.getName()); + + /* + * The pcl is in the class because it has the easiest mechanisms to add + * and remove itself during its life cycles. + */ + private final PropertyChangeListener pcl = new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + String eventType = evt.getPropertyName(); + if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) + || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString()) + // || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString()) + || eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) { + /** + * Checking for a current case is a stop gap measure until a + * different way of handling the closing of cases is worked out. + * Currently, remote events may be received for a case that is + * already closed. + */ + try { + Case.getCurrentCase(); + populateHashMap(); + } catch (IllegalStateException notUsed) { + /** + * Case is closed, do nothing. + */ + } + } + } + }; + + private List getMediaTypeList() { + synchronized (existingMimeTypes) { + List mediaTypes = new ArrayList<>(existingMimeTypes.keySet()); + Collections.sort(mediaTypes); + return mediaTypes; + } + } + + private void populateHashMap() { + StringBuilder allDistinctMimeTypesQuery = new StringBuilder(); + allDistinctMimeTypesQuery.append("SELECT DISTINCT mime_type from tsk_files where mime_type NOT null"); + allDistinctMimeTypesQuery.append(" AND dir_type = ").append(TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue()).append(";"); //NON-NLS + synchronized (existingMimeTypes) { + existingMimeTypes.clear(); + } + + if (skCase == null) { + + return; + } + try (SleuthkitCase.CaseDbQuery dbQuery = skCase.executeQuery(allDistinctMimeTypesQuery.toString())) { + ResultSet resultSet = dbQuery.getResultSet(); + synchronized (existingMimeTypes) { + while (resultSet.next()) { + final String mime_type = resultSet.getString("mime_type"); //NON-NLS + if (!mime_type.isEmpty()) { + String mimeType[] = mime_type.split("/"); + if (!mimeType[0].isEmpty() && !mimeType[1].isEmpty()) { + if (!existingMimeTypes.containsKey(mimeType[0])) { + existingMimeTypes.put(mimeType[0], new ArrayList<>()); + } + existingMimeTypes.get(mimeType[0]).add(mimeType[1]); + } + } + } + } + } catch (TskCoreException | SQLException ex) { + LOGGER.log(Level.WARNING, "Unable to populate File Types by MIME Type tree view from DB: ", ex); //NON-NLS + } + setChanged(); + notifyObservers(); + } + + FileTypesByMimeType(SleuthkitCase skCase) { + IngestManager.getInstance().addIngestJobEventListener(pcl); + IngestManager.getInstance().addIngestModuleEventListener(pcl); +// Case.addPropertyChangeListener(pcl); + + FileTypesByMimeType.skCase = skCase; + } + + SleuthkitCase getSleuthkitCase() { + return skCase; + } + + @Override + public T accept(AutopsyItemVisitor v) { + return v.visit(this); + } + + class FileTypesByMimeTypeNode extends DisplayableItemNode { + + @NbBundle.Messages("FileTypesByMimeType.name.text=By MIME Type") + final String NAME = Bundle.FileTypesByMimeType_name_text(); + + FileTypesByMimeTypeNode(SleuthkitCase sleuthkitCase) { + super(Children.create(new FileTypesByMimeTypeNodeChildren(skCase), true)); + setName(NAME); + setDisplayName(NAME); + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); + } + + @Override + public boolean isLeafTypeNode() { +// if (!existingMimeTypes.isEmpty()) { + return false; +// } +// else { +// return true; +// } + } + + @Override + public T accept(DisplayableItemNodeVisitor v) { + return v.visit(this); + } + + @Override + public String getItemType() { + return getClass().getName(); + } + + } + + class FileTypesByMimeTypeNodeChildren extends ChildFactory implements Observer { + + private SleuthkitCase skCase; + + /** + * + * @param skCase (or null if one needs to be created) + */ + public FileTypesByMimeTypeNodeChildren(SleuthkitCase skCase) { + super(); + addObserver(this); + this.skCase = skCase; + } + + @Override + protected boolean createKeys(List mediaTypeNodes) { +// if (!existingMimeTypes.isEmpty()) { + mediaTypeNodes.addAll(getMediaTypeList()); +// } else { +// mediaTypeNodes.add(EMPTY_MIME_TREE_STRING); +// } + return true; + } + + @Override + protected Node createNodeForKey(String key) { + return new MediaTypeNode(key); + + } + + @Override + public void update(Observable o, Object arg) { + refresh(true); + } + + } + + class MediaTypeNode extends DisplayableItemNode { + + String mediaType; + + MediaTypeNode(String name) { + super(Children.create(new MediaTypeChildren(name), true)); + setName(name); + setDisplayName(name); + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); + } + + @Override + public boolean isLeafTypeNode() { + return false; + } + + @Override + public T accept(DisplayableItemNodeVisitor v) { + return v.visit(this); + } + + @Override + public String getItemType() { + return getClass().getName(); + } + + } + + class MediaTypeChildren extends ChildFactory implements Observer { + + String mediaType; + + MediaTypeChildren(String name) { + addObserver(this); + this.mediaType = name; + } + + @Override + protected boolean createKeys(List mediaTypeNodes) { +// if (!existingMimeTypes.isEmpty() && !mediaType.equals(EMPTY_MIME_TREE_STRING)) { +// System.out.println(mediaType); +// System.out.println(existingMimeTypes.size()); + mediaTypeNodes.addAll(existingMimeTypes.get(mediaType)); + return true; +// } else { +// return false; +// } + } + + @Override + protected Node createNodeForKey(String subtype) { + String mimeType = mediaType + "/" + subtype; + return new MediaSubTypeNode(mimeType); + } + + @Override + public void update(Observable o, Object arg) { + refresh(true); + } + + } + + class MediaSubTypeNode extends DisplayableItemNode { + + private MediaSubTypeNode(String mimeType) { + super(Children.create(new MediaSubTypeNodeChildren(mimeType), true)); + init(mimeType); + } + + private void init(String mimeType) { + super.setName(mimeType); + updateDisplayName(mimeType); + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS + } + + private void updateDisplayName(String mimeType) { + final long count = MediaSubTypeNodeChildren.calculateItems(skCase, mimeType); + super.setDisplayName(mimeType.split("/")[1] + " (" + count + ")"); + } + + @Override + public boolean isLeafTypeNode() { + return true; + } + + @Override + public T accept(DisplayableItemNodeVisitor v) { + return v.visit(this); + } + + @Override + public String getItemType() { + return getClass().getName(); + } + + } + + private static class MediaSubTypeNodeChildren extends ChildFactory.Detachable { + + private final String mimeType; + + MediaSubTypeNodeChildren(String mimeType) { + super(); + this.mimeType = mimeType; + } + + /** + * Get children count without actually loading all nodes + * + * @return + */ + private static long calculateItems(SleuthkitCase sleuthkitCase, String mimeType) { + try { + return sleuthkitCase.countFilesWhere(createQuery(mimeType)); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Error getting file search view count", ex); //NON-NLS + return 0; + } + } + + @Override + protected boolean createKeys(List list) { + try { + List files = skCase.findAllFilesWhere(createQuery(mimeType)); + list.addAll(files); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS + } + return true; + } + + private static String createQuery(String mimeType) { + StringBuilder query = new StringBuilder(); + query.append("(dir_type = ").append(TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue()).append(")"); //NON-NLS + if (UserPreferences.hideKnownFilesInViewsTree()) { + query.append(" AND (known IS NULL OR known != ").append(TskData.FileKnown.KNOWN.getFileKnownValue()).append(")"); //NON-NLS + } + query.append(" AND mime_type = '").append(mimeType).append("'"); + return query.toString(); + } + + @Override + protected Node createNodeForKey(Content key) { + return key.accept(new ContentVisitor.Default() { + @Override + public FileNode visit(File f) { + return new FileNode(f, false); + } + + @Override + public DirectoryNode visit(Directory d) { + return new DirectoryNode(d); + } + + @Override + public LayoutFileNode visit(LayoutFile lf) { + return new LayoutFileNode(lf); + } + + @Override + public LocalFileNode visit(DerivedFile df) { + return new LocalFileNode(df); + } + + @Override + public LocalFileNode visit(LocalFile lf) { + return new LocalFileNode(lf); + } + + @Override + protected AbstractNode defaultVisit(Content di) { + throw new UnsupportedOperationException(NbBundle.getMessage(this.getClass(), "FileTypeChildren.exception.notSupported.msg", di.toString())); + } + }); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNew.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNew.java deleted file mode 100644 index b0273b4ae4..0000000000 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNew.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.sleuthkit.autopsy.datamodel; - -import java.util.Arrays; -import org.openide.nodes.Sheet; -import org.openide.util.NbBundle; -import org.openide.util.lookup.Lookups; -import org.sleuthkit.autopsy.datamodel.accounts.FileTypeExtensionFilters; -import org.sleuthkit.datamodel.SleuthkitCase; - -/** - * - * @author wschaefer - */ -public class FileTypesNew extends DisplayableItemNode { - - @NbBundle.Messages("FileTypesNew.name.text=File Types_New") - public static final String NAME = Bundle.FileTypesNew_name_text(); - - public FileTypesNew(SleuthkitCase sleuthkitCase) { - super(new RootContentChildren(Arrays.asList( - - new FileTypeExtensionFilters(sleuthkitCase) - )), Lookups.singleton(NAME)); - setName(NAME); - setDisplayName(NAME); - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); - } - - - @Override - public boolean isLeafTypeNode() { - return false; - } - - @Override - public T accept(DisplayableItemNodeVisitor v) { - return v.visit(this); - } - - @Override - @NbBundle.Messages({ - "FileTypesNew.createSheet.name.name=Name", - "FileTypesNew.createSheet.name.displayName=Name", - "FileTypesNew.createSheet.name.desc=no description"}) - protected Sheet createSheet() { - Sheet s = super.createSheet(); - Sheet.Set ss = s.get(Sheet.PROPERTIES); - if (ss == null) { - ss = Sheet.createPropertiesSet(); - s.put(ss); - } - - ss.put(new NodeProperty<>(Bundle.FileTypesNew_createSheet_name_name(), - Bundle.FileTypesNew_createSheet_name_displayName(), - Bundle.FileTypesNew_createSheet_name_desc(), - NAME - )); - return s; - } - -} diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index 26a14f34d3..2d3d26d5b3 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -42,7 +42,7 @@ import org.sleuthkit.autopsy.datamodel.DirectoryNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; import org.sleuthkit.autopsy.datamodel.FileNode; -import org.sleuthkit.autopsy.datamodel.FileTypesNew; +import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesNode; import org.sleuthkit.autopsy.datamodel.LayoutFileNode; import org.sleuthkit.autopsy.datamodel.LocalFileNode; import org.sleuthkit.autopsy.datamodel.Reports; @@ -234,10 +234,11 @@ public class DataResultFilterNode extends FilterNode { } @Override - public List visit(FileTypesNew fileTypes) { + public List visit(FileTypesNode fileTypes) { return defaultVisit(fileTypes); } + @Override protected List defaultVisit(DisplayableItemNode ditem) { //preserve the default node's actions @@ -331,9 +332,12 @@ public class DataResultFilterNode extends FilterNode { } @Override - public AbstractAction visit(FileTypesNew fileTypes) { + public AbstractAction visit(FileTypesNode fileTypes) { return openChild(fileTypes); } + + + /** * Tell the originating ExplorerManager to display the given * dataModelNode. diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterChildren.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterChildren.java index 728e42c426..09759c79a8 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterChildren.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterChildren.java @@ -29,7 +29,7 @@ import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; import org.sleuthkit.autopsy.datamodel.FileNode; -import org.sleuthkit.autopsy.datamodel.FileTypesNew; +import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesNode; import org.sleuthkit.autopsy.datamodel.LayoutFileNode; import org.sleuthkit.autopsy.datamodel.LocalFileNode; import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode; @@ -239,9 +239,10 @@ class DirectoryTreeFilterChildren extends FilterNode.Children { } @Override - public Boolean visit(FileTypesNew ft) { + public Boolean visit(FileTypesNode ft) { return defaultVisit(ft); } + } private static class ShowItemVisitor extends DisplayableItemNodeVisitor.Default { @@ -281,8 +282,9 @@ class DirectoryTreeFilterChildren extends FilterNode.Children { } @Override - public Boolean visit(FileTypesNew fileTypes) { + public Boolean visit(FileTypesNode fileTypes) { return defaultVisit(fileTypes); } + } }