5372 initial video thumbnail viewer

This commit is contained in:
William Schaefer 2019-08-12 13:07:30 -04:00
parent 6da2310384
commit ab6abbe29a
15 changed files with 344 additions and 68 deletions

View File

@ -56,3 +56,4 @@ ResultsPanel.currentPageLabel.text=Page: -
ResultsPanel.pageControlsLabel.text=Pages:
ResultsPanel.gotoPageLabel.text=Go to Page:
ResultsPanel.pageSizeLabel.text=Page size:
ThumbnailPanel.fileInfoLabel.text=

View File

@ -164,3 +164,4 @@ ResultsPanel.pageControlsLabel.text=Pages:
ResultsPanel.gotoPageLabel.text=Go to Page:
ResultsPanel.pageSizeLabel.text=Page size:
SearchNode.getName.text=Search Result
ThumbnailPanel.fileInfoLabel.text=

View File

@ -24,10 +24,9 @@ import java.util.List;
import java.util.LinkedHashMap;
import java.util.Map;
import org.sleuthkit.autopsy.filequery.FileSearchData.FileType;
import org.sleuthkit.datamodel.AbstractFile;
/**
* Class to handle envent bus and events for file discovery tool.
* Class to handle event bus and events for file discovery tool.
*/
final class DiscoveryEvents {
@ -156,7 +155,7 @@ final class DiscoveryEvents {
*/
static final class PageRetrievedEvent {
private final List<AbstractFile> results;
private final List<ResultFile> results;
private final int page;
private final FileType resultType;
@ -167,7 +166,7 @@ final class DiscoveryEvents {
* @param page The number of the page which was retrieved.
* @param results The list of files in the page retrieved.
*/
PageRetrievedEvent(FileType resultType, int page, List<AbstractFile> results) {
PageRetrievedEvent(FileType resultType, int page, List<ResultFile> results) {
this.results = results;
this.page = page;
this.resultType = resultType;
@ -178,7 +177,7 @@ final class DiscoveryEvents {
*
* @return The list of files in the page retrieved.
*/
List<AbstractFile> getSearchResults() {
List<ResultFile> getSearchResults() {
return Collections.unmodifiableList(results);
}

View File

@ -77,8 +77,8 @@ class FileGroup implements Comparable<FileGroup> {
*
* @return List of abstract files
*/
List<AbstractFile> getAbstractFiles() {
return files.stream().map(file -> file.getAbstractFile()).collect(Collectors.toList());
List<ResultFile> getAbstractFiles() {
return Collections.unmodifiableList(files);
}
/**

View File

@ -57,7 +57,7 @@ import org.sleuthkit.datamodel.TskCoreException;
class FileSearch {
private final static Logger logger = Logger.getLogger(FileSearch.class.getName());
private static final Cache<String, List<AbstractFile>> groupCache = CacheBuilder.newBuilder().build();
private static final Cache<String, List<ResultFile>> groupCache = CacheBuilder.newBuilder().build();
/**
* Run the file search and returns the SearchResults object for debugging.
@ -104,7 +104,7 @@ class FileSearch {
// Sort and group the results
searchResults.sortGroupsAndFiles();
LinkedHashMap<String, List<AbstractFile>> resultHashMap = searchResults.toLinkedHashMap();
LinkedHashMap<String, List<ResultFile>> resultHashMap = searchResults.toLinkedHashMap();
for (String groupName : resultHashMap.keySet()) {
groupCache.put(groupName, resultHashMap.get(groupName));
}
@ -134,7 +134,7 @@ class FileSearch {
FileGroup.GroupSortingAlgorithm groupSortingType,
FileSorter.SortingMethod fileSortingMethod,
SleuthkitCase caseDb, EamDb centralRepoDb) throws FileSearchException {
LinkedHashMap<String, List<AbstractFile>> searchResults = runFileSearch(filters,
LinkedHashMap<String, List<ResultFile>> searchResults = runFileSearch(filters,
groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb);
LinkedHashMap<String, Integer> groupSizes = new LinkedHashMap<>();
for (String groupName : searchResults.keySet()) {
@ -163,7 +163,7 @@ class FileSearch {
*
* @throws FileSearchException
*/
static synchronized List<AbstractFile> getFilesInGroup(
static synchronized List<ResultFile> getFilesInGroup(
List<FileSearchFiltering.FileFilter> filters,
AttributeType groupAttributeType,
FileGroup.GroupSortingAlgorithm groupSortingType,
@ -173,8 +173,8 @@ class FileSearch {
int numberOfEntries,
SleuthkitCase caseDb, EamDb centralRepoDb) throws FileSearchException {
//the group should be in the cache at this point
List<AbstractFile> filesInGroup = groupCache.getIfPresent(groupName);
List<AbstractFile> page = new ArrayList<>();
List<ResultFile> filesInGroup = groupCache.getIfPresent(groupName);
List<ResultFile> page = new ArrayList<>();
if (filesInGroup == null) {
logger.log(Level.INFO, "Group {0} was not cached, performing search to cache all groups again", groupName);
runFileSearch(filters, groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb);
@ -214,7 +214,7 @@ class FileSearch {
*
* @throws FileSearchException
*/
private synchronized static LinkedHashMap<String, List<AbstractFile>> runFileSearch(
private synchronized static LinkedHashMap<String, List<ResultFile>> runFileSearch(
List<FileSearchFiltering.FileFilter> filters,
AttributeType groupAttributeType,
FileGroup.GroupSortingAlgorithm groupSortingType,
@ -239,7 +239,7 @@ class FileSearch {
// Collect everything in the search results
SearchResults searchResults = new SearchResults(groupSortingType, groupAttributeType, fileSortingMethod);
searchResults.add(resultFiles);
LinkedHashMap<String, List<AbstractFile>> resultHashMap = searchResults.toLinkedHashMap();
LinkedHashMap<String, List<ResultFile>> resultHashMap = searchResults.toLinkedHashMap();
for (String groupName : resultHashMap.keySet()) {
groupCache.put(groupName, resultHashMap.get(groupName));
}
@ -361,6 +361,7 @@ class FileSearch {
*/
void addAttributeToResultFiles(List<ResultFile> files, SleuthkitCase caseDb, EamDb centralRepoDb) throws FileSearchException {
// Default is to do nothing
System.out.println("DEFAULT IMPLE ");
}
}

View File

@ -18,7 +18,6 @@
*/
package org.sleuthkit.autopsy.filequery;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.logging.Level;
@ -33,7 +32,6 @@ import org.openide.util.NbBundle;
import org.openide.util.actions.CallableSystemAction;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
/**
* Class to test the file search API. Allows the user to run searches and see results.
@ -106,7 +104,7 @@ public final class FileSearchTestAction extends CallableSystemAction {
if (! groups.isEmpty()) {
String firstGroupName = groups.keySet().iterator().next();
List<AbstractFile> entries0to5 = FileSearch.getFilesInGroup(filters,
List<ResultFile> entries0to5 = FileSearch.getFilesInGroup(filters,
groupingAttr,
groupSortAlgorithm,
fileSort,
@ -115,11 +113,11 @@ public final class FileSearchTestAction extends CallableSystemAction {
5,
Case.getCurrentCase().getSleuthkitCase(), crDb);
System.out.println("First five " + firstGroupName + " : ");
for (AbstractFile f : entries0to5) {
System.out.println(" " + f.getName());
for (ResultFile f : entries0to5) {
System.out.println(" " + f.getAbstractFile().getName());
}
List<AbstractFile> entries6to106 = FileSearch.getFilesInGroup(filters,
List<ResultFile> entries6to106 = FileSearch.getFilesInGroup(filters,
groupingAttr,
groupSortAlgorithm,
fileSort,
@ -128,8 +126,8 @@ public final class FileSearchTestAction extends CallableSystemAction {
100,
Case.getCurrentCase().getSleuthkitCase(), crDb);
System.out.println(firstGroupName + " 6 to 106: ");
for (AbstractFile f : entries6to106) {
System.out.println(" " + f.getName());
for (ResultFile f : entries6to106) {
System.out.println(" " + f.getAbstractFile().getName());
}
}

View File

@ -76,7 +76,7 @@ final class PageWorker extends SwingWorker<Void, Void> {
try {
// Run the search
List<AbstractFile> results = FileSearch.getFilesInGroup(searchfilters,
List<ResultFile> results = FileSearch.getFilesInGroup(searchfilters,
groupingAttribute,
groupSort,
fileSortMethod, groupName, startingEntry, pageSize,

View File

@ -18,12 +18,14 @@
*/
package org.sleuthkit.autopsy.filequery;
import java.awt.Image;
import org.sleuthkit.autopsy.filequery.FileSearchData.FileType;
import org.sleuthkit.datamodel.AbstractFile;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.sleuthkit.autopsy.coreutils.ImageUtils;
import org.sleuthkit.datamodel.HashUtility;
/**
@ -38,6 +40,7 @@ class ResultFile {
private final List<String> tagNames;
private final List<String> interestingSetNames;
private final List<String> objectDetectedNames;
private final List<Image> thumbnails;
private final List<AbstractFile> duplicates;
private FileType fileType;
@ -54,6 +57,7 @@ class ResultFile {
tagNames = new ArrayList<>();
interestingSetNames = new ArrayList<>();
objectDetectedNames = new ArrayList<>();
thumbnails = new ArrayList<>();
duplicates = new ArrayList<>();
fileType = FileType.OTHER;
}
@ -198,6 +202,30 @@ class ResultFile {
Collections.sort(interestingSetNames);
}
private void createThumbnails(FileSearchData.FileType resultType) {
if (resultType == FileType.IMAGE) {
System.out.println("create single image thumbnail");
thumbnails.add(ImageUtils.getThumbnail(abstractFile, ImageUtils.ICON_SIZE_MEDIUM));
} else if (resultType == FileType.VIDEO) {
thumbnails.add(ImageUtils.getThumbnail(abstractFile, ImageUtils.ICON_SIZE_LARGE));
thumbnails.add(ImageUtils.getThumbnail(abstractFile, ImageUtils.ICON_SIZE_LARGE));
thumbnails.add(ImageUtils.getThumbnail(abstractFile, ImageUtils.ICON_SIZE_LARGE));
thumbnails.add(ImageUtils.getThumbnail(abstractFile, ImageUtils.ICON_SIZE_LARGE));
} else {
System.out.println("NOT IMAGE OR VIDEO: " + fileType.name());
}
}
List<Image> getThumbnails(FileSearchData.FileType resultType) {
if (thumbnails.isEmpty()) {
System.out.println("IS EMPTY");
createThumbnails(resultType);
}
System.out.println("THUMBNAILS GOT");
return Collections.unmodifiableList(thumbnails);
}
/**
* Get the interesting item set names for this file
*
@ -252,10 +280,10 @@ class ResultFile {
if (this.getAbstractFile().getMd5Hash() == null
|| HashUtility.isNoDataMd5(this.getAbstractFile().getMd5Hash())
|| !HashUtility.isValidMd5Hash(this.getAbstractFile().getMd5Hash())) {
return super.hashCode();
return super.hashCode();
} else {
//if the file has a valid MD5 use the hashcode of the MD5 for deduping files with the same MD5
return this.getAbstractFile().getMd5Hash().hashCode();
return this.getAbstractFile().getMd5Hash().hashCode();
}
}
@ -268,7 +296,7 @@ class ResultFile {
|| !HashUtility.isValidMd5Hash(this.getAbstractFile().getMd5Hash())) {
return super.equals(obj);
} else {
//if the file has a valid MD5 compare use the MD5 for equality check
//if the file has a valid MD5 compare use the MD5 for equality check
return this.getAbstractFile().getMd5Hash().equals(((ResultFile) obj).getAbstractFile().getMd5Hash());
}
}

View File

@ -17,15 +17,15 @@
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="pagingPanel" max="32767" attributes="0"/>
<Component id="resultsViewerPanel" alignment="0" max="32767" attributes="0"/>
<Component id="jScrollPane1" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="pagingPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Component id="resultsViewerPanel" max="32767" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="jScrollPane1" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -101,15 +101,6 @@
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[23, 23]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[23, 23]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[23, 23]"/>
</Property>
<Property name="rolloverIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"/>
</Property>
@ -147,15 +138,6 @@
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[23, 23]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[23, 23]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[23, 23]"/>
</Property>
<Property name="rolloverIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"/>
</Property>
@ -234,9 +216,15 @@
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="resultsViewerPanel">
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="resultsViewerPanel">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -19,7 +19,9 @@
package org.sleuthkit.autopsy.filequery;
import com.google.common.eventbus.Subscribe;
import java.awt.Image;
import java.util.List;
import java.util.stream.Collectors;
import javax.swing.JOptionPane;
import javax.swing.JSpinner;
import javax.swing.SwingUtilities;
@ -32,6 +34,7 @@ import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
import org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
import org.sleuthkit.datamodel.AbstractFile;
/**
* Panel for displaying of file discovery results and handling the paging of
@ -42,6 +45,7 @@ public class ResultsPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private final DataResultViewerThumbnail thumbnailViewer;
private final DataResultViewerTable tableViewer;
private final VideoThumbnailViewer videoThumbnailViewer;
private List<FileSearchFiltering.FileFilter> searchFilters;
private FileSearch.AttributeType groupingAttribute;
private FileGroup.GroupSortingAlgorithm groupSort;
@ -62,6 +66,7 @@ public class ResultsPanel extends javax.swing.JPanel {
this.centralRepo = centralRepo;
thumbnailViewer = new DataResultViewerThumbnail(explorerManager);
tableViewer = new DataResultViewerTable(explorerManager);
videoThumbnailViewer = new VideoThumbnailViewer();
// Disable manual editing of page size spinner
((JSpinner.DefaultEditor) pageSizeSpinner.getEditor()).getTextField().setEditable(false);
}
@ -79,17 +84,23 @@ public class ResultsPanel extends javax.swing.JPanel {
thumbnailViewer.resetComponent();
resultsViewerPanel.remove(thumbnailViewer);
resultsViewerPanel.remove(tableViewer);
if (pageRetrievedEvent.getType() == FileSearchData.FileType.IMAGE || pageRetrievedEvent.getType() == FileSearchData.FileType.VIDEO) {
if (pageRetrievedEvent.getType() == FileSearchData.FileType.IMAGE) {
resultsViewerPanel.add(thumbnailViewer);
if (pageRetrievedEvent.getSearchResults().size() > 0) {
thumbnailViewer.setNode(new TableFilterNode(new DataResultFilterNode(new AbstractNode(new DiscoveryThumbnailChildren(pageRetrievedEvent.getSearchResults()))), true));
List<AbstractFile> filesList = pageRetrievedEvent.getSearchResults().stream().map(file -> file.getAbstractFile()).collect(Collectors.toList());
thumbnailViewer.setNode(new TableFilterNode(new DataResultFilterNode(new AbstractNode(new DiscoveryThumbnailChildren(filesList))), true));
} else {
thumbnailViewer.setNode(new TableFilterNode(new DataResultFilterNode(Node.EMPTY), true));
}
} else if (pageRetrievedEvent.getType() == FileSearchData.FileType.VIDEO) {
populateVideoViewer(pageRetrievedEvent.getSearchResults());
resultsViewerPanel.add(videoThumbnailViewer);
} else {
resultsViewerPanel.add(tableViewer);
if (pageRetrievedEvent.getSearchResults().size() > 0) {
tableViewer.setNode(new TableFilterNode(new SearchNode(pageRetrievedEvent.getSearchResults()), true));
List<AbstractFile> filesList = pageRetrievedEvent.getSearchResults().stream().map(file -> file.getAbstractFile()).collect(Collectors.toList());
tableViewer.setNode(new TableFilterNode(new SearchNode(filesList), true));
} else {
tableViewer.setNode(new TableFilterNode(new DataResultFilterNode(Node.EMPTY), true));
}
@ -98,6 +109,19 @@ public class ResultsPanel extends javax.swing.JPanel {
});
}
void populateVideoViewer(List<ResultFile> files) {
System.out.println("POPULATE VIEWER");
videoThumbnailViewer.clearViewer();
for (ResultFile file : files) {
System.out.println("NEW THREAD");
new Thread(() -> {
System.out.println("ON NEW THREAD");
videoThumbnailViewer.addRow(file.getThumbnails(resultType), file.getAbstractFile().getParentPath());
System.out.println("END NEW THREAD");
}).start();
}
}
/**
* Subscribe and respond to GroupSelectedEvents.
*
@ -168,6 +192,7 @@ public class ResultsPanel extends javax.swing.JPanel {
gotoPageLabel = new javax.swing.JLabel();
gotoPageField = new javax.swing.JTextField();
pageSizeLabel = new javax.swing.JLabel();
jScrollPane1 = new javax.swing.JScrollPane();
resultsViewerPanel = new javax.swing.JPanel();
pagingPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
@ -177,9 +202,6 @@ public class ResultsPanel extends javax.swing.JPanel {
previousPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); // NOI18N
previousPageButton.setEnabled(false);
previousPageButton.setFocusable(false);
previousPageButton.setMaximumSize(new java.awt.Dimension(23, 23));
previousPageButton.setMinimumSize(new java.awt.Dimension(23, 23));
previousPageButton.setPreferredSize(new java.awt.Dimension(23, 23));
previousPageButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"))); // NOI18N
previousPageButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
@ -197,9 +219,6 @@ public class ResultsPanel extends javax.swing.JPanel {
nextPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); // NOI18N
nextPageButton.setEnabled(false);
nextPageButton.setFocusable(false);
nextPageButton.setMaximumSize(new java.awt.Dimension(23, 23));
nextPageButton.setMinimumSize(new java.awt.Dimension(23, 23));
nextPageButton.setPreferredSize(new java.awt.Dimension(23, 23));
nextPageButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"))); // NOI18N
nextPageButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
@ -244,9 +263,9 @@ public class ResultsPanel extends javax.swing.JPanel {
.addGap(18, 18, 18)
.addComponent(pageControlsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(previousPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(previousPageButton)
.addGap(0, 0, 0)
.addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(nextPageButton)
.addGap(18, 18, 18)
.addComponent(gotoPageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@ -262,9 +281,9 @@ public class ResultsPanel extends javax.swing.JPanel {
.addGroup(pagingPanelLayout.createSequentialGroup()
.addGap(4, 4, 4)
.addGroup(pagingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(nextPageButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(nextPageButton, javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, pagingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(previousPageButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(previousPageButton, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(currentPageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(pageControlsLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, pagingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
@ -276,20 +295,21 @@ public class ResultsPanel extends javax.swing.JPanel {
);
resultsViewerPanel.setLayout(new java.awt.BorderLayout());
jScrollPane1.setViewportView(resultsViewerPanel);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(pagingPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(resultsViewerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jScrollPane1)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(pagingPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0)
.addComponent(resultsViewerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(jScrollPane1))
);
}// </editor-fold>//GEN-END:initComponents
@ -368,6 +388,7 @@ public class ResultsPanel extends javax.swing.JPanel {
private javax.swing.JLabel currentPageLabel;
private javax.swing.JTextField gotoPageField;
private javax.swing.JLabel gotoPageLabel;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JButton nextPageButton;
private javax.swing.JLabel pageControlsLabel;
private javax.swing.JLabel pageSizeLabel;

View File

@ -135,7 +135,7 @@ class SearchResults {
* @param groupName The name of the group. Can have the size appended.
* @return the list of abstract files
*/
List<AbstractFile> getAbstractFilesInGroup(String groupName) {
List<ResultFile> getAbstractFilesInGroup(String groupName) {
if (groupName != null) {
final String modifiedGroupName = groupName.replaceAll(" \\([0-9]+\\)$", "");
@ -152,8 +152,8 @@ class SearchResults {
*
* @return the grouped and sorted results
*/
LinkedHashMap<String, List<AbstractFile>> toLinkedHashMap() throws FileSearchException {
LinkedHashMap<String, List<AbstractFile>> map = new LinkedHashMap<>();
LinkedHashMap<String, List<ResultFile>> toLinkedHashMap() throws FileSearchException {
LinkedHashMap<String, List<ResultFile>> map = new LinkedHashMap<>();
// Sort the groups and files
sortGroupsAndFiles();

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
<EtchetBorder/>
</Border>
</Property>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="imagePanel" pref="756" max="32767" attributes="0"/>
<Component id="fileInfoLabel" max="32767" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="imagePanel" pref="125" max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="fileInfoLabel" pref="8" max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="imagePanel">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
</Container>
<Component class="javax.swing.JLabel" name="fileInfoLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/filequery/Bundle.properties" key="ThumbnailPanel.fileInfoLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,92 @@
/*
* 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.filequery;
import java.awt.GridBagConstraints;
import java.awt.Image;
import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
/**
*
* @author wschaefer
*/
public class ThumbnailPanel extends javax.swing.JPanel {
private static final int GAP_SIZE = 2;
/**
* Creates new form ThumbnailPanel
*/
public ThumbnailPanel(List<Image> thumbnails, String fileInfo) {
initComponents();
fileInfoLabel.setText(fileInfo);
addThumbnails(thumbnails);
this.setFocusable(true);
}
private void addThumbnails(List<Image> thumbnails) {
GridBagConstraints gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = GridBagConstraints.LINE_START;
imagePanel.add(new javax.swing.Box.Filler(new java.awt.Dimension(2, 0), new java.awt.Dimension(2, 0), new java.awt.Dimension(2, 32767)));
gridBagConstraints.gridx++;
for (Image image : thumbnails) {
imagePanel.add(new JLabel(new ImageIcon(image)), gridBagConstraints);
gridBagConstraints.gridx++;
imagePanel.add(new javax.swing.Box.Filler(new java.awt.Dimension(2, 0), new java.awt.Dimension(2, 0), new java.awt.Dimension(2, 32767)));
gridBagConstraints.gridx++;
}
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
imagePanel = new javax.swing.JPanel();
fileInfoLabel = new javax.swing.JLabel();
setBorder(javax.swing.BorderFactory.createEtchedBorder());
imagePanel.setLayout(new java.awt.GridBagLayout());
org.openide.awt.Mnemonics.setLocalizedText(fileInfoLabel, org.openide.util.NbBundle.getMessage(ThumbnailPanel.class, "ThumbnailPanel.fileInfoLabel.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(imagePanel, javax.swing.GroupLayout.DEFAULT_SIZE, 756, Short.MAX_VALUE)
.addComponent(fileInfoLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(imagePanel, javax.swing.GroupLayout.DEFAULT_SIZE, 125, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(fileInfoLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 8, Short.MAX_VALUE)
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel fileInfoLabel;
private javax.swing.JPanel imagePanel;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
</Form>

View File

@ -0,0 +1,68 @@
/*
* 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.filequery;
import java.awt.GridBagConstraints;
import java.awt.Image;
import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
/**
*
* @author wschaefer
*/
public class VideoThumbnailViewer extends javax.swing.JPanel {
private int nextRow = 0;
/**
* Creates new form VideoThumbnailViewer
*/
public VideoThumbnailViewer() {
initComponents();
}
void clearViewer(){
nextRow = 0;
this.removeAll();
}
void addRow(List<Image> thumbnails, String fileInfo) {
SwingUtilities.invokeLater(() -> {
GridBagConstraints gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.anchor = GridBagConstraints.LINE_START;
synchronized (this) {
gridBagConstraints.gridy = nextRow;
nextRow++;
}
this.add(new ThumbnailPanel(thumbnails, fileInfo), gridBagConstraints);
System.out.println("ROW ADDED");
revalidate();
repaint();
});
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
setLayout(new java.awt.GridBagLayout());
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
// End of variables declaration//GEN-END:variables
}