From d8c4ea9044b8b3a15881e63e659cb1573243c916 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 1 Dec 2016 16:51:13 -0500 Subject: [PATCH] 1917 made FileTypeByExtType a inner class of FileTypesByExtType --- .../autopsy/datamodel/Bundle.properties | 12 +- .../datamodel/DisplayableItemNodeVisitor.java | 24 +- .../autopsy/datamodel/EmptyNode.java | 14 - .../autopsy/datamodel/FileTypeByExtNode.java | 277 --------- .../autopsy/datamodel/FileTypesByExtNode.java | 278 ++++++++- .../datamodel/FileTypesByMimeType.java | 583 +++++++++--------- .../DirectoryTreeTopComponent.java | 9 +- 7 files changed, 583 insertions(+), 614 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/FileTypeByExtNode.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties index 2230c23fe8..b1cf4839c8 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties @@ -118,12 +118,12 @@ FileSize.createSheet.filterType.displayName=Filter Type FileSize.createSheet.filterType.desc=no description FileSize.exception.notSupported.msg=Not supported for this type of Displayable Item\: {0} FileTypeChildren.exception.notSupported.msg=Not supported for this type of Displayable Item\: {0} -FileTypeByExtNode.createSheet.filterType.name=Filter Type -FileTypeByExtNode.createSheet.filterType.displayName=Filter Type -FileTypeByExtNode.createSheet.filterType.desc=no description -FileTypeByExtNode.createSheet.fileExt.name=File Extensions -FileTypeByExtNode.createSheet.fileExt.displayName=File Extensions -FileTypeByExtNode.createSheet.fileExt.desc=no description +FileTypesByExtNode.createSheet.filterType.name=Filter Type +FileTypesByExtNode.createSheet.filterType.displayName=Filter Type +FileTypesByExtNode.createSheet.filterType.desc=no description +FileTypesByExtNode.createSheet.fileExt.name=File Extensions +FileTypesByExtNode.createSheet.fileExt.displayName=File Extensions +FileTypesByExtNode.createSheet.fileExt.desc=no description FileTypesByExtNode.fname.text=By Extension FileTypesByExtNode.createSheet.name.name=Name FileTypesByExtNode.createSheet.name.displayName=Name diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index 978933a7e1..2c029806cd 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -49,16 +49,16 @@ public interface DisplayableItemNodeVisitor { T visit(ImageNode in); T visit(VolumeNode vn); - + T visit(SlackFileNode sfn); - + /* * Views Area */ T visit(ViewsNode vn); - T visit(FileTypeByExtNode fsfn); + T visit(FileTypesByExtNode.ByExtNode fsfn); T visit(DeletedContentNode dcn); @@ -154,8 +154,6 @@ public interface DisplayableItemNodeVisitor { T visit(EmptyNode.MessageNode emptyNode); - - /** * Visitor with an implementable default behavior for all types. Override * specific visit types to not use the default behavior. @@ -214,30 +212,30 @@ public interface DisplayableItemNodeVisitor { } @Override - public T visit(FileTypeByExtNode fsfn) { + public T visit(FileTypesByExtNode.ByExtNode fsfn) { return defaultVisit(fsfn); } - + @Override public T visit(FileTypesByMimeType.ByMimeTypeNode 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(EmptyNode.MessageNode ftByMimeTypeEmptyNode) { return defaultVisit(ftByMimeTypeEmptyNode); } - + @Override public T visit(DeletedContentNode dcn) { return defaultVisit(dcn); @@ -297,11 +295,12 @@ public interface DisplayableItemNodeVisitor { public T visit(ResultsNode rn) { return defaultVisit(rn); } - + @Override public T visit(FileTypesNode ft) { return defaultVisit(ft); } + @Override public T visit(DataSourcesNode in) { return defaultVisit(in); @@ -426,6 +425,7 @@ public interface DisplayableItemNodeVisitor { public T visit(Accounts.BINNode node) { return defaultVisit(node); } + @Override public T visit(Accounts.DefaultAccountTypeNode node) { return defaultVisit(node); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmptyNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmptyNode.java index a8eaf76cda..39eb01b4e1 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmptyNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmptyNode.java @@ -25,20 +25,6 @@ public final class EmptyNode extends AbstractNode { } - /** - * Method to check if the node in question is a ByMimeTypeNode which is empty. - * - * @param originNode the Node which you wish to check. - * @return True if originNode is an instance of ByMimeTypeNode and is empty, false otherwise. - */ - public static boolean isEmptyMimeTypeNode(Node originNode) { - boolean isEmptyMimeNode = false; - if (originNode instanceof FileTypesByMimeType.ByMimeTypeNode && ((FileTypesByMimeType.ByMimeTypeNode) originNode).isEmpty()) { - isEmptyMimeNode = true; - } - return isEmptyMimeNode; - } - static class EmptyChildFactory extends ChildFactory { String fileIdMsg; //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeByExtNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeByExtNode.java deleted file mode 100644 index f3d7eb28ba..0000000000 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeByExtNode.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * 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 org.sleuthkit.autopsy.datamodel.accounts.FileTypeExtensionFilters; -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.nodes.Sheet; -import org.openide.util.NbBundle; -import org.openide.util.lookup.Lookups; -import org.sleuthkit.autopsy.core.UserPreferences; -import org.sleuthkit.autopsy.coreutils.Logger; -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 a specific file type / extension. Children of it will be the files - * of that type. - */ -class FileTypeByExtNode extends DisplayableItemNode { - - FileTypeExtensionFilters.SearchFilterInterface filter; - SleuthkitCase skCase; - - // deprecated in favor of the version that takes an observable to provide refresh updates - @Deprecated - FileTypeByExtNode(FileTypeExtensionFilters.SearchFilterInterface filter, SleuthkitCase skCase) { - super(Children.create(new FileTypeChildFactory(filter, skCase), true), Lookups.singleton(filter.getDisplayName())); - this.filter = filter; - this.skCase = skCase; - init(); - } - - /** - * - * @param filter Extensions that will be shown for this node - * @param skCase - * @param o Observable that sends updates when the child factories - * should refresh - */ - 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; - init(); - o.addObserver(new FileTypeNodeObserver()); - } - - private void init() { - super.setName(filter.getName()); - updateDisplayName(); - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS - } - - // update the display name when new events are fired - private class FileTypeNodeObserver implements Observer { - - @Override - public void update(Observable o, Object arg) { - updateDisplayName(); - } - } - - private void updateDisplayName() { - final long count = FileTypeChildFactory.calculateItems(skCase, filter); - super.setDisplayName(filter.getDisplayName() + " (" + count + ")"); - } - - @Override - public T accept(DisplayableItemNodeVisitor v) { - return v.visit(this); - } - - @Override - protected Sheet createSheet() { - Sheet s = super.createSheet(); - Sheet.Set ss = s.get(Sheet.PROPERTIES); - if (ss == null) { - ss = Sheet.createPropertiesSet(); - s.put(ss); - } - - ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypeByExtNode.createSheet.filterType.name"), - NbBundle.getMessage(this.getClass(), "FileTypeByExtNode.createSheet.filterType.displayName"), - NbBundle.getMessage(this.getClass(), "FileTypeByExtNode.createSheet.filterType.desc"), - filter.getDisplayName())); - String extensions = ""; - for (String ext : filter.getFilter()) { - extensions += "'" + ext + "', "; - } - extensions = extensions.substring(0, extensions.lastIndexOf(',')); - ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypeByExtNode.createSheet.fileExt.name"), - NbBundle.getMessage(this.getClass(), "FileTypeByExtNode.createSheet.fileExt.displayName"), - NbBundle.getMessage(this.getClass(), "FileTypeByExtNode.createSheet.fileExt.desc"), - extensions)); - - return s; - } - - @Override - public boolean isLeafTypeNode() { - return true; - } - - /** - * Consider allowing different configurations for Images, Videos, etc - * (in which case we'd return getClass().getName() + filter.getName() - * for all filters). - */ - @Override - public String getItemType() { - return DisplayableItemNode.FILE_PARENT_NODE_KEY; - } - - /** - * Child node factory for a specific file type - does the database query. - */ - private static class FileTypeChildFactory extends ChildFactory.Detachable { - - private final SleuthkitCase skCase; - private final FileTypeExtensionFilters.SearchFilterInterface filter; - private final static Logger LOGGER = Logger.getLogger(FileTypeChildFactory.class.getName()); - private final Observable notifier; - - // use the constructor that gets an observable passed in for updates - @Deprecated - FileTypeChildFactory(FileTypeExtensionFilters.SearchFilterInterface filter, SleuthkitCase skCase) { - super(); - this.filter = filter; - this.skCase = skCase; - notifier = null; - } - - /** - * - * @param filter Extensions to display - * @param skCase - * @param o Observable that will notify when there could be new - * data to display - */ - private FileTypeChildFactory(FileTypeExtensionFilters.SearchFilterInterface filter, SleuthkitCase skCase, Observable o) { - super(); - this.filter = filter; - this.skCase = skCase; - notifier = o; - } - - @Override - protected void addNotify() { - if (notifier != null) { - notifier.addObserver(observer); - } - } - - @Override - protected void removeNotify() { - if (notifier != null) { - notifier.deleteObserver(observer); - } - } - private final Observer observer = new FileTypeChildFactoryObserver(); - - // Cause refresh of children if there are changes - private class FileTypeChildFactoryObserver implements Observer { - - @Override - public void update(Observable o, Object arg) { - refresh(true); - } - } - - /** - * Get children count without actually loading all nodes - * - * @return - */ - private static long calculateItems(SleuthkitCase sleuthkitCase, FileTypeExtensionFilters.SearchFilterInterface filter) { - try { - return sleuthkitCase.countFilesWhere(createQuery(filter)); - } 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(filter)); - list.addAll(files); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS - } - return true; - } - - private static String createQuery(FileTypeExtensionFilters.SearchFilterInterface filter) { - 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 (NULL"); //NON-NLS - for (String s : filter.getFilter()) { - query.append(" OR LOWER(name) LIKE LOWER('%").append(s).append("')"); //NON-NLS - } - query.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/FileTypesByExtNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtNode.java index be76722876..4e40ab9bc4 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtNode.java @@ -24,6 +24,9 @@ import java.beans.PropertyChangeListener; import java.util.Arrays; 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; @@ -31,8 +34,20 @@ import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; 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 file types view. Children are nodes for specific types. @@ -41,14 +56,15 @@ class FileTypesByExtNode extends DisplayableItemNode { private static final String FNAME = NbBundle.getMessage(FileTypesByExtNode.class, "FileTypesByExtNode.fname.text"); private final FileTypeExtensionFilters.RootFilter filter; + /** * * @param skCase * @param filter null to display root node of file type tree, pass in - * something to provide a sub-node. + * something to provide a sub-node. */ FileTypesByExtNode(SleuthkitCase skCase, FileTypeExtensionFilters.RootFilter filter) { - super(Children.create(new FileTypesByExtChildren(skCase, filter, null), true), Lookups.singleton(filter == null ? FNAME : filter.getName())); + super(Children.create(new ByExtChildren(skCase, filter, null), true), Lookups.singleton(filter == null ? FNAME : filter.getName())); this.filter = filter; init(); } @@ -57,11 +73,11 @@ class FileTypesByExtNode extends DisplayableItemNode { * * @param skCase * @param filter - * @param o Observable that was created by a higher-level node that - * provides updates on events + * @param o Observable that was created by a higher-level node that provides + * updates on events */ private FileTypesByExtNode(SleuthkitCase skCase, FileTypeExtensionFilters.RootFilter filter, Observable o) { - super(Children.create(new FileTypesByExtChildren(skCase, filter, o), true), Lookups.singleton(filter == null ? FNAME : filter.getName())); + super(Children.create(new ByExtChildren(skCase, filter, o), true), Lookups.singleton(filter == null ? FNAME : filter.getName())); this.filter = filter; init(); } @@ -108,21 +124,23 @@ class FileTypesByExtNode extends DisplayableItemNode { @Override public String getItemType() { /** - * Because Documents and Executable are further expandable, their - * column order settings should be stored separately. + * Because Documents and Executable are further expandable, their column + * order settings should be stored separately. */ - if(filter == null) + if (filter == null) { return getClass().getName(); - if (filter.equals(FileTypeExtensionFilters.RootFilter.TSK_DOCUMENT_FILTER) || - filter.equals(FileTypeExtensionFilters.RootFilter.TSK_EXECUTABLE_FILTER)) + } + if (filter.equals(FileTypeExtensionFilters.RootFilter.TSK_DOCUMENT_FILTER) + || filter.equals(FileTypeExtensionFilters.RootFilter.TSK_EXECUTABLE_FILTER)) { return getClass().getName() + filter.getName(); + } return getClass().getName(); } /** * */ - private static class FileTypesByExtChildren extends ChildFactory { + private static class ByExtChildren extends ChildFactory { private final SleuthkitCase skCase; private final FileTypeExtensionFilters.RootFilter filter; @@ -132,15 +150,15 @@ class FileTypesByExtNode extends DisplayableItemNode { * * @param skCase * @param filter Is null for root node - * @param o Observable that provides updates based on events being - * fired (or null if one needs to be created) + * @param o Observable that provides updates based on events being fired + * (or null if one needs to be created) */ - private FileTypesByExtChildren(SleuthkitCase skCase, FileTypeExtensionFilters.RootFilter filter, Observable o) { + private ByExtChildren(SleuthkitCase skCase, FileTypeExtensionFilters.RootFilter filter, Observable o) { super(); this.skCase = skCase; this.filter = filter; if (o == null) { - this.notifier = new FileTypesByExtChildrenObservable(); + this.notifier = new ByExtChildrenObservable(); } else { this.notifier = o; } @@ -150,9 +168,9 @@ class FileTypesByExtNode extends DisplayableItemNode { * Listens for case and ingest invest. Updates observers when events are * fired. FileType and FileTypes nodes are all listening to this. */ - private final class FileTypesByExtChildrenObservable extends Observable { + private final class ByExtChildrenObservable extends Observable { - private FileTypesByExtChildrenObservable() { + private ByExtChildrenObservable() { IngestManager.getInstance().addIngestJobEventListener(pcl); IngestManager.getInstance().addIngestModuleEventListener(pcl); Case.addPropertyChangeListener(pcl); @@ -224,7 +242,231 @@ class FileTypesByExtNode extends DisplayableItemNode { } else if (key.getName().equals(FileTypeExtensionFilters.RootFilter.TSK_EXECUTABLE_FILTER.getName())) { return new FileTypesByExtNode(skCase, FileTypeExtensionFilters.RootFilter.TSK_EXECUTABLE_FILTER, notifier); } else { - return new FileTypeByExtNode(key, skCase, notifier); + return new ByExtNode(key, skCase, notifier); + } + } + } + + /** + * Node for a specific file type / extension. Children of it will be the + * files of that type. + */ + static class ByExtNode extends DisplayableItemNode { + + FileTypeExtensionFilters.SearchFilterInterface filter; + SleuthkitCase skCase; + + /** + * + * @param filter Extensions that will be shown for this node + * @param skCase + * @param o Observable that sends updates when the child factories + * should refresh + */ + ByExtNode(FileTypeExtensionFilters.SearchFilterInterface filter, SleuthkitCase skCase, Observable o) { + super(Children.create(new ByExtChildFactory(filter, skCase, o), true), Lookups.singleton(filter.getDisplayName())); + this.filter = filter; + this.skCase = skCase; + init(); + o.addObserver(new ByExtNodeObserver()); + } + + private void init() { + super.setName(filter.getName()); + updateDisplayName(); + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS + } + + // update the display name when new events are fired + private class ByExtNodeObserver implements Observer { + + @Override + public void update(Observable o, Object arg) { + updateDisplayName(); + } + } + + private void updateDisplayName() { + final long count = ByExtChildFactory.calculateItems(skCase, filter); + super.setDisplayName(filter.getDisplayName() + " (" + count + ")"); + } + + @Override + public T accept(DisplayableItemNodeVisitor v) { + return v.visit(this); + } + + @Override + protected Sheet createSheet() { + Sheet s = super.createSheet(); + Sheet.Set ss = s.get(Sheet.PROPERTIES); + if (ss == null) { + ss = Sheet.createPropertiesSet(); + s.put(ss); + } + + ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.filterType.name"), + NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.filterType.displayName"), + NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.filterType.desc"), + filter.getDisplayName())); + String extensions = ""; + for (String ext : filter.getFilter()) { + extensions += "'" + ext + "', "; + } + extensions = extensions.substring(0, extensions.lastIndexOf(',')); + ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.name"), + NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.displayName"), + NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.desc"), + extensions)); + + return s; + } + + @Override + public boolean isLeafTypeNode() { + return true; + } + + /** + * Consider allowing different configurations for Images, Videos, etc + * (in which case we'd return getClass().getName() + filter.getName() + * for all filters). + */ + @Override + public String getItemType() { + return DisplayableItemNode.FILE_PARENT_NODE_KEY; + } + + /** + * Child node factory for a specific file type - does the database + * query. + */ + private static class ByExtChildFactory extends ChildFactory.Detachable { + + private final SleuthkitCase skCase; + private final FileTypeExtensionFilters.SearchFilterInterface filter; + private final static Logger LOGGER = Logger.getLogger(ByExtChildFactory.class.getName()); + private final Observable notifier; + + // use the constructor that gets an observable passed in for updates + @Deprecated + ByExtChildFactory(FileTypeExtensionFilters.SearchFilterInterface filter, SleuthkitCase skCase) { + super(); + this.filter = filter; + this.skCase = skCase; + notifier = null; + } + + /** + * + * @param filter Extensions to display + * @param skCase + * @param o Observable that will notify when there could be new data + * to display + */ + private ByExtChildFactory(FileTypeExtensionFilters.SearchFilterInterface filter, SleuthkitCase skCase, Observable o) { + super(); + this.filter = filter; + this.skCase = skCase; + notifier = o; + } + + @Override + protected void addNotify() { + if (notifier != null) { + notifier.addObserver(observer); + } + } + + @Override + protected void removeNotify() { + if (notifier != null) { + notifier.deleteObserver(observer); + } + } + private final Observer observer = new FileTypeChildFactoryObserver(); + + // Cause refresh of children if there are changes + private class FileTypeChildFactoryObserver implements Observer { + + @Override + public void update(Observable o, Object arg) { + refresh(true); + } + } + + /** + * Get children count without actually loading all nodes + * + * @return + */ + private static long calculateItems(SleuthkitCase sleuthkitCase, FileTypeExtensionFilters.SearchFilterInterface filter) { + try { + return sleuthkitCase.countFilesWhere(createQuery(filter)); + } 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(filter)); + list.addAll(files); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS + } + return true; + } + + private static String createQuery(FileTypeExtensionFilters.SearchFilterInterface filter) { + 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 (NULL"); //NON-NLS + for (String s : filter.getFilter()) { + query.append(" OR LOWER(name) LIKE LOWER('%").append(s).append("')"); //NON-NLS + } + query.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/FileTypesByMimeType.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java index 8548904601..0bfc95660e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java @@ -57,7 +57,7 @@ import org.sleuthkit.datamodel.TskData; * Listener which is checking for changes in IngestJobEvent Completed or * Cancelled and IngestModuleEvent Content Changed. */ -class FileTypesByMimeType extends Observable implements AutopsyVisitableItem { +public final class FileTypesByMimeType extends Observable implements AutopsyVisitableItem { private final SleuthkitCase SKCASE; /** @@ -167,315 +167,334 @@ class FileTypesByMimeType extends Observable implements AutopsyVisitableItem { return v.visit(this); } -/** - * Class which represents the root node of the "By MIME Type" tree, will have - * children of each media type present in the database or no children when the - * file detection module has not been run and MIME type is currently unknown. - */ -class ByMimeTypeNode extends DisplayableItemNode { - - @NbBundle.Messages("FileTypesByMimeType.name.text=By MIME Type") - final String NAME = Bundle.FileTypesByMimeType_name_text(); - - ByMimeTypeNode() { - super(Children.create(new ByMimeTypeNodeChildren(), true)); - super.setName(NAME); - super.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(); - } - - boolean isEmpty() { - return existingMimeTypes.isEmpty(); - } - -} - -/** - * Creates the children for the "By MIME Type" node these children will each - * represent a distinct media type present in the DB - */ -private class ByMimeTypeNodeChildren extends ChildFactory implements Observer { - - private ByMimeTypeNodeChildren() { - super(); - addObserver(this); - } - - @Override - protected boolean createKeys(List mediaTypeNodes) { - if (!existingMimeTypes.isEmpty()) { - mediaTypeNodes.addAll(getMediaTypeList()); + /** + * Method to check if the node in question is a ByMimeTypeNode which is + * empty. + * + * @param originNode the Node which you wish to check. + * @return True if originNode is an instance of ByMimeTypeNode and is empty, + * false otherwise. + */ + public static boolean isEmptyMimeTypeNode(Node originNode) { + boolean isEmptyMimeNode = false; + if (originNode instanceof FileTypesByMimeType.ByMimeTypeNode && ((FileTypesByMimeType.ByMimeTypeNode) originNode).isEmpty()) { + isEmptyMimeNode = true; } - return true; - } - - @Override - protected Node createNodeForKey(String key) { - return new MediaTypeNode(key); - } - - @Override - public void update(Observable o, Object arg) { - refresh(true); - } - -} - -/** - * The Media type node created by the ByMimeTypeNodeChildren and - contains one of the unique media types present in the database for this case. - */ -class MediaTypeNode extends DisplayableItemNode { - - MediaTypeNode(String name) { - super(Children.create(new MediaTypeNodeChildren(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(); - } - -} - -/** - * Creates children for media type nodes, children will be MediaSubTypeNodes and - * represent one of the subtypes which are present in the database of their - * media type. - */ -private class MediaTypeNodeChildren extends ChildFactory implements Observer { - - String mediaType; - - MediaTypeNodeChildren(String name) { - addObserver(this); - this.mediaType = name; - } - - @Override - protected boolean createKeys(List mediaTypeNodes) { - mediaTypeNodes.addAll(existingMimeTypes.get(mediaType)); - return true; - } - - @Override - protected Node createNodeForKey(String subtype) { - String mimeType = mediaType + "/" + subtype; - return new MediaSubTypeNode(mimeType); - } - - @Override - public void update(Observable o, Object arg) { - refresh(true); - } - -} - -/** - * Node which represents the media sub type in the By MIME type tree, the media - * subtype is the portion of the MIME type following the /. - */ -class MediaSubTypeNode extends DisplayableItemNode implements Observer { - - private MediaSubTypeNode(String mimeType) { - super(Children.create(new MediaSubTypeNodeChildren(mimeType), true)); - addObserver(this); - init(mimeType); - } - - private void init(String mimeType) { - super.setName(mimeType); - updateDisplayName(mimeType); - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS + return isEmptyMimeNode; } /** - * Updates the display name of the mediaSubTypeNode to include the count of - * files which it represents. - * - * @param mimeType - the complete MimeType, needed for accurate query - * results + * Class which represents the root node of the "By MIME Type" tree, will + * have children of each media type present in the database or no children + * when the file detection module has not been run and MIME type is + * currently unknown. */ - private void updateDisplayName(String mimeType) { + class ByMimeTypeNode extends DisplayableItemNode { - final long count = new MediaSubTypeNodeChildren(mimeType).calculateItems(SKCASE, mimeType); + @NbBundle.Messages("FileTypesByMimeType.name.text=By MIME Type") + final String NAME = Bundle.FileTypesByMimeType_name_text(); + + ByMimeTypeNode() { + super(Children.create(new ByMimeTypeNodeChildren(), true)); + super.setName(NAME); + super.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(); + } + + boolean isEmpty() { + return existingMimeTypes.isEmpty(); + } - super.setDisplayName(mimeType.split("/")[1] + " (" + count + ")"); } /** - * This returns true because any MediaSubTypeNode that exists is going to be - * a bottom level node in the Tree view on the left of Autopsy. - * - * @return true + * Creates the children for the "By MIME Type" node these children will each + * represent a distinct media type present in the DB */ - @Override - public boolean isLeafTypeNode() { - return true; - } + private class ByMimeTypeNodeChildren extends ChildFactory implements Observer { - @Override - public T accept(DisplayableItemNodeVisitor v) { - return v.visit(this); - } + private ByMimeTypeNodeChildren() { + super(); + addObserver(this); + } - @Override - public String getItemType() { - return getClass().getName(); - } + @Override + protected boolean createKeys(List mediaTypeNodes) { + if (!existingMimeTypes.isEmpty()) { + mediaTypeNodes.addAll(getMediaTypeList()); + } + return true; + } - @Override - public void update(Observable o, Object arg) { - updateDisplayName(getName()); - } -} + @Override + protected Node createNodeForKey(String key) { + return new MediaTypeNode(key); + } -/** - * Factory for populating the contents of the Media Sub Type Node with the files - * that match MimeType which is represented by this position in the tree. - */ -private class MediaSubTypeNodeChildren extends ChildFactory.Detachable implements Observer { + @Override + public void update(Observable o, Object arg) { + refresh(true); + } - private final String mimeType; - - private MediaSubTypeNodeChildren(String mimeType) { - super(); - addObserver(this); - this.mimeType = mimeType; } /** - * Get children count without actually loading all nodes - * - * @return count(*) - the number of items that will be shown in this items - * Directory Listing + * The Media type node created by the ByMimeTypeNodeChildren and contains + * one of the unique media types present in the database for this case. */ - private long calculateItems(SleuthkitCase sleuthkitCase, String mime_type) { - try { - return sleuthkitCase.countFilesWhere(createQuery(mime_type)); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Error getting file search view count", ex); //NON-NLS - return 0; + class MediaTypeNode extends DisplayableItemNode { + + MediaTypeNode(String name) { + super(Children.create(new MediaTypeNodeChildren(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(); + } + + } + + /** + * Creates children for media type nodes, children will be MediaSubTypeNodes + * and represent one of the subtypes which are present in the database of + * their media type. + */ + private class MediaTypeNodeChildren extends ChildFactory implements Observer { + + String mediaType; + + MediaTypeNodeChildren(String name) { + addObserver(this); + this.mediaType = name; + } + + @Override + protected boolean createKeys(List mediaTypeNodes) { + mediaTypeNodes.addAll(existingMimeTypes.get(mediaType)); + return true; + } + + @Override + protected Node createNodeForKey(String subtype) { + String mimeType = mediaType + "/" + subtype; + return new MediaSubTypeNode(mimeType); + } + + @Override + public void update(Observable o, Object arg) { + refresh(true); + } + + } + + /** + * Node which represents the media sub type in the By MIME type tree, the + * media subtype is the portion of the MIME type following the /. + */ + class MediaSubTypeNode extends DisplayableItemNode implements Observer { + + private MediaSubTypeNode(String mimeType) { + super(Children.create(new MediaSubTypeNodeChildren(mimeType), true)); + addObserver(this); + init(mimeType); + } + + private void init(String mimeType) { + super.setName(mimeType); + updateDisplayName(mimeType); + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS + } + + /** + * Updates the display name of the mediaSubTypeNode to include the count + * of files which it represents. + * + * @param mimeType - the complete MimeType, needed for accurate query + * results + */ + private void updateDisplayName(String mimeType) { + + final long count = new MediaSubTypeNodeChildren(mimeType).calculateItems(SKCASE, mimeType); + + super.setDisplayName(mimeType.split("/")[1] + " (" + count + ")"); + } + + /** + * This returns true because any MediaSubTypeNode that exists is going + * to be a bottom level node in the Tree view on the left of Autopsy. + * + * @return true + */ + @Override + public boolean isLeafTypeNode() { + return true; + } + + @Override + public T accept(DisplayableItemNodeVisitor v) { + return v.visit(this); + } + + @Override + public String getItemType() { + return getClass().getName(); + } + + @Override + public void update(Observable o, Object arg) { + updateDisplayName(getName()); } } /** - * Uses the createQuery method to complete the query, Select * from - * tsk_files WHERE. The results from the database will contain the files - * which match this mime type and their information. - * - * @param list - will contain all files and their attributes from the - * tsk_files table where mime_type matches the one specified - * @return true + * Factory for populating the contents of the Media Sub Type Node with the + * files that match MimeType which is represented by this position in the + * tree. */ - @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 + private class MediaSubTypeNodeChildren extends ChildFactory.Detachable implements Observer { + + private final String mimeType; + + private MediaSubTypeNodeChildren(String mimeType) { + super(); + addObserver(this); + this.mimeType = mimeType; } - return true; - } - /** - * Create the portion of the query following WHERE for a query of the - * database for each file which matches the complete MIME type represented - * by this node. Matches against the mime_type column in tsk_files. - * - * @param mimeType - the complete mimetype of the file mediatype/subtype - * @return query.toString - portion of SQL query which will follow a WHERE - * clause. - */ - private String createQuery(String mime_type) { - StringBuilder query = new StringBuilder(); - query.append("(dir_type = ").append(TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue()).append(")"); //NON-NLS - query.append(" AND (type IN (").append(TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal()).append(","); //NON-NLS - query.append(TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal()).append(","); - query.append(TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal()).append(","); - query.append(TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()).append("))"); - if (UserPreferences.hideKnownFilesInViewsTree()) { - query.append(" AND (known IS NULL OR known != ").append(TskData.FileKnown.KNOWN.getFileKnownValue()).append(")"); //NON-NLS + /** + * Get children count without actually loading all nodes + * + * @return count(*) - the number of items that will be shown in this + * items Directory Listing + */ + private long calculateItems(SleuthkitCase sleuthkitCase, String mime_type) { + try { + return sleuthkitCase.countFilesWhere(createQuery(mime_type)); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Error getting file search view count", ex); //NON-NLS + return 0; + } + } + + /** + * Uses the createQuery method to complete the query, Select * from + * tsk_files WHERE. The results from the database will contain the files + * which match this mime type and their information. + * + * @param list - will contain all files and their attributes from the + * tsk_files table where mime_type matches the one specified + * @return true + */ + @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; + } + + /** + * Create the portion of the query following WHERE for a query of the + * database for each file which matches the complete MIME type + * represented by this node. Matches against the mime_type column in + * tsk_files. + * + * @param mimeType - the complete mimetype of the file mediatype/subtype + * @return query.toString - portion of SQL query which will follow a + * WHERE clause. + */ + private String createQuery(String mime_type) { + StringBuilder query = new StringBuilder(); + query.append("(dir_type = ").append(TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue()).append(")"); //NON-NLS + query.append(" AND (type IN (").append(TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal()).append(","); //NON-NLS + query.append(TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal()).append(","); + query.append(TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal()).append(","); + query.append(TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()).append("))"); + 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(mime_type).append("'"); //NON-NLS + return query.toString(); + } + + @Override + public void update(Observable o, Object arg) { + refresh(true); + } + + /** + * Creates the content to populate the Directory Listing Table view for + * each file + * + * @param key + * @return + */ + @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())); + } + }); } - query.append(" AND mime_type = '").append(mime_type).append("'"); //NON-NLS - return query.toString(); } - @Override - public void update(Observable o, Object arg) { - refresh(true); - } - - /** - * Creates the content to populate the Directory Listing Table view for each - * file - * - * @param key - * @return - */ - @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/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index a57f85fb68..496831fa88 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -63,6 +63,7 @@ import org.sleuthkit.autopsy.datamodel.DataSources; import org.sleuthkit.autopsy.datamodel.DataSourcesNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.ExtractedContent; +import org.sleuthkit.autopsy.datamodel.FileTypesByMimeType; import org.sleuthkit.autopsy.datamodel.KeywordHits; import org.sleuthkit.autopsy.datamodel.KnownFileFilterNode; import org.sleuthkit.autopsy.datamodel.Reports; @@ -134,7 +135,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat refreshContentTreeSafe(); break; case UserPreferences.HIDE_KNOWN_FILES_IN_VIEWS_TREE: - case UserPreferences.HIDE_SLACK_FILES_IN_VIEWS_TREE: + case UserPreferences.HIDE_SLACK_FILES_IN_VIEWS_TREE: // TODO: Need a way to refresh the Views subtree break; } @@ -602,7 +603,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat } } } - + @NbBundle.Messages("DirectoryTreeTopComponent.emptyMimeNode.text=Data not available. Run file type identification module.") /** * Event handler to run when selection changed @@ -645,12 +646,10 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat Node kffn = new KnownFileFilterNode(drfn, KnownFileFilterNode.getSelectionContext(originNode)); Node sffn = new SlackFileFilterNode(kffn, SlackFileFilterNode.getSelectionContext(originNode)); - // Create a TableFilterNode with knowledge of the node's type to allow for column order settings - //Special case for when File Type Identification has not yet been run and //there are no mime types to populate Files by Mime Type Tree - if (EmptyNode.isEmptyMimeTypeNode(originNode)) { + if (FileTypesByMimeType.isEmptyMimeTypeNode(originNode)) { EmptyNode emptyNode = new EmptyNode(Bundle.DirectoryTreeTopComponent_emptyMimeNode_text()); Node emptyDrfn = new DataResultFilterNode(emptyNode, DirectoryTreeTopComponent.this.em); Node emptyKffn = new KnownFileFilterNode(emptyDrfn, KnownFileFilterNode.getSelectionContext(emptyNode));