5372 clean up and add comments in preperation of PR

This commit is contained in:
William Schaefer 2019-08-21 17:09:22 -04:00
parent 6f79f6bed5
commit bda249e2ed
12 changed files with 146 additions and 76 deletions

View File

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

View File

@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.filequery;
import com.google.common.eventbus.EventBus;
import java.util.Collections;
import java.util.List;
import java.util.LinkedHashMap;
import java.util.Map;
import org.sleuthkit.autopsy.filequery.FileSearchData.FileType;

View File

@ -61,6 +61,8 @@ class FileDiscoveryDialog extends javax.swing.JDialog {
leftSplitPane.setRightComponent(groupListPanel);
rightSplitPane.setTopComponent(resultsPanel);
rightSplitPane.setBottomComponent(dataContentPanel);
//add list selection listener so the content viewer will be updated with the selected file
//when a file is selected in the results panel
resultsPanel.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {

View File

@ -21,9 +21,6 @@ package org.sleuthkit.autopsy.filequery;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.sleuthkit.datamodel.AbstractFile;
/**
* Class for storing files that belong to a particular group.

View File

@ -335,20 +335,29 @@ class FileSearch {
+ "AND blackboard_artifacts.obj_id IN (" + objIdList + ") "; // NON-NLS
}
/**
* Get the video thumbnails for a specified AbstractFile.
*
* @param file Video file to generate thumbnails for.
*
* @return An object containing the list of video thumbnails, an array of
* their timestamps, and the AbstractFile they were generated for.
*/
@NbBundle.Messages({"# {0} - file name",
"FileSearch.genVideoThumb.progress.text=extracting temporary file {0}"})
static ThumbnailsWrapper createVideoThumbnails(AbstractFile file) {
static VideoThumbnailsWrapper getVideoThumbnails(AbstractFile file) {
//Currently this method always creates the thumbnails
java.io.File tempFile;
try {
tempFile = getVideoFileInTempDir(file);
} catch (NoCurrentCaseException ex) {
// LOGGER.log(Level.WARNING, "Exception while getting open case.", ex); //NON-NLS
logger.log(Level.WARNING, "Exception while getting open case.", ex); //NON-NLS
int[] framePositions = new int[]{
0,
0,
0,
0};
return new ThumbnailsWrapper(createDefaultThumbnailList(), framePositions, file);
return new VideoThumbnailsWrapper(createDefaultThumbnailList(), framePositions, file);
}
if (tempFile.exists() == false || tempFile.length() < file.getSize()) {
ProgressHandle progress = ProgressHandle.createHandle(Bundle.FileSearch_genVideoThumb_progress_text(file.getName()));
@ -361,11 +370,11 @@ class FileSearch {
0,
0,
0};
return new ThumbnailsWrapper(createDefaultThumbnailList(), framePositions, file);
return new VideoThumbnailsWrapper(createDefaultThumbnailList(), framePositions, file);
}
ContentUtils.writeToFile(file, tempFile, progress, null, true);
} catch (IOException ex) {
// LOGGER.log(Level.WARNING, "Error extracting temporary file for " + ImageUtils.getContentPathSafe(file), ex); //NON-NLS
logger.log(Level.WARNING, "Error extracting temporary file for " + file.getParentPath() + "/" + file.getName(), ex); //NON-NLS
} finally {
progress.finish();
}
@ -375,24 +384,24 @@ class FileSearch {
try {
if (!videoFile.open(tempFile.toString())) {
// LOGGER.log(Level.WARNING, "Error opening {0} for preview generation.", ImageUtils.getContentPathSafe(file)); //NON-NLS
logger.log(Level.WARNING, "Error opening {0} for preview generation.", file.getParentPath() + "/" + file.getName()); //NON-NLS
int[] framePositions = new int[]{
0,
0,
0,
0};
return new ThumbnailsWrapper(createDefaultThumbnailList(), framePositions, file);
return new VideoThumbnailsWrapper(createDefaultThumbnailList(), framePositions, file);
}
double fps = videoFile.get(5); // gets frame per second
double totalFrames = videoFile.get(7); // gets total frames
if (fps <= 0 || totalFrames <= 0) {
// LOGGER.log(Level.WARNING, "Error getting fps or total frames for {0}", ImageUtils.getContentPathSafe(file)); //NON-NLS
logger.log(Level.WARNING, "Error getting fps or total frames for {0}", file.getParentPath() + "/" + file.getName()); //NON-NLS
int[] framePositions = new int[]{
0,
0,
0,
0};
return new ThumbnailsWrapper(createDefaultThumbnailList(), framePositions, file);
return new VideoThumbnailsWrapper(createDefaultThumbnailList(), framePositions, file);
}
if (Thread.interrupted()) {
int[] framePositions = new int[]{
@ -400,22 +409,11 @@ class FileSearch {
0,
0,
0};
return new ThumbnailsWrapper(createDefaultThumbnailList(), framePositions, file);
return new VideoThumbnailsWrapper(createDefaultThumbnailList(), framePositions, file);
}
double duration = 1000 * (totalFrames / fps); //total milliseconds
/*
* Four attempts are made to grab a frame from a video. The first
* attempt at 50% will give us a nice frame in the middle that gets
* to the heart of the content. If that fails, the next positions
* tried will be 25% and 75%. After three failed attempts, 1% will
* be tried in a last-ditch effort, the idea being the video may be
* corrupt and that our best chance at retrieving a frame is early
* on in the video.
*
* If no frame can be retrieved, no thumbnail will be created.
*/
int[] framePositions = new int[]{
(int) (duration * .01),
(int) (duration * .25),
@ -426,7 +424,7 @@ class FileSearch {
List<Image> videoThumbnails = new ArrayList<>();
for (int i = 0; i < framePositions.length; i++) {
if (!videoFile.set(0, framePositions[i])) {
// LOGGER.log(Level.WARNING, "Error seeking to " + framePositions[i] + "ms in {0}", ImageUtils.getContentPathSafe(file)); //NON-NLS
logger.log(Level.WARNING, "Error seeking to " + framePositions[i] + "ms in {0}", file.getParentPath() + "/" + file.getName()); //NON-NLS
// If we can't set the time, continue to the next frame position and try again.
videoThumbnails.add(ImageUtils.getDefaultThumbnail());
@ -434,7 +432,7 @@ class FileSearch {
}
// Read the frame into the image/matrix.
if (!videoFile.read(imageMatrix)) {
// LOGGER.log(Level.WARNING, "Error reading frame at " + framePositions[i] + "ms from {0}", ImageUtils.getContentPathSafe(file)); //NON-NLS
logger.log(Level.WARNING, "Error reading frame at " + framePositions[i] + "ms from {0}", file.getParentPath() + "/" + file.getName()); //NON-NLS
// If the image is bad for some reason, continue to the next frame position and try again.
videoThumbnails.add(ImageUtils.getDefaultThumbnail());
continue;
@ -456,7 +454,6 @@ class FileSearch {
byte[] data = new byte[matrixRows * matrixColumns * (int) (imageMatrix.elemSize())];
imageMatrix.get(0, 0, data); //copy the image to data
//todo: this looks like we are swapping the first and third channels. so we can use BufferedImage.TYPE_3BYTE_BGR
if (imageMatrix.channels() == 3) {
for (int k = 0; k < data.length; k += 3) {
byte temp = data[k];
@ -467,11 +464,11 @@ class FileSearch {
bufferedImage.getRaster().setDataElements(0, 0, matrixColumns, matrixRows, data);
if (Thread.interrupted()) {
return new ThumbnailsWrapper(videoThumbnails, framePositions, file);
return new VideoThumbnailsWrapper(videoThumbnails, framePositions, file);
}
videoThumbnails.add(bufferedImage == null ? ImageUtils.getDefaultThumbnail() : ScalrWrapper.resizeFast(bufferedImage, ImageUtils.ICON_SIZE_LARGE));
videoThumbnails.add(ScalrWrapper.resizeFast(bufferedImage, ImageUtils.ICON_SIZE_LARGE));
}
return new ThumbnailsWrapper(videoThumbnails, framePositions, file);
return new VideoThumbnailsWrapper(videoThumbnails, framePositions, file);
} finally {
videoFile.release(); // close the file}
}

View File

@ -59,7 +59,7 @@ public class ResultsPanel extends javax.swing.JPanel {
private final EamDb centralRepo;
private int groupSize = 0;
private PageWorker pageWorker;
private final List<ThumbnailWorker> thumbnailWorkers = new ArrayList<>();
private final List<SwingWorker> thumbnailWorkers = new ArrayList<>();
/**
* Creates new form ResultsPanel.
@ -122,8 +122,8 @@ public class ResultsPanel extends javax.swing.JPanel {
}
void populateVideoViewer(List<ResultFile> files) {
//cancell any unfished thumb workers
for (ThumbnailWorker thumbWorker : thumbnailWorkers) {
//cancel any unfished thumb workers
for (SwingWorker thumbWorker : thumbnailWorkers) {
if (!thumbWorker.isDone()) {
thumbWorker.cancel(true);
}
@ -132,9 +132,9 @@ public class ResultsPanel extends javax.swing.JPanel {
thumbnailWorkers.clear();
videoThumbnailViewer.clearViewer();
for (ResultFile file : files) {
ThumbnailWorker thumbWorker = new ThumbnailWorker(file);
VideoThumbnailWorker thumbWorker = new VideoThumbnailWorker(file);
thumbWorker.execute();
//keep track of thumb worker for possible cancellation
//keep track of thumb worker for possible cancelation
thumbnailWorkers.add(thumbWorker);
}
}
@ -426,18 +426,18 @@ public class ResultsPanel extends javax.swing.JPanel {
private javax.swing.JPanel resultsViewerPanel;
// End of variables declaration//GEN-END:variables
private class ThumbnailWorker extends SwingWorker<Void, Void> {
private class VideoThumbnailWorker extends SwingWorker<Void, Void> {
private final ResultFile file;
private ThumbnailsWrapper thumbnailWrapper;
private VideoThumbnailsWrapper thumbnailWrapper;
ThumbnailWorker(ResultFile file) {
VideoThumbnailWorker(ResultFile file) {
this.file = file;
}
@Override
protected Void doInBackground() throws Exception {
thumbnailWrapper = FileSearch.createVideoThumbnails(file.getAbstractFile());
thumbnailWrapper = FileSearch.getVideoThumbnails(file.getAbstractFile());
return null;
}

View File

@ -24,9 +24,7 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.sleuthkit.datamodel.AbstractFile;
/**
* Class to hold the results of the filtering/grouping/sorting operations

View File

@ -51,11 +51,6 @@
<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

@ -1,7 +1,20 @@
/*
* 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.
* Autopsy
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
@ -16,23 +29,28 @@ import javax.swing.JList;
import javax.swing.ListCellRenderer;
/**
*
* Class which displays thumbnails and information for a video file.
*/
public final class ThumbnailPanel extends javax.swing.JPanel implements ListCellRenderer<ThumbnailsWrapper> {
public final class VideoThumbnailPanel extends javax.swing.JPanel implements ListCellRenderer<VideoThumbnailsWrapper> {
private static final int GAP_SIZE = 4;
private static final Color SELECTION_COLOR = new Color(100, 200, 255);
private static final long serialVersionUID = 1L;
/**
* Creates new form ThumbnailPanel
* Creates new form VideoThumbnailPanel
*/
public ThumbnailPanel() {
public VideoThumbnailPanel() {
initComponents();
this.setFocusable(true);
}
private void addThumbnails(ThumbnailsWrapper thumbnailWrapper) {
/**
* Add the thumbnails to the panel.
*
* @param thumbnailWrapper
*/
private void addThumbnails(VideoThumbnailsWrapper thumbnailWrapper) {
imagePanel.removeAll();
GridBagConstraints gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 0;
@ -81,8 +99,6 @@ public final class ThumbnailPanel extends javax.swing.JPanel implements ListCell
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(
@ -112,8 +128,8 @@ public final class ThumbnailPanel extends javax.swing.JPanel implements ListCell
// End of variables declaration//GEN-END:variables
@Override
public Component getListCellRendererComponent(JList<? extends ThumbnailsWrapper> list, ThumbnailsWrapper value, int index, boolean isSelected, boolean cellHasFocus) {
fileInfoLabel.setText(value.getFileInfo());
public Component getListCellRendererComponent(JList<? extends VideoThumbnailsWrapper> list, VideoThumbnailsWrapper value, int index, boolean isSelected, boolean cellHasFocus) {
fileInfoLabel.setText(value.getFilePath());
addThumbnails(value);
imagePanel.setBackground(isSelected ? SELECTION_COLOR : list.getBackground());
setBackground(isSelected ? SELECTION_COLOR : list.getBackground());

View File

@ -35,14 +35,14 @@
</Property>
<Property name="selectionMode" type="int" value="0"/>
<Property name="cellRenderer" type="javax.swing.ListCellRenderer" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new ThumbnailPanel()" type="code"/>
<Connection code="new org.sleuthkit.autopsy.filequery.VideoThumbnailPanel()" type="code"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;ThumbnailsWrapper&gt;"/>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;org.sleuthkit.autopsy.filequery.VideoThumbnailsWrapper&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>
</Form>

View File

@ -1,7 +1,20 @@
/*
* 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.
* Autopsy
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
@ -10,13 +23,13 @@ import javax.swing.event.ListSelectionListener;
import org.sleuthkit.datamodel.AbstractFile;
/**
* A JPanel to display video thumbnails.
*
* @author wschaefer
*/
public class VideoThumbnailViewer extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private final DefaultListModel<ThumbnailsWrapper> thumbnailListModel = new DefaultListModel<>();
private final DefaultListModel<VideoThumbnailsWrapper> thumbnailListModel = new DefaultListModel<>();
/**
* Creates new form VideoThumbnailViewer
@ -25,10 +38,21 @@ public class VideoThumbnailViewer extends javax.swing.JPanel {
initComponents();
}
/**
* Add a selection listener to the list of thumbnails being displayed.
*
* @param listener The ListSelectionListener to add to the selection model.
*/
void addListSelectionListener(ListSelectionListener listener) {
thumbnailList.getSelectionModel().addListSelectionListener(listener);
}
/**
* Get the AbstractFile associated with the selected thumbnails.
*
* @return The AbstractFile associated with the selected thumbnails, or null
* if no thumnails are selected.
*/
AbstractFile getSelectedFile() {
if (thumbnailList.getSelectedIndex() == -1) {
return null;
@ -37,13 +61,22 @@ public class VideoThumbnailViewer extends javax.swing.JPanel {
}
}
/**
* Clear the list of thumbnails being displayed.
*/
void clearViewer() {
synchronized (this) {
thumbnailListModel.removeAllElements();
}
}
void addRow(ThumbnailsWrapper thumbnailWrapper) {
/**
* Add thumbnails for a video to the panel.
*
* @param thumbnailWrapper The object which contains the thumbnails which
* will be displayed.
*/
void addRow(VideoThumbnailsWrapper thumbnailWrapper) {
synchronized (this) {
thumbnailListModel.addElement(thumbnailWrapper);
}
@ -65,7 +98,7 @@ public class VideoThumbnailViewer extends javax.swing.JPanel {
thumbnailList.setModel(thumbnailListModel);
thumbnailList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
thumbnailList.setCellRenderer(new ThumbnailPanel());
thumbnailList.setCellRenderer(new VideoThumbnailPanel());
thumbnailListScrollPane.setViewportView(thumbnailList);
add(thumbnailListScrollPane, java.awt.BorderLayout.CENTER);
@ -73,7 +106,7 @@ public class VideoThumbnailViewer extends javax.swing.JPanel {
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JList<ThumbnailsWrapper> thumbnailList;
private javax.swing.JList<VideoThumbnailsWrapper> thumbnailList;
private javax.swing.JScrollPane thumbnailListScrollPane;
// End of variables declaration//GEN-END:variables

View File

@ -25,30 +25,59 @@ import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.TskCoreException;
/**
*
* @author wschaefer
* Class to wrap all the information necessary for video thumbnails to be
* displayed.
*/
public class ThumbnailsWrapper {
public class VideoThumbnailsWrapper {
private final List<Image> thumbnails;
private final AbstractFile abstractFile;
private final int[] timeStamps;
public ThumbnailsWrapper(List<Image> thumbnails, int[] timeStamps, AbstractFile file) {
/**
* Construct a new VideoThumbnailsWrapper.
*
* @param thumbnails The list of Images which are the thumbnails for the
* video.
* @param timeStamps An array containing the time in milliseconds into the
* video that each thumbnail created for.
* @param file The AbstractFile which represents the video file which
* the thumbnails were created for.
*/
public VideoThumbnailsWrapper(List<Image> thumbnails, int[] timeStamps, AbstractFile file) {
this.thumbnails = thumbnails;
this.timeStamps = timeStamps;
this.abstractFile = file;
}
/**
* Get the AbstractFile which represents the video file which the thumbnails
* were created for.
*
* @return The AbstractFile which represents the video file which the
* thumbnails were created for.
*/
AbstractFile getAbstractFile() {
return abstractFile;
}
/**
* Get the array containing thumbnail timestamps. Each timestamp is stored
* as the number of milliseconds into the video each thumbnail was created
* at.
*
* @return The array of timestamps in milliseconds from start of video.
*/
int[] getTimeStamps() {
return timeStamps.clone();
}
String getFileInfo() {
/**
* Get the path to the file including the file name.
*
* @return The path to the file including the file name.
*/
String getFilePath() {
try {
return abstractFile.getUniquePath();
} catch (TskCoreException ingored) {
@ -56,6 +85,11 @@ public class ThumbnailsWrapper {
}
}
/**
* Get the list of thumbnails for the video.
*
* @return The list of Images which are the thumbnails for the video.
*/
List<Image> getThumbnails() {
return Collections.unmodifiableList(thumbnails);
}