- * Note that this class exposes a very simple get/set API that operates on the
- * user-defined file types as a complete set - there is no concept of adding,
- * editing or deleting file types singly. This works because this class is not
- * exposed outside of this ingest module package and is ONLY used in a very
- * specific paradigm. In this paradigm, there is a single modal writer of file
- * types in the form of a global settings panel that disables itself when ingest
- * is running so that multiple readers in the form of file ingest modules get a
- * consistent set of file type definitions.
- *
- * Thread-safe.
+ * A singleton manager for the custom file types defined by Autopsy and by
+ * users.
*/
-final class UserDefinedFileTypesManager {
+final class CustomFileTypesManager {
- private static final Logger logger = Logger.getLogger(UserDefinedFileTypesManager.class.getName());
- private static final String USER_DEFINED_TYPES_XML_FILE = "UserFileTypeDefinitions.xml"; //NON-NLS
- private static final String USER_DEFINED_TYPES_SERIALIZATION_FILE = "UserFileTypeDefinitions.settings";
+ private static final String XML_SETTINGS_FILE = "UserFileTypeDefinitions.xml"; //NON-NLS
+ private static final String SERIALIZED_SETTINGS_FILE = "UserFileTypeDefinitions.settings"; //NON-NLS
private static final String FILE_TYPES_TAG_NAME = "FileTypes"; //NON-NLS
private static final String FILE_TYPE_TAG_NAME = "FileType"; //NON-NLS
private static final String MIME_TYPE_TAG_NAME = "MimeType"; //NON-NLS
@@ -73,58 +55,39 @@ final class UserDefinedFileTypesManager {
private static final String BYTES_TAG_NAME = "Bytes"; //NON-NLS
private static final String OFFSET_TAG_NAME = "Offset"; //NON-NLS
private static final String RELATIVE_ATTRIBUTE = "RelativeToStart"; //NON-NLS
- private static final String INTERESTING_FILES_SET_TAG_NAME = "InterestingFileSset"; //NON-NLS
- private static final String ALERT_ATTRIBUTE = "alert"; //NON-NLS
- private static final String ENCODING_FOR_XML_FILE = "UTF-8"; //NON-NLS
- private static UserDefinedFileTypesManager instance;
-
- /**
- * File types to be persisted to the user-defined file type definitions file
- * are stored in this mapping of MIME types to file types. Access to this
- * map is guarded by the intrinsic lock of the user-defined file types
- * manager for thread-safety.
- */
+ private static CustomFileTypesManager instance;
private final List userDefinedFileTypes = new ArrayList<>();
+ private final List allFileTypes = new ArrayList<>();
/**
- * The combined set of user-defined file types and file types predefined by
- * Autopsy are stored in this mapping of MIME types to file types. This is
- * the current working set of file types. Access to this map is guarded by
- * the intrinsic lock of the user-defined file types manager for
- * thread-safety.
- */
- private final List fileTypes = new ArrayList<>();
-
- /**
- * Gets the singleton manager of user-defined file types characterized by
- * MIME type, signature, and optional membership in an interesting files
- * set.
+ * Gets the singleton manager of the custom file types defined by Autopsy
+ * and by users.
*
- * @return The user-defined file types manager singleton.
+ * @return The custom file types manager singleton.
*/
- synchronized static UserDefinedFileTypesManager getInstance() {
+ synchronized static CustomFileTypesManager getInstance() {
if (instance == null) {
- instance = new UserDefinedFileTypesManager();
+ instance = new CustomFileTypesManager();
}
return instance;
}
/**
- * Creates a manager of user-defined file types characterized by MIME type,
- * signature, and optional membership in an interesting files set.
+ * Constructs a manager for the custom file types defined by Autopsy and by
+ * users.
*/
- private UserDefinedFileTypesManager() {
+ private CustomFileTypesManager() {
}
/**
- * Gets both the predefined and the user-defined file types.
+ * Gets all of the custom file types defined by Autopsy and by users.
*
- * @return A mapping of file type names to file types, possibly empty.
+ * @return A list of file types, possibly empty.
*
- * @throws
- * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException
+ * @throws CustomFileTypesException if there is a problem accessing the
+ * file types.
*/
- synchronized List getFileTypes() throws UserDefinedFileTypesException {
+ synchronized List getFileTypes() throws CustomFileTypesException {
loadFileTypes();
/**
@@ -133,18 +96,18 @@ final class UserDefinedFileTypesManager {
* Collections.unmodifiableCollection() is not used here because this
* view of the file types is a snapshot.
*/
- return new ArrayList<>(fileTypes);
+ return new ArrayList<>(allFileTypes);
}
/**
- * Gets the user-defined file types.
+ * Gets the custom file types defined by users.
*
- * @return A mapping of file type names to file types, possibly empty.
+ * @return A list of file types, possibly empty.
*
- * @throws
- * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException
+ * @throws CustomFileTypesException if there is a problem accessing the
+ * file types.
*/
- synchronized List getUserDefinedFileTypes() throws UserDefinedFileTypesException {
+ synchronized List getUserDefinedFileTypes() throws CustomFileTypesException {
loadFileTypes();
/**
@@ -157,15 +120,15 @@ final class UserDefinedFileTypesManager {
}
/**
- * Loads the MIME type to file type mappings with predefined and
- * user-defined types.
+ * Loads or re-loads the custom file types defined by Autopsy and by users.
*
- * @throws
- * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException
+ * @throws CustomFileTypesException if there is a problem loading the
+ * file types.
*/
- private void loadFileTypes() throws UserDefinedFileTypesException {
- fileTypes.clear();
+ private void loadFileTypes() throws CustomFileTypesException {
+ allFileTypes.clear();
userDefinedFileTypes.clear();
+
/**
* Load the predefined types first so that they can be overwritten by
* any user-defined types with the same names.
@@ -175,156 +138,185 @@ final class UserDefinedFileTypesManager {
}
/**
- * Adds the predefined file types to the in-memory mappings of MIME types to
- * file types.
+ * Loads or re-loads the custom file types defined by Autopsy.
*
- * @throws
- * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException
+ * @throws CustomFileTypesException if there is a problem loading the
+ * file types.
*/
- private void loadPredefinedFileTypes() throws UserDefinedFileTypesException {
+ private void loadPredefinedFileTypes() throws CustomFileTypesException {
byte[] byteArray;
FileType fileType;
try {
+ /*
+ * Add type for xml.
+ */
List signatureList;
signatureList = new ArrayList<>();
- signatureList.add(new Signature(" newFileTypes) throws UserDefinedFileTypesException {
- String filePath = getFileTypeDefinitionsFilePath(USER_DEFINED_TYPES_SERIALIZATION_FILE);
+ synchronized void setUserDefinedFileTypes(List newFileTypes) throws CustomFileTypesException {
+ String filePath = getFileTypeDefinitionsFilePath(SERIALIZED_SETTINGS_FILE);
writeFileTypes(newFileTypes, filePath);
}
@@ -378,72 +368,68 @@ final class UserDefinedFileTypesManager {
}
/**
- * Writes a set of file types to a file.
+ * Writes a collection of custom file types to disk.
*
* @param fileTypes A collection of file types.
* @param filePath The path to the destination file.
*
- * @throws ParserConfigurationException
- * @throws IOException
- * @throws FileNotFoundException
- * @throws UnsupportedEncodingException
- * @throws TransformerException
+ * @throws CustomFileTypesException if there is a problem writing the
+ * file types.
*/
- private static void writeFileTypes(List fileTypes, String filePath) throws UserDefinedFileTypesException {
+ private static void writeFileTypes(List fileTypes, String filePath) throws CustomFileTypesException {
try (NbObjectOutputStream out = new NbObjectOutputStream(new FileOutputStream(filePath))) {
UserDefinedFileTypesSettings settings = new UserDefinedFileTypesSettings(fileTypes);
out.writeObject(settings);
} catch (IOException ex) {
- throw new UserDefinedFileTypesException(String.format("Failed to write settings to %s", filePath), ex);
+ throw new CustomFileTypesException(String.format("Failed to write settings to %s", filePath), ex); //NON-NLS
}
}
/**
- * Reads the file types
+ * Reads a collection of custom file types from disk.
*
- * @param filePath the file path where the file types are to be read
+ * @param filePath The path of the file from which the custom file types are
+ * to be read.
*
- * @return the file types
+ * @return The custom file types.
*
- * @throws ParserConfigurationException If the file cannot be read
+ * @throws CustomFileTypesException if there is a problem reading the
+ * file types.
*/
- private static List readFileTypesSerialized() throws UserDefinedFileTypesException {
- File serializedDefs = new File(getFileTypeDefinitionsFilePath(USER_DEFINED_TYPES_SERIALIZATION_FILE));
+ private static List readSerializedFileTypes() throws CustomFileTypesException {
+ File serializedDefs = new File(getFileTypeDefinitionsFilePath(SERIALIZED_SETTINGS_FILE));
try {
try (NbObjectInputStream in = new NbObjectInputStream(new FileInputStream(serializedDefs))) {
UserDefinedFileTypesSettings filesSetsSettings = (UserDefinedFileTypesSettings) in.readObject();
return filesSetsSettings.getUserDefinedFileTypes();
}
} catch (IOException | ClassNotFoundException ex) {
- throw new UserDefinedFileTypesException("Couldn't read serialized settings.", ex);
+ throw new CustomFileTypesException("Couldn't read serialized settings.", ex); //NON-NLS
}
}
/**
- * Provides a mechanism for reading a set of file type definitions from an
- * XML file.
+ * Provides a mechanism for reading a set of custom file type definitions
+ * from an XML file.
*/
private static class XMLDefinitionsReader {
/**
- * Reads a set of file type definitions from an XML file.
+ * Reads a set of custom file type definitions from an XML file.
*
* @param filePath The path to the XML file.
*
- * @return A collection of file types read from the XML file.
+ * @return A collection of custom file types read from the XML file.
+ *
+ * @throws IOException if there is problem reading the
+ * XML file.
+ * @throws SAXException if there is a problem parsing
+ * the XML file.
+ * @throws ParserConfigurationException if there is a problem parsing
+ * the XML file.
*/
private static List readFileTypes(String filePath) throws IOException, SAXException, ParserConfigurationException {
List fileTypes = new ArrayList<>();
- /*
- * RC: Commenting out the loadDocument overload that validates
- * against the XSD is a temp fix for a failure to provide an upgrade
- * path when the RelativeToStart attribute was added to the
- * Signature element. The upgrade path can be supplied, but the plan
- * is to replace the use of XML with object serialization for the
- * settings, so it may not be worth the effort.
- */
- // private static final String FILE_TYPE_DEFINITIONS_SCHEMA_FILE = "FileTypes.xsd"; //NON-NLS
- // Document doc = XMLUtil.loadDocument(filePath, UserDefinedFileTypesManager.class, FILE_TYPE_DEFINITIONS_SCHEMA_FILE);
Document doc = XMLUtil.loadDocument(filePath);
if (doc != null) {
Element fileTypesElem = doc.getDocumentElement();
@@ -460,14 +446,16 @@ final class UserDefinedFileTypesManager {
}
/**
- * Gets a file type definition from a file type XML element.
+ * Gets a custom file type definition from a file type XML element.
*
* @param fileTypeElem The XML element.
*
* @return A file type object.
*
- * @throws IllegalArgumentException
- * @throws NumberFormatException
+ * @throws IllegalArgumentException if there is a problem parsing the
+ * file type.
+ * @throws NumberFormatException if there is a problem parsing the
+ * file type.
*/
private static FileType parseFileType(Element fileTypeElem) throws IllegalArgumentException, NumberFormatException {
String mimeType = XMLDefinitionsReader.parseMimeType(fileTypeElem);
@@ -522,35 +510,6 @@ final class UserDefinedFileTypesManager {
return new Signature(signatureBytes, offset, signatureType, isRelativeToStart);
}
- /**
- * Gets the interesting files set name from a file type XML element.
- *
- * @param fileTypeElem The XML element.
- *
- * @return The files set name, possibly empty.
- */
- private static String parseInterestingFilesSet(Element fileTypeElem) {
- String filesSetName = "";
- NodeList filesSetElems = fileTypeElem.getElementsByTagName(INTERESTING_FILES_SET_TAG_NAME);
- if (filesSetElems.getLength() > 0) {
- Element filesSetElem = (Element) filesSetElems.item(0);
- filesSetName = filesSetElem.getTextContent();
- }
- return filesSetName;
- }
-
- /**
- * Gets the alert attribute from a file type XML element.
- *
- * @param fileTypeElem The XML element.
- *
- * @return True or false;
- */
- private static boolean parseAlert(Element fileTypeElem) {
- String alertAttribute = fileTypeElem.getAttribute(ALERT_ATTRIBUTE);
- return Boolean.parseBoolean(alertAttribute);
- }
-
/**
* Gets the text content of a single child element.
*
@@ -570,7 +529,7 @@ final class UserDefinedFileTypesManager {
}
/**
- * Private constructor suppresses creation of instanmces of this utility
+ * Private constructor suppresses creation of instances of this utility
* class.
*/
private XMLDefinitionsReader() {
@@ -579,36 +538,17 @@ final class UserDefinedFileTypesManager {
}
/**
- * Logs an exception, bundles the exception with a simple message in a
- * uniform exception type, and throws the wrapper exception.
- *
- * @param ex The exception to wrap.
- * @param messageKey A key into the bundle file that maps to the desired
- * message.
- *
- * @throws
- * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException
+ * .An exception thrown by the custom file types manager.
*/
- private void throwUserDefinedFileTypesException(Exception ex, String messageKey) throws UserDefinedFileTypesException {
- String message = NbBundle.getMessage(UserDefinedFileTypesManager.class, messageKey);
- logger.log(Level.SEVERE, message, ex);
- throw new UserDefinedFileTypesException(message, ex);
- }
-
- /**
- * Used to translate more implementation-details-specific exceptions (which
- * are logged by this class) into more generic exceptions for propagation to
- * clients of the user-defined file types manager.
- */
- static class UserDefinedFileTypesException extends Exception {
+ static class CustomFileTypesException extends Exception {
private static final long serialVersionUID = 1L;
- UserDefinedFileTypesException(String message) {
+ CustomFileTypesException(String message) {
super(message);
}
- UserDefinedFileTypesException(String message, Throwable throwable) {
+ CustomFileTypesException(String message, Throwable throwable) {
super(message, throwable);
}
}
diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java
index e33740805f..bb65ad7376 100644
--- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java
+++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java
@@ -60,8 +60,8 @@ public class FileTypeDetector {
*/
public FileTypeDetector() throws FileTypeDetectorInitException {
try {
- userDefinedFileTypes = UserDefinedFileTypesManager.getInstance().getFileTypes();
- } catch (UserDefinedFileTypesManager.UserDefinedFileTypesException ex) {
+ userDefinedFileTypes = CustomFileTypesManager.getInstance().getFileTypes();
+ } catch (CustomFileTypesManager.CustomFileTypesException ex) {
throw new FileTypeDetectorInitException(Bundle.CouldNotInitializeFileTypeDetector(), ex);
}
}
diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form
index 42e8e8ebce..6c562d5325 100644
--- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form
+++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form
@@ -3,10 +3,10 @@
+
@@ -44,11 +42,11 @@
-
-
-
+
+
+
-
+
@@ -81,209 +79,241 @@
-
+
+
+
+
+
+
-
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
+
+
-
-
-
-
-
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
-
-
-
-
-
-
-
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
+
-
-
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java
index 3db4cc5d68..72e45983ba 100644
--- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java
@@ -35,7 +35,7 @@ import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
import org.sleuthkit.autopsy.modules.filetypeid.FileType.Signature;
-import org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException;
+import org.sleuthkit.autopsy.modules.filetypeid.CustomFileTypesManager.CustomFileTypesException;
/**
* A panel to allow a user to make custom file type definitions. In addition to
@@ -207,12 +207,12 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
@Override
public void load() {
try {
- fileTypes = UserDefinedFileTypesManager.getInstance().getUserDefinedFileTypes();
+ fileTypes = CustomFileTypesManager.getInstance().getUserDefinedFileTypes();
updateFileTypesListModel();
if (!typesListModel.isEmpty()) {
typesList.setSelectedIndex(0);
}
- } catch (UserDefinedFileTypesException ex) {
+ } catch (CustomFileTypesException ex) {
JOptionPane.showMessageDialog(null,
ex.getLocalizedMessage(),
NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.loadFailed.title"),
@@ -266,8 +266,8 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
@Override
public void store() {
try {
- UserDefinedFileTypesManager.getInstance().setUserDefinedFileTypes(fileTypes);
- } catch (UserDefinedFileTypesManager.UserDefinedFileTypesException ex) {
+ CustomFileTypesManager.getInstance().setUserDefinedFileTypes(fileTypes);
+ } catch (CustomFileTypesManager.CustomFileTypesException ex) {
JOptionPane.showMessageDialog(null,
ex.getLocalizedMessage(),
NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.storeFailed.title"),
@@ -304,21 +304,22 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
ingestRunningWarningLabel = new javax.swing.JLabel();
jLabel3 = new javax.swing.JLabel();
+ jScrollPane2 = new javax.swing.JScrollPane();
jSplitPane1 = new javax.swing.JSplitPane();
jPanel1 = new javax.swing.JPanel();
jLabel2 = new javax.swing.JLabel();
typesScrollPane = new javax.swing.JScrollPane();
- typesList = new javax.swing.JList();
+ typesList = new javax.swing.JList<>();
deleteTypeButton = new javax.swing.JButton();
newTypeButton = new javax.swing.JButton();
editTypeButton = new javax.swing.JButton();
jPanel2 = new javax.swing.JPanel();
jLabel1 = new javax.swing.JLabel();
jScrollPane1 = new javax.swing.JScrollPane();
- signatureList = new javax.swing.JList();
+ signatureList = new javax.swing.JList<>();
- setMaximumSize(new java.awt.Dimension(552, 297));
- setPreferredSize(new java.awt.Dimension(552, 297));
+ setMaximumSize(new java.awt.Dimension(752, 507));
+ setPreferredSize(new java.awt.Dimension(752, 507));
ingestRunningWarningLabel.setFont(ingestRunningWarningLabel.getFont().deriveFont(ingestRunningWarningLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
ingestRunningWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/modules/filetypeid/warning16.png"))); // NOI18N
@@ -327,6 +328,12 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
jLabel3.setFont(jLabel3.getFont().deriveFont(jLabel3.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.jLabel3.text")); // NOI18N
+ jScrollPane2.setMinimumSize(new java.awt.Dimension(300, 100));
+
+ jSplitPane1.setMinimumSize(new java.awt.Dimension(558, 285));
+
+ jPanel1.setMinimumSize(new java.awt.Dimension(362, 283));
+
jLabel2.setFont(jLabel2.getFont().deriveFont(jLabel2.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.jLabel2.text")); // NOI18N
@@ -384,7 +391,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
.addGap(12, 12, 12)
.addComponent(jLabel2)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(typesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 367, Short.MAX_VALUE)
+ .addComponent(typesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 385, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(newTypeButton)
@@ -397,6 +404,8 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
jSplitPane1.setLeftComponent(jPanel1);
+ jPanel2.setMinimumSize(new java.awt.Dimension(79, 283));
+
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.jLabel1.text")); // NOI18N
signatureList.setModel(new javax.swing.AbstractListModel() {
@@ -404,6 +413,8 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
public int getSize() { return signatures.length; }
public Signature getElementAt(int i) { return signatures[i]; }
});
+ signatureList.setMaximumSize(new java.awt.Dimension(32767, 32767));
+ signatureList.setPreferredSize(null);
jScrollPane1.setViewportView(signatureList);
javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
@@ -415,8 +426,8 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel2Layout.createSequentialGroup()
.addComponent(jLabel1)
- .addGap(0, 0, Short.MAX_VALUE))
- .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 385, Short.MAX_VALUE))
+ .addGap(100, 100, 100))
+ .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
.addContainerGap())
);
jPanel2Layout.setVerticalGroup(
@@ -425,12 +436,14 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
.addContainerGap()
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 370, Short.MAX_VALUE)
+ .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 388, Short.MAX_VALUE)
.addGap(40, 40, 40))
);
jSplitPane1.setRightComponent(jPanel2);
+ jScrollPane2.setViewportView(jSplitPane1);
+
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
@@ -440,10 +453,9 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(ingestRunningWarningLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(jLabel3, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addComponent(jSplitPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 782, Short.MAX_VALUE))
+ .addComponent(jLabel3, javax.swing.GroupLayout.DEFAULT_SIZE, 753, Short.MAX_VALUE)
.addContainerGap())))
+ .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@@ -451,10 +463,10 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
.addGap(6, 6, 6)
.addComponent(jLabel3)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 443, Short.MAX_VALUE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(ingestRunningWarningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addContainerGap())
+ .addGap(12, 12, 12))
);
}// //GEN-END:initComponents
@@ -501,6 +513,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JScrollPane jScrollPane1;
+ private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JSplitPane jSplitPane1;
private javax.swing.JButton newTypeButton;
private javax.swing.JList signatureList;
diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties
index 9e7efa38d6..70de8af545 100644
--- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties
+++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties
@@ -160,14 +160,14 @@ HashDbManager.saveErrorExceptionMsg=Error saving hash configuration
HashLookupSettingsPanel.optionsLabel.text=Options
HashLookupSettingsPanel.jButton3.text=Import Database
HashLookupSettingsPanel.indexPathLabelLabel.text=Index Path:
-HashLookupSettingsPanel.createDatabaseButton.text=Create Database
+HashLookupSettingsPanel.createDatabaseButton.text=Create DB
HashLookupSettingsPanel.jLabel6.text=Type:
HashLookupSettingsPanel.jLabel4.text=Location:
HashLookupSettingsPanel.jLabel2.text=Name:
HashLookupSettingsPanel.indexPathLabel.text=No database selected
HashLookupSettingsPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes.
-HashLookupSettingsPanel.deleteDatabaseButton.text=Delete Database
-HashLookupSettingsPanel.importDatabaseButton.text=Import Database
+HashLookupSettingsPanel.deleteDatabaseButton.text=Delete DB
+HashLookupSettingsPanel.importDatabaseButton.text=Import DB
HashLookupSettingsPanel.hashDatabasesLabel.text=Hash Databases:
HashLookupSettingsPanel.nameLabel.text=Hash Set Name:
HashLookupSettingsPanel.informationLabel.text=Information
@@ -208,4 +208,4 @@ AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.invaliHash.msg=Inv
AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.noHashesToAdd=There are no hashes to add.
AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.success={0} Hashes added successfully.
AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.errorAddingValidHash=There is an error adding valid hashes.
-AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.errorAddingValidHash.msg=Error adding valid hashes to the database:
\ No newline at end of file
+AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.errorAddingValidHash.msg=Error adding valid hashes to the database:
diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form
index 5cd2c50c5e..4a547413cf 100644
--- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form
+++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form
@@ -53,10 +53,10 @@
-
+
-
+
@@ -74,18 +74,14 @@
-
-
-
-
+
+
-
-
@@ -98,7 +94,7 @@
-
+
@@ -106,16 +102,22 @@
-
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
@@ -124,7 +126,7 @@
-
+
@@ -140,27 +142,23 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
+
@@ -168,26 +166,22 @@
-
-
-
-
-
+
-
+
-
+
@@ -239,16 +233,15 @@
-
+
-
+
+
-
-
-
+
diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java
index 0eefefba17..824be8cb1a 100644
--- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java
@@ -516,10 +516,10 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
jButton3.setFont(jButton3.getFont().deriveFont(jButton3.getFont().getStyle() & ~java.awt.Font.BOLD, 14));
org.openide.awt.Mnemonics.setLocalizedText(jButton3, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.jButton3.text")); // NOI18N
- setMinimumSize(new java.awt.Dimension(700, 430));
- setPreferredSize(new java.awt.Dimension(700, 430));
+ setMinimumSize(new java.awt.Dimension(700, 500));
+ setPreferredSize(new java.awt.Dimension(700, 500));
- jPanel1.setPreferredSize(new java.awt.Dimension(671, 430));
+ jPanel1.setPreferredSize(new java.awt.Dimension(671, 400));
ingestWarningLabel.setFont(ingestWarningLabel.getFont().deriveFont(ingestWarningLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
ingestWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/modules/hashdatabase/warning16.png"))); // NOI18N
@@ -652,12 +652,17 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
.addContainerGap()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(jPanel1Layout.createSequentialGroup()
- .addComponent(createDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 137, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addComponent(importDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE))
- .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 275, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addComponent(createDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 102, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(importDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 103, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(deleteDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 102, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addGap(0, 84, Short.MAX_VALUE))
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addGap(1, 1, 1)
+ .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)))
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGap(10, 10, 10)
@@ -665,7 +670,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(informationLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(informationSeparator))
+ .addComponent(informationSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 305, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(ingestWarningLabel)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
.addGap(10, 10, 10)
@@ -679,30 +684,24 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
.addComponent(indexPathLabelLabel))
.addGap(10, 10, 10)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(hashDbTypeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addComponent(hashDbLocationLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addComponent(indexPathLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addComponent(hashDbIndexStatusLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addComponent(addHashesToDatabaseButton)
- .addGap(0, 0, Short.MAX_VALUE))))
+ .addComponent(hashDbTypeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(hashDbLocationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(indexPathLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(hashDbIndexStatusLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(addHashesToDatabaseButton)))
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(nameLabel)
.addGap(53, 53, 53)
- .addComponent(hashDbNameLabel)
- .addGap(0, 0, Short.MAX_VALUE))))
+ .addComponent(hashDbNameLabel))))
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(optionsLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(optionsSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 324, javax.swing.GroupLayout.PREFERRED_SIZE))))
.addGroup(jPanel1Layout.createSequentialGroup()
.addGap(23, 23, 23)
- .addComponent(sendIngestMessagesCheckBox)
- .addGap(0, 0, Short.MAX_VALUE))))
+ .addComponent(sendIngestMessagesCheckBox))))
.addGroup(jPanel1Layout.createSequentialGroup()
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(hashDatabasesLabel)
- .addComponent(deleteDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 137, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addComponent(hashDatabasesLabel)
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
);
@@ -751,14 +750,13 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
.addComponent(sendIngestMessagesCheckBox)
.addGap(18, 18, 18)
.addComponent(ingestWarningLabel))
- .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 304, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 425, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(importDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addComponent(createDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(deleteDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addContainerGap(33, Short.MAX_VALUE))
+ .addComponent(createDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(deleteDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGap(48, 48, 48))
);
jScrollPane2.setViewportView(jPanel1);
@@ -767,16 +765,13 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(layout.createSequentialGroup()
- .addContainerGap()
- .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 690, Short.MAX_VALUE))
+ .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 800, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
- .addContainerGap()
- .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 410, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 537, Short.MAX_VALUE)
+ .addContainerGap())
);
}// //GEN-END:initComponents
diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingItemDefsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingItemDefsPanel.form
index e55060f6a1..483d6e386e 100755
--- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingItemDefsPanel.form
+++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingItemDefsPanel.form
@@ -29,15 +29,12 @@
-
-
-
-
+
-
+
@@ -65,138 +62,145 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
-
+
-
+
-
-
-
+
+
+
@@ -205,23 +209,23 @@
-
+
-
+
-
+
-
+
-
-
-
+
+
+
-
+
@@ -235,36 +239,37 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
@@ -405,6 +410,12 @@
+
+
+
+
+
+
@@ -778,6 +789,12 @@
+
+
+
+
+
+
@@ -802,9 +819,12 @@
-
+
+
+
+
diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingItemDefsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingItemDefsPanel.java
index dba9091bb7..3669612f16 100755
--- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingItemDefsPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingItemDefsPanel.java
@@ -208,6 +208,10 @@ final class InterestingItemDefsPanel extends IngestModuleGlobalSettingsPanel imp
this.filesRadioButton.setSelected(true);
this.rulePathConditionTextField.setText("");
this.rulePathConditionRegexCheckBox.setSelected(false);
+ this.mimeTypeComboBox.setSelectedIndex(0);
+ this.equalitySignComboBox.setSelectedIndex(2);
+ this.fileSizeUnitComboBox.setSelectedIndex(1);
+ this.fileSizeSpinner.setValue(0);
this.newRuleButton.setEnabled(!this.setsListModel.isEmpty());
this.editRuleButton.setEnabled(false);
this.deleteRuleButton.setEnabled(false);
@@ -317,11 +321,11 @@ final class InterestingItemDefsPanel extends IngestModuleGlobalSettingsPanel imp
if (fileSizeCondition != null) {
InterestingItemDefsPanel.this.fileSizeUnitComboBox.setSelectedItem(fileSizeCondition.getUnit().getName());
InterestingItemDefsPanel.this.equalitySignComboBox.setSelectedItem(fileSizeCondition.getComparator().getSymbol());
- InterestingItemDefsPanel.this.jSpinner1.setValue(fileSizeCondition.getSizeValue());
+ InterestingItemDefsPanel.this.fileSizeSpinner.setValue(fileSizeCondition.getSizeValue());
} else {
InterestingItemDefsPanel.this.fileSizeUnitComboBox.setSelectedIndex(1);
InterestingItemDefsPanel.this.equalitySignComboBox.setSelectedIndex(2);
- InterestingItemDefsPanel.this.jSpinner1.setValue(0);
+ InterestingItemDefsPanel.this.fileSizeSpinner.setValue(0);
}
// Enable the new, edit and delete rule buttons.
@@ -493,12 +497,12 @@ final class InterestingItemDefsPanel extends IngestModuleGlobalSettingsPanel imp
editRuleButton = new javax.swing.JButton();
rulesListLabel = new javax.swing.JLabel();
rulesListScrollPane = new javax.swing.JScrollPane();
- rulesList = new javax.swing.JList();
+ rulesList = new javax.swing.JList<>();
setDescScrollPanel = new javax.swing.JScrollPane();
setDescriptionTextArea = new javax.swing.JTextArea();
editSetButton = new javax.swing.JButton();
setsListScrollPane = new javax.swing.JScrollPane();
- setsList = new javax.swing.JList();
+ setsList = new javax.swing.JList<>();
fileNameExtensionRadioButton = new javax.swing.JRadioButton();
jLabel3 = new javax.swing.JLabel();
fileNameTextField = new javax.swing.JTextField();
@@ -521,10 +525,10 @@ final class InterestingItemDefsPanel extends IngestModuleGlobalSettingsPanel imp
jScrollPane2 = new javax.swing.JScrollPane();
jTextArea1 = new javax.swing.JTextArea();
jLabel7 = new javax.swing.JLabel();
- mimeTypeComboBox = new javax.swing.JComboBox();
+ mimeTypeComboBox = new javax.swing.JComboBox<>();
jLabel8 = new javax.swing.JLabel();
equalitySignComboBox = new javax.swing.JComboBox();
- jSpinner1 = new javax.swing.JSpinner();
+ fileSizeSpinner = new javax.swing.JSpinner();
fileSizeUnitComboBox = new javax.swing.JComboBox();
setFont(getFont().deriveFont(getFont().getStyle() & ~java.awt.Font.BOLD, 11));
@@ -578,6 +582,8 @@ final class InterestingItemDefsPanel extends IngestModuleGlobalSettingsPanel imp
setDescriptionTextArea.setFont(setDescriptionTextArea.getFont().deriveFont(setDescriptionTextArea.getFont().getStyle() & ~java.awt.Font.BOLD, 13));
setDescriptionTextArea.setLineWrap(true);
setDescriptionTextArea.setRows(2);
+ setDescriptionTextArea.setMinimumSize(new java.awt.Dimension(10, 22));
+ setDescriptionTextArea.setPreferredSize(new java.awt.Dimension(14, 40));
setDescScrollPanel.setViewportView(setDescriptionTextArea);
editSetButton.setFont(editSetButton.getFont().deriveFont(editSetButton.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
@@ -717,13 +723,16 @@ final class InterestingItemDefsPanel extends IngestModuleGlobalSettingsPanel imp
mimeTypeComboBox.setEditable(true);
mimeTypeComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] {""}));
mimeTypeComboBox.setEnabled(false);
+ mimeTypeComboBox.setMinimumSize(new java.awt.Dimension(0, 20));
+ mimeTypeComboBox.setPreferredSize(new java.awt.Dimension(12, 20));
org.openide.awt.Mnemonics.setLocalizedText(jLabel8, org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.jLabel8.text")); // NOI18N
equalitySignComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "=", ">", "≥", "<", "≤" }));
equalitySignComboBox.setEnabled(false);
- jSpinner1.setEnabled(false);
+ fileSizeSpinner.setEnabled(false);
+ fileSizeSpinner.setMinimumSize(new java.awt.Dimension(2, 20));
fileSizeUnitComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { Bundle.InterestingItemDefsPanel_bytes(), Bundle.InterestingItemDefsPanel_kiloBytes(), Bundle.InterestingItemDefsPanel_megaBytes(), Bundle.InterestingItemDefsPanel_gigaBytes() }));
fileSizeUnitComboBox.setEnabled(false);
@@ -732,95 +741,97 @@ final class InterestingItemDefsPanel extends IngestModuleGlobalSettingsPanel imp
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addContainerGap()
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(setsListLabel)
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
- .addComponent(setsListScrollPane, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 314, Short.MAX_VALUE)
- .addComponent(jScrollPane2, javax.swing.GroupLayout.Alignment.LEADING))
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addComponent(newSetButton, javax.swing.GroupLayout.PREFERRED_SIZE, 93, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
- .addComponent(editSetButton, javax.swing.GroupLayout.PREFERRED_SIZE, 89, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
- .addComponent(deleteSetButton)))
- .addGap(18, 18, 18)
- .addComponent(separator, javax.swing.GroupLayout.PREFERRED_SIZE, 6, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addGap(12, 12, 12)
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addComponent(jLabel1)
- .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addComponent(jLabel2)
- .addGap(27, 27, 27)
- .addComponent(filesRadioButton, javax.swing.GroupLayout.PREFERRED_SIZE, 47, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(dirsRadioButton)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(bothRadioButton)
- .addGap(27, 27, 27))))
.addGroup(jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
- .addGap(380, 380, 380)
+ .addGap(360, 360, 360)
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(rulesListLabel)
+ .addComponent(jLabel5)
+ .addComponent(ignoreKnownFilesCheckbox)
+ .addComponent(jLabel6))
+ .addGap(0, 0, Short.MAX_VALUE))
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addContainerGap()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(jLabel3)
- .addComponent(jLabel7)
- .addComponent(jLabel8))
- .addGap(6, 6, 6))
- .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
- .addComponent(jLabel4)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)))
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
- .addComponent(rulePathConditionTextField, javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel1Layout.createSequentialGroup()
- .addComponent(equalitySignComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 38, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(jSpinner1, javax.swing.GroupLayout.PREFERRED_SIZE, 104, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(fileSizeUnitComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 83, javax.swing.GroupLayout.PREFERRED_SIZE))
- .addComponent(mimeTypeComboBox, javax.swing.GroupLayout.Alignment.LEADING, 0, 245, Short.MAX_VALUE)
- .addComponent(fileNameTextField)))
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addGap(360, 360, 360)
- .addComponent(rulesListLabel))
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addGap(360, 360, 360)
- .addComponent(jLabel5))
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addGap(360, 360, 360)
- .addComponent(ignoreKnownFilesCheckbox))
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addGap(360, 360, 360)
- .addComponent(setDescScrollPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 336, javax.swing.GroupLayout.PREFERRED_SIZE))
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addGap(360, 360, 360)
- .addComponent(jLabel6))
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addGap(360, 360, 360)
- .addComponent(rulesListScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 336, javax.swing.GroupLayout.PREFERRED_SIZE))
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addGap(360, 360, 360)
- .addComponent(newRuleButton)
- .addGap(18, 18, 18)
- .addComponent(editRuleButton)
- .addGap(18, 18, 18)
- .addComponent(deleteRuleButton))
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addGap(456, 456, 456)
+ .addComponent(setsListLabel)
+ .addComponent(setsListScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 314, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 314, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGap(18, 18, 18)
+ .addComponent(separator, javax.swing.GroupLayout.PREFERRED_SIZE, 6, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addComponent(newSetButton, javax.swing.GroupLayout.PREFERRED_SIZE, 93, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addComponent(editSetButton, javax.swing.GroupLayout.PREFERRED_SIZE, 89, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addComponent(deleteSetButton)))
+ .addGap(12, 12, 12)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
- .addComponent(fileNameRadioButton)
- .addGap(4, 4, 4)
- .addComponent(fileNameExtensionRadioButton)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
- .addComponent(fileNameRegexCheckbox))
- .addComponent(rulePathConditionRegexCheckBox))))
- .addGap(20, 20, 20))
+ .addGap(20, 20, 20)
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(jLabel3)
+ .addComponent(jLabel2))
+ .addGap(6, 6, 6))
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
+ .addComponent(jLabel4)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)))
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+ .addComponent(rulePathConditionTextField, javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(fileNameTextField)))
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(jLabel7)
+ .addComponent(jLabel8))
+ .addGap(6, 6, 6)
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+ .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel1Layout.createSequentialGroup()
+ .addComponent(equalitySignComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 38, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(fileSizeSpinner, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(fileSizeUnitComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 83, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addGap(8, 8, 8))
+ .addComponent(mimeTypeComboBox, javax.swing.GroupLayout.Alignment.LEADING, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))))
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(setDescScrollPanel)
+ .addComponent(rulesListScrollPane))
+ .addGap(7, 7, 7))
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(jLabel1)
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addGap(92, 92, 92)
+ .addComponent(filesRadioButton, javax.swing.GroupLayout.PREFERRED_SIZE, 47, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addComponent(dirsRadioButton)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(bothRadioButton))
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addComponent(newRuleButton)
+ .addGap(18, 18, 18)
+ .addComponent(editRuleButton)
+ .addGap(18, 18, 18)
+ .addComponent(deleteRuleButton))
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addGap(96, 96, 96)
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addComponent(fileNameRadioButton)
+ .addGap(4, 4, 4)
+ .addComponent(fileNameExtensionRadioButton)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addComponent(fileNameRegexCheckbox))
+ .addComponent(rulePathConditionRegexCheckBox))))
+ .addGap(4, 4, 4)))))
+ .addGap(23, 23, 23))
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@@ -835,7 +846,7 @@ final class InterestingItemDefsPanel extends IngestModuleGlobalSettingsPanel imp
.addGap(18, 18, 18)
.addComponent(setsListLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(setsListScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 199, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(setsListScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 354, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(newSetButton)
@@ -852,8 +863,8 @@ final class InterestingItemDefsPanel extends IngestModuleGlobalSettingsPanel imp
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(rulesListLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(rulesListScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 64, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(rulesListScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 67, Short.MAX_VALUE)
+ .addGap(10, 10, 10)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(newRuleButton)
.addComponent(editRuleButton)
@@ -874,24 +885,25 @@ final class InterestingItemDefsPanel extends IngestModuleGlobalSettingsPanel imp
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(fileNameRadioButton)
.addComponent(fileNameExtensionRadioButton)
- .addComponent(fileNameRegexCheckbox))))
- .addGap(14, 14, 14)
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(jLabel4)
- .addComponent(rulePathConditionTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE))
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(rulePathConditionRegexCheckBox)
- .addGap(10, 10, 10)
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(jLabel7)
- .addComponent(mimeTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
- .addGap(16, 16, 16)
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(jLabel8)
- .addComponent(equalitySignComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addComponent(jSpinner1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addComponent(fileSizeUnitComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
- .addContainerGap())
+ .addComponent(fileNameRegexCheckbox))
+ .addGap(14, 14, 14)
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(jLabel4)
+ .addComponent(rulePathConditionTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(rulePathConditionRegexCheckBox)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(jLabel7)
+ .addComponent(mimeTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGap(16, 16, 16)
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(jLabel8)
+ .addComponent(equalitySignComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(fileSizeSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(fileSizeUnitComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGap(13, 13, 13)))
+ .addGap(5, 5, 5))))
);
jPanel1Layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {deleteRuleButton, deleteSetButton, editRuleButton, editSetButton, newRuleButton, newSetButton});
@@ -902,13 +914,11 @@ final class InterestingItemDefsPanel extends IngestModuleGlobalSettingsPanel imp
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(layout.createSequentialGroup()
- .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 728, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addGap(0, 34, Short.MAX_VALUE))
+ .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 762, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 503, Short.MAX_VALUE)
+ .addComponent(jScrollPane1)
);
}// //GEN-END:initComponents
@@ -931,6 +941,11 @@ final class InterestingItemDefsPanel extends IngestModuleGlobalSettingsPanel imp
FilesSet.Rule selectedRule = this.rulesList.getSelectedValue();
rules.remove(selectedRule.getUuid());
this.replaceFilesSet(oldSet, oldSet.getName(), oldSet.getDescription(), oldSet.ignoresKnownFiles(), rules);
+ if (!this.rulesListModel.isEmpty()) {
+ this.rulesList.setSelectedIndex(0);
+ } else {
+ this.resetRuleComponents();
+ }
pcs.firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_deleteRuleButtonActionPerformed
@@ -985,6 +1000,7 @@ final class InterestingItemDefsPanel extends IngestModuleGlobalSettingsPanel imp
private javax.swing.JRadioButton fileNameRadioButton;
private javax.swing.JCheckBox fileNameRegexCheckbox;
private javax.swing.JTextField fileNameTextField;
+ private javax.swing.JSpinner fileSizeSpinner;
private javax.swing.JComboBox fileSizeUnitComboBox;
private javax.swing.JRadioButton filesRadioButton;
private javax.swing.JCheckBox ignoreKnownFilesCheckbox;
@@ -999,7 +1015,6 @@ final class InterestingItemDefsPanel extends IngestModuleGlobalSettingsPanel imp
private javax.swing.JPanel jPanel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JScrollPane jScrollPane2;
- private javax.swing.JSpinner jSpinner1;
private javax.swing.JTextArea jTextArea1;
private javax.swing.JComboBox mimeTypeComboBox;
private javax.swing.JButton newRuleButton;
diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.form b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.form
index 119000eebe..3df3f78f59 100644
--- a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.form
+++ b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.form
@@ -87,9 +87,6 @@
-
-
-
diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java
index f57da241f9..a140357a50 100644
--- a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java
+++ b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java
@@ -22,7 +22,6 @@ import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
-import java.util.EnumMap;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
@@ -36,12 +35,13 @@ import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
import javax.swing.ListModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
import javax.swing.event.ListDataListener;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifact;
-import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
@@ -68,6 +68,26 @@ final class ReportVisualPanel2 extends JPanel {
deselectAllButton.setEnabled(false);
allResultsRadioButton.setSelected(true);
this.wizPanel = wizPanel;
+ this.allResultsRadioButton.addChangeListener(new ChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ tagsList.setEnabled(taggedResultsRadioButton.isSelected());
+ selectAllButton.setEnabled(taggedResultsRadioButton.isSelected());
+ deselectAllButton.setEnabled(taggedResultsRadioButton.isSelected());
+ advancedButton.setEnabled(!taggedResultsRadioButton.isSelected());
+ updateFinishButton();
+ }
+ });
+ this.taggedResultsRadioButton.addChangeListener(new ChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ tagsList.setEnabled(taggedResultsRadioButton.isSelected());
+ selectAllButton.setEnabled(taggedResultsRadioButton.isSelected());
+ deselectAllButton.setEnabled(taggedResultsRadioButton.isSelected());
+ advancedButton.setEnabled(!taggedResultsRadioButton.isSelected());
+ updateFinishButton();
+ }
+ });
}
// Initialize the list of Tags
@@ -164,21 +184,11 @@ final class ReportVisualPanel2 extends JPanel {
return result;
}
- private boolean areArtifactsSelected() {
- boolean result = false;
- for (Entry entry : artifactStates.entrySet()) {
- if (entry.getValue()) {
- result = true;
- }
- }
- return result;
- }
-
private void updateFinishButton() {
if (taggedResultsRadioButton.isSelected()) {
wizPanel.setFinish(areTagsSelected());
} else {
- wizPanel.setFinish(areArtifactsSelected());
+ wizPanel.setFinish(true);
}
}
@@ -211,11 +221,6 @@ final class ReportVisualPanel2 extends JPanel {
optionsButtonGroup.add(taggedResultsRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(taggedResultsRadioButton, org.openide.util.NbBundle.getMessage(ReportVisualPanel2.class, "ReportVisualPanel2.taggedResultsRadioButton.text")); // NOI18N
- taggedResultsRadioButton.addChangeListener(new javax.swing.event.ChangeListener() {
- public void stateChanged(javax.swing.event.ChangeEvent evt) {
- taggedResultsRadioButtonStateChanged(evt);
- }
- });
optionsButtonGroup.add(allResultsRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(allResultsRadioButton, org.openide.util.NbBundle.getMessage(ReportVisualPanel2.class, "ReportVisualPanel2.allResultsRadioButton.text")); // NOI18N
@@ -293,14 +298,6 @@ final class ReportVisualPanel2 extends JPanel {
);
}// //GEN-END:initComponents
- private void taggedResultsRadioButtonStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_taggedResultsRadioButtonStateChanged
- tagsList.setEnabled(taggedResultsRadioButton.isSelected());
- selectAllButton.setEnabled(taggedResultsRadioButton.isSelected());
- deselectAllButton.setEnabled(taggedResultsRadioButton.isSelected());
- advancedButton.setEnabled(!taggedResultsRadioButton.isSelected());
- updateFinishButton();
- }//GEN-LAST:event_taggedResultsRadioButtonStateChanged
-
private void selectAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectAllButtonActionPerformed
for (String tag : tags) {
tagStates.put(tag, Boolean.TRUE);
@@ -319,8 +316,8 @@ final class ReportVisualPanel2 extends JPanel {
private void advancedButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_advancedButtonActionPerformed
artifactStates = dialog.display();
- wizPanel.setFinish(areArtifactsSelected());
}//GEN-LAST:event_advancedButtonActionPerformed
+
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton advancedButton;
private javax.swing.JRadioButton allResultsRadioButton;
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/PromptDialogManager.java b/Core/src/org/sleuthkit/autopsy/timeline/PromptDialogManager.java
index 45c22ac047..0e1996456e 100644
--- a/Core/src/org/sleuthkit/autopsy/timeline/PromptDialogManager.java
+++ b/Core/src/org/sleuthkit/autopsy/timeline/PromptDialogManager.java
@@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.timeline;
import java.io.IOException;
import java.net.URL;
-import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import javafx.collections.FXCollections;
@@ -34,8 +33,6 @@ import javafx.scene.control.ListView;
import javafx.scene.image.Image;
import javafx.stage.Modality;
import javafx.stage.Stage;
-import javax.annotation.Nullable;
-import org.apache.commons.lang3.StringUtils;
import org.controlsfx.dialog.ProgressDialog;
import org.controlsfx.tools.Borders;
import org.openide.util.NbBundle;
@@ -50,13 +47,13 @@ class PromptDialogManager {
private static final Logger LOGGER = Logger.getLogger(PromptDialogManager.class.getName());
- @NbBundle.Messages("PrompDialogManager.buttonType.showTimeline=Show Timeline")
- private static final ButtonType SHOW_TIMELINE = new ButtonType(Bundle.PrompDialogManager_buttonType_showTimeline(), ButtonBar.ButtonData.OK_DONE);
+ @NbBundle.Messages("PrompDialogManager.buttonType.showTimeline=Continue")
+ private static final ButtonType CONTINUE = new ButtonType(Bundle.PrompDialogManager_buttonType_showTimeline(), ButtonBar.ButtonData.OK_DONE);
@NbBundle.Messages("PrompDialogManager.buttonType.continueNoUpdate=Continue Without Updating")
private static final ButtonType CONTINUE_NO_UPDATE = new ButtonType(Bundle.PrompDialogManager_buttonType_continueNoUpdate(), ButtonBar.ButtonData.CANCEL_CLOSE);
- @NbBundle.Messages("PrompDialogManager.buttonType.update=Update")
+ @NbBundle.Messages("PrompDialogManager.buttonType.update=Update DB")
private static final ButtonType UPDATE = new ButtonType(Bundle.PrompDialogManager_buttonType_update(), ButtonBar.ButtonData.OK_DONE);
/**
@@ -89,7 +86,7 @@ class PromptDialogManager {
}
/**
- * Bring the currently managed dialog (if there is one) to the front
+ * Bring the currently managed dialog (if there is one) to the front.
*
* @return True if a dialog was brought to the front, or false of there is
* no currently managed open dialog
@@ -151,60 +148,45 @@ class PromptDialogManager {
}
/**
- * Prompt the user that ingest is running and the db may not end up
+ * Prompt the user that ingest is running and the DB may not end up
* complete.
*
- * @return True if they want to continue anyways
+ * @return True if they want to continue anyways.
*/
@NbBundle.Messages({
- "PromptDialogManager.confirmDuringIngest.headerText=You are trying to show a timeline before ingest has been completed.\nThe timeline may be incomplete.",
+ "PromptDialogManager.confirmDuringIngest.headerText=You are trying to update the Timeline DB before ingest has been completed. The Timeline DB may be incomplete.",
"PromptDialogManager.confirmDuringIngest.contentText=Do you want to continue?"})
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
boolean confirmDuringIngest() {
- currentDialog = new Alert(Alert.AlertType.CONFIRMATION, Bundle.PromptDialogManager_confirmDuringIngest_contentText(), SHOW_TIMELINE, ButtonType.CANCEL);
+ currentDialog = new Alert(Alert.AlertType.CONFIRMATION, Bundle.PromptDialogManager_confirmDuringIngest_contentText(), CONTINUE, ButtonType.CANCEL);
currentDialog.initModality(Modality.APPLICATION_MODAL);
currentDialog.setTitle(Bundle.Timeline_dialogs_title());
setDialogIcons(currentDialog);
currentDialog.setHeaderText(Bundle.PromptDialogManager_confirmDuringIngest_headerText());
- //show dialog and map all results except "show timeline" to false.
- return currentDialog.showAndWait().map(SHOW_TIMELINE::equals).orElse(false);
+ //show dialog and map all results except "continue" to false.
+ return currentDialog.showAndWait().map(CONTINUE::equals).orElse(false);
}
/**
* Prompt the user to confirm rebuilding the database for the given list of
- * reasons, adding that "ingest has finished" for the datasource with the
- * given name, if not blank, as a reason and as extra header text.
+ * reasons.
*
- * @param finishedDataSourceName The name of the datasource that has
- * finished be analyzed. Will be ignored if it
- * is null or empty.
- * @param rebuildReasons A List of reasons why the database is out
- * of date.
+ * @param rebuildReasons A List of reasons why the database is out of date.
*
* @return True if the user a confirms rebuilding the database.
*/
@NbBundle.Messages({
- "PromptDialogManager.rebuildPrompt.headerText=The Timeline database is incomplete and/or out of date."
- + " Some events may be missing or inaccurate and some features may be unavailable.",
- "# {0} - data source name",
- "PromptDialogManager.rebuildPrompt.ingestDone=Ingest has finished for {0}.",
+ "PromptDialogManager.rebuildPrompt.headerText=The Timeline DB is incomplete and/or out of date. Some events may be missing or inaccurate and some features may be unavailable.",
"PromptDialogManager.rebuildPrompt.details=Details"})
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
- boolean confirmRebuild(@Nullable String finishedDataSourceName, List rebuildReasons) {
+ boolean confirmRebuild(List rebuildReasons) {
currentDialog = new Alert(Alert.AlertType.CONFIRMATION, Bundle.TimeLinecontroller_updateNowQuestion(), UPDATE, CONTINUE_NO_UPDATE);
currentDialog.initModality(Modality.APPLICATION_MODAL);
currentDialog.setTitle(Bundle.Timeline_dialogs_title());
setDialogIcons(currentDialog);
- //configure header text depending on presence of finishedDataSourceName
- String headerText = Bundle.PromptDialogManager_rebuildPrompt_headerText();
- if (StringUtils.isNotBlank(finishedDataSourceName)) {
- String datasourceMessage = Bundle.PromptDialogManager_rebuildPrompt_ingestDone(finishedDataSourceName);
- rebuildReasons.add(0, datasourceMessage);
- headerText = datasourceMessage + "\n\n" + headerText;
- }
- currentDialog.setHeaderText(headerText);
+ currentDialog.setHeaderText(Bundle.PromptDialogManager_rebuildPrompt_headerText());
//set up listview of reasons to rebuild
ListView listView = new ListView<>(FXCollections.observableArrayList(rebuildReasons));
@@ -224,17 +206,4 @@ class PromptDialogManager {
//show dialog and map all results except "update" to false.
return currentDialog.showAndWait().map(UPDATE::equals).orElse(false);
}
-
- /**
- * Prompt the user to confirm rebuilding the database for the given list of
- * reasons.
- *
- * @param rebuildReasons S List of reasons why the database is out of date.
- *
- * @return True if the user a confirms rebuilding the database.
- */
- @ThreadConfined(type = ThreadConfined.ThreadType.JFX)
- boolean confirmRebuild(ArrayList rebuildReasons) {
- return confirmRebuild(null, rebuildReasons);
- }
}
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java
index 294de1395d..d2740c652b 100644
--- a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java
+++ b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java
@@ -51,7 +51,6 @@ import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import static javafx.concurrent.Worker.State.FAILED;
import static javafx.concurrent.Worker.State.SUCCEEDED;
-import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.Immutable;
import javax.swing.SwingUtilities;
@@ -74,9 +73,9 @@ import org.sleuthkit.autopsy.coreutils.LoggedTask;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
+import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.autopsy.ingest.IngestManager;
import static org.sleuthkit.autopsy.ingest.IngestManager.IngestJobEvent.CANCELLED;
-import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisEvent;
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
import org.sleuthkit.autopsy.timeline.datamodel.TimeLineEvent;
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType;
@@ -89,12 +88,11 @@ import org.sleuthkit.autopsy.timeline.zooming.DescriptionLoD;
import org.sleuthkit.autopsy.timeline.zooming.EventTypeZoomLevel;
import org.sleuthkit.autopsy.timeline.zooming.TimeUnits;
import org.sleuthkit.autopsy.timeline.zooming.ZoomParams;
-import org.sleuthkit.datamodel.Content;
/**
- * Controller in the MVC design along with model = {@link FilteredEventsModel}
- * and views = {@link TimeLineView}. Forwards interpreted user gestures form
- * views to model. Provides model to view. Is entry point for timeline module.
+ * Controller in the MVC design along with FilteredEventsModel TimeLineView.
+ * Forwards interpreted user gestures form views to model. Provides model to
+ * view. Is entry point for timeline module.
*
* Concurrency Policy:
*
Since filteredEvents is internally synchronized, only compound access to
@@ -141,7 +139,7 @@ public class TimeLineController {
private final ReadOnlyStringWrapper taskTitle = new ReadOnlyStringWrapper();
- private final ReadOnlyStringWrapper status = new ReadOnlyStringWrapper();
+ private final ReadOnlyStringWrapper statusMessage = new ReadOnlyStringWrapper();
/**
* Status is a string that will be displayed in the status bar as a kind of
@@ -149,12 +147,12 @@ public class TimeLineController {
*
* @return The status property
*/
- public ReadOnlyStringProperty getStatusProperty() {
- return status.getReadOnlyProperty();
+ public ReadOnlyStringProperty statusMessageProperty() {
+ return statusMessage.getReadOnlyProperty();
}
- public void setStatus(String string) {
- status.set(string);
+ public void setStatusMessage(String string) {
+ statusMessage.set(string);
}
private final Case autoCase;
private final PerCaseTimelineProperties perCaseTimelineProperties;
@@ -201,10 +199,10 @@ public class TimeLineController {
private final PropertyChangeListener ingestModuleListener = new AutopsyIngestModuleListener();
@GuardedBy("this")
- private final ReadOnlyObjectWrapper viewMode = new ReadOnlyObjectWrapper<>(VisualizationMode.COUNTS);
+ private final ReadOnlyObjectWrapper visualizationMode = new ReadOnlyObjectWrapper<>(VisualizationMode.COUNTS);
- synchronized public ReadOnlyObjectProperty viewModeProperty() {
- return viewMode.getReadOnlyProperty();
+ synchronized public ReadOnlyObjectProperty visualizationModeProperty() {
+ return visualizationMode.getReadOnlyProperty();
}
@GuardedBy("filteredEvents")
@@ -263,6 +261,7 @@ public class TimeLineController {
@NbBundle.Messages({
"TimeLineController.setEventsDBStale.errMsgStale=Failed to mark the timeline db as stale. Some results may be out of date or missing.",
"TimeLineController.setEventsDBStale.errMsgNotStale=Failed to mark the timeline db as not stale. Some results may be out of date or missing."})
+ @ThreadConfined(type = ThreadConfined.ThreadType.JFX)
private void setEventsDBStale(final Boolean stale) {
eventsDBStale.set(stale);
try {
@@ -395,6 +394,7 @@ public class TimeLineController {
}
if (markDBNotStale) {
setEventsDBStale(false);
+ filteredEvents.postDBUpdated();
}
SwingUtilities.invokeLater(this::showWindow);
TimeLineController.this.showRange(interval);
@@ -473,6 +473,7 @@ public class TimeLineController {
mainFrame.close();
mainFrame = null;
}
+ OpenTimelineAction.invalidateController();
}
/**
@@ -489,18 +490,14 @@ public class TimeLineController {
listeningToAutopsy = true;
}
- Platform.runLater(() -> promptForRebuild(null, interval));
+ Platform.runLater(() -> promptForRebuild( interval));
}
/**
- * Prompt the user to confirm rebuilding the db because ingest has finished
- * on the datasource with the given name. Checks if a database rebuild is
- * necessary for any other reasons and includes those in the prompt. If the
- * user confirms, rebuilds the database. Shows the timeline window when the
- * rebuild is done, or immediately if the rebuild is not confirmed.
- *
- * @param dataSourceName The name of the datasource that ingest has finished
- * processing. Will be ignored if it is null or empty.
+ * Prompt the user to confirm rebuilding the db. Checks if a database
+ * rebuild is necessary and includes the reasons in the prompt. If the user
+ * confirms, rebuilds the database. Shows the timeline window when the
+ * rebuild is done, or immediately if the rebuild is not confirmed. F
*/
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
private void promptForRebuild(@Nullable String dataSourceName, Interval interval) {
@@ -518,7 +515,7 @@ public class TimeLineController {
//if necessary prompt user with reasons to rebuild
List rebuildReasons = getRebuildReasons();
if (false == rebuildReasons.isEmpty()) {
- if (promptDialogManager.confirmRebuild(dataSourceName, rebuildReasons)) {
+ if (promptDialogManager.confirmRebuild(rebuildReasons)) {
rebuildRepo(interval);
return;
}
@@ -578,7 +575,7 @@ public class TimeLineController {
* Request a time range the same length as the given period and centered
* around the middle of the currently viewed time range.
*
- * @param period The period of time to shw around the current center of the
+ * @param period The period of time to show around the current center of the
* view.
*/
synchronized public void pushPeriod(ReadablePeriod period) {
@@ -604,9 +601,14 @@ public class TimeLineController {
pushTimeRange(new Interval(start, end));
}
- synchronized public void setViewMode(VisualizationMode visualizationMode) {
- if (viewMode.get() != visualizationMode) {
- viewMode.set(visualizationMode);
+ /**
+ * Set a new Visualization mode as the active one.
+ *
+ * @param visualizationMode The new VisaualizationMode to set.
+ */
+ synchronized public void setVisualizationMode(VisualizationMode visualizationMode) {
+ if (this.visualizationMode.get() != visualizationMode) {
+ this.visualizationMode.set(visualizationMode);
}
}
@@ -636,7 +638,8 @@ public class TimeLineController {
}
/**
- * private method to build gui if necessary and make it visible.
+ * Show the timeline TimeLineTopComponent. This method will construct a new
+ * instance of TimeLineTopComponent if necessary.
*/
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
synchronized private void showWindow() {
@@ -645,6 +648,11 @@ public class TimeLineController {
}
mainFrame.open();
mainFrame.toFront();
+ /*
+ * Make this top component active so its ExplorerManager's lookup gets
+ * proxied in Utilities.actionsGlobalContext()
+ */
+ mainFrame.requestActive();
}
synchronized public void pushEventTypeZoom(EventTypeZoomLevel typeZoomeLevel) {
@@ -824,47 +832,6 @@ public class TimeLineController {
TimeLineController.timeZone.set(timeZone);
}
- Interval getSpanningInterval(Collection eventIDs) {
- return filteredEvents.getSpanningInterval(eventIDs);
-
- }
-
- /**
- * Is the timeline window open?
- *
- * @return True if the timeline is open.
- */
- @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
- private boolean isWindowOpen() {
- return mainFrame != null && mainFrame.isOpened() && mainFrame.isVisible();
- }
-
- /**
- * Rebuild the db ONLY IF THE TIMELINE WINDOW IS OPEN. The user will be
- * prompted with reasons why the database needs to be rebuilt and can still
- * cancel the rebuild. The prompt will include that ingest has finished for
- * the given datasource name, if not blank.
- *
- * @param dataSourceName The name of the datasource that has finished
- * ingest. Will be ignored if it is null or empty.
- */
- @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
- private void rebuildIfWindowOpen(@Nullable String dataSourceName) {
- if (isWindowOpen()) {
- Platform.runLater(() -> this.promptForRebuild(dataSourceName));
- }
- }
-
- /**
- * Rebuild the db ONLY IF THE TIMELINE WINDOW IS OPEN. The user will be
- * prompted with reasons why the database needs to be rebuilt and can still
- * cancel the rebuild.
- */
- @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
- public void rebuildIfWindowOpen() {
- rebuildIfWindowOpen(null);
- }
-
/**
* Listener for IngestManager.IngestModuleEvents.
*/
@@ -882,16 +849,14 @@ public class TimeLineController {
try {
Case.getCurrentCase();
} catch (IllegalStateException notUsed) {
- /**
- * Case is closed, do nothing.
- */
+ // Case is closed, do nothing.
return;
}
switch (IngestManager.IngestModuleEvent.valueOf(evt.getPropertyName())) {
case CONTENT_CHANGED:
case DATA_ADDED:
- //since black board artifacts or new derived content have been added, the db is stale.
+ //since black board artifacts or new derived content have been added, the DB is stale.
Platform.runLater(() -> setEventsDBStale(true));
break;
case FILE_DONE:
@@ -914,9 +879,9 @@ public class TimeLineController {
public void propertyChange(PropertyChangeEvent evt) {
switch (IngestManager.IngestJobEvent.valueOf(evt.getPropertyName())) {
case DATA_SOURCE_ANALYSIS_COMPLETED:
- // include data source name in rebuild prompt on ingest completed
- final Content dataSource = ((DataSourceAnalysisEvent) evt).getDataSource();
- SwingUtilities.invokeLater(() -> rebuildIfWindowOpen(dataSource.getName()));
+ //mark db stale, and prompt to rebuild
+ Platform.runLater(() -> setEventsDBStale(true));
+ filteredEvents.postAutopsyEventLocally((AutopsyEvent) evt);
break;
case DATA_SOURCE_ANALYSIS_STARTED:
case CANCELLED:
@@ -951,10 +916,10 @@ public class TimeLineController {
case DATA_SOURCE_ADDED:
//mark db stale, and prompt to rebuild
Platform.runLater(() -> setEventsDBStale(true));
+ filteredEvents.postAutopsyEventLocally((AutopsyEvent) evt);
break;
case CURRENT_CASE:
//close timeline on case changes.
- OpenTimelineAction.invalidateController();
SwingUtilities.invokeLater(TimeLineController.this::shutDownTimeLine);
break;
}
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java
index ab52c1cbb5..f91d2e8bba 100644
--- a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java
+++ b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java
@@ -108,12 +108,12 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer
final Tab eventsTreeTab = new Tab(Bundle.TimeLineTopComponent_eventsTab_name(), eventsTree);
eventsTreeTab.setClosable(false);
eventsTreeTab.setGraphic(new ImageView("org/sleuthkit/autopsy/timeline/images/timeline_marker.png")); // NON-NLS
- eventsTreeTab.disableProperty().bind(controller.viewModeProperty().isEqualTo(VisualizationMode.COUNTS));
+ eventsTreeTab.disableProperty().bind(controller.visualizationModeProperty().isEqualTo(VisualizationMode.COUNTS));
final TabPane leftTabPane = new TabPane(filterTab, eventsTreeTab);
VBox.setVgrow(leftTabPane, Priority.ALWAYS);
- controller.viewModeProperty().addListener((Observable observable) -> {
- if (controller.viewModeProperty().get().equals(VisualizationMode.COUNTS)) {
+ controller.visualizationModeProperty().addListener((Observable observable) -> {
+ if (controller.visualizationModeProperty().get().equals(VisualizationMode.COUNTS)) {
//if view mode is counts, make sure events tabd is not active
leftTabPane.getSelectionModel().select(filterTab);
}
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/actions/RebuildDataBase.java b/Core/src/org/sleuthkit/autopsy/timeline/actions/UpdateDB.java
similarity index 69%
rename from Core/src/org/sleuthkit/autopsy/timeline/actions/RebuildDataBase.java
rename to Core/src/org/sleuthkit/autopsy/timeline/actions/UpdateDB.java
index 85715b6706..599f029844 100644
--- a/Core/src/org/sleuthkit/autopsy/timeline/actions/RebuildDataBase.java
+++ b/Core/src/org/sleuthkit/autopsy/timeline/actions/UpdateDB.java
@@ -25,18 +25,26 @@ import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.timeline.TimeLineController;
/**
- * An action that rebuilds the events database to include any new results from
+ * An action that rebuilds the timeline database to include any new results from
* ingest.
*/
-public class RebuildDataBase extends Action {
+public class UpdateDB extends Action {
private static final Image DB_REFRESH = new Image("org/sleuthkit/autopsy/timeline/images/database_refresh.png");
- @NbBundle.Messages({"RebuildDataBase.text=Update"})
- public RebuildDataBase(TimeLineController controller) {
+ /**
+ * Constructor
+ *
+ * @param controller The TimeLineController for this action.
+ */
+ @NbBundle.Messages({
+ "RebuildDataBase.text=Update DB",
+ "RebuildDataBase.longText=Update the DB to include new events."})
+ public UpdateDB(TimeLineController controller) {
super(Bundle.RebuildDataBase_text());
-
+ setLongText(Bundle.RebuildDataBase_longText());
setGraphic(new ImageView(DB_REFRESH));
setEventHandler(actionEvent -> controller.rebuildRepo());
+ disabledProperty().bind(controller.eventsDBStaleProperty().not());
}
}
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java
index ad5bc8786e..1431673f22 100644
--- a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java
+++ b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java
@@ -40,9 +40,11 @@ import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent.DeletedContentTagInfo;
import org.sleuthkit.autopsy.coreutils.Logger;
+import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType;
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.RootEventType;
import org.sleuthkit.autopsy.timeline.db.EventsRepository;
+import org.sleuthkit.autopsy.timeline.events.DBUpdatedEvent;
import org.sleuthkit.autopsy.timeline.events.RefreshRequestedEvent;
import org.sleuthkit.autopsy.timeline.events.TagsAddedEvent;
import org.sleuthkit.autopsy.timeline.events.TagsDeletedEvent;
@@ -412,6 +414,15 @@ public final class FilteredEventsModel {
return false;
}
+ /**
+ * Post a TagsAddedEvent to all registered subscribers, if the given set of
+ * updated event IDs is not empty.
+ *
+ * @param updatedEventIDs The set of event ids to be included in the
+ * TagsAddedEvent.
+ *
+ * @return True if an event was posted.
+ */
private boolean postTagsAdded(Set updatedEventIDs) {
boolean tagsUpdated = !updatedEventIDs.isEmpty();
if (tagsUpdated) {
@@ -420,6 +431,15 @@ public final class FilteredEventsModel {
return tagsUpdated;
}
+ /**
+ * Post a TagsDeletedEvent to all registered subscribers, if the given set
+ * of updated event IDs is not empty.
+ *
+ * @param updatedEventIDs The set of event ids to be included in the
+ * TagsDeletedEvent.
+ *
+ * @return True if an event was posted.
+ */
private boolean postTagsDeleted(Set updatedEventIDs) {
boolean tagsUpdated = !updatedEventIDs.isEmpty();
if (tagsUpdated) {
@@ -428,16 +448,45 @@ public final class FilteredEventsModel {
return tagsUpdated;
}
+ /**
+ * Register the given object to receive events.
+ *
+ * @param o The object to register. Must implement public methods annotated
+ * with Subscribe.
+ */
synchronized public void registerForEvents(Object o) {
eventbus.register(o);
}
+ /**
+ * Un-register the given object, so it no longer receives events.
+ *
+ * @param o The object to un-register.
+ */
synchronized public void unRegisterForEvents(Object o) {
eventbus.unregister(0);
}
- public void refresh() {
+ /**
+ * Post a DBUpdatedEvent to all registered subscribers.
+ */
+ public void postDBUpdated() {
+ eventbus.post(new DBUpdatedEvent());
+ }
+
+ /**
+ * Post a RefreshRequestedEvent to all registered subscribers.
+ */
+ public void postRefreshRequest() {
eventbus.post(new RefreshRequestedEvent());
}
+ /**
+ * (Re)Post an AutopsyEvent received from another event distribution system
+ * locally to all registered subscribers.
+ */
+ public void postAutopsyEventLocally(AutopsyEvent event) {
+ eventbus.post(event);
+ }
+
}
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/events/DBUpdatedEvent.java b/Core/src/org/sleuthkit/autopsy/timeline/events/DBUpdatedEvent.java
new file mode 100644
index 0000000000..75d72d913a
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/timeline/events/DBUpdatedEvent.java
@@ -0,0 +1,29 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 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.timeline.events;
+
+/**
+ * A "local" event published by filteredEventsModel to indicate that DB has been
+ * updated.
+ *
+ * This event is not intended for use out side of the Timeline module.
+ */
+public class DBUpdatedEvent {
+
+}
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/events/RefreshRequestedEvent.java b/Core/src/org/sleuthkit/autopsy/timeline/events/RefreshRequestedEvent.java
index f8cdfe23e7..47b04eb479 100644
--- a/Core/src/org/sleuthkit/autopsy/timeline/events/RefreshRequestedEvent.java
+++ b/Core/src/org/sleuthkit/autopsy/timeline/events/RefreshRequestedEvent.java
@@ -22,8 +22,8 @@ package org.sleuthkit.autopsy.timeline.events;
* A "local" event published by filteredEventsModel to indicate that the user
* requested that the current visualization be refreshed with out changing any
* of the parameters ( to include more up to date tag data for example.)
- *
- * This event is not intended for use out side of the timeline module.
+ *
+ * This event is not intended for use out side of the Timeline module.
*/
public class RefreshRequestedEvent {
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/events/TagsAddedEvent.java b/Core/src/org/sleuthkit/autopsy/timeline/events/TagsAddedEvent.java
index 2ff4474429..0917513430 100644
--- a/Core/src/org/sleuthkit/autopsy/timeline/events/TagsAddedEvent.java
+++ b/Core/src/org/sleuthkit/autopsy/timeline/events/TagsAddedEvent.java
@@ -1,14 +1,36 @@
/*
- * 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 Forensic Browser
+ *
+ * Copyright 2014-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.timeline.events;
import java.util.Set;
+/**
+ * A TagsUpdatedEvent for tags that have been added to events.
+ */
public class TagsAddedEvent extends TagsUpdatedEvent {
+ /**
+ * Constructor
+ *
+ * @param updatedEventIDs The event IDs of the events that have had tags
+ * added to them.
+ */
public TagsAddedEvent(Set updatedEventIDs) {
super(updatedEventIDs);
}
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/events/TagsDeletedEvent.java b/Core/src/org/sleuthkit/autopsy/timeline/events/TagsDeletedEvent.java
index 8f7791910f..f0d5826060 100644
--- a/Core/src/org/sleuthkit/autopsy/timeline/events/TagsDeletedEvent.java
+++ b/Core/src/org/sleuthkit/autopsy/timeline/events/TagsDeletedEvent.java
@@ -1,17 +1,37 @@
/*
- * 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 Forensic Browser
+ *
+ * Copyright 2015-16 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.timeline.events;
import java.util.Set;
+/**
+ * A TagsUpdatedEvent for tags that have been removed from events.
+ */
public class TagsDeletedEvent extends TagsUpdatedEvent {
+ /**
+ * Constructor
+ *
+ * @param updatedEventIDs The event IDs of the events that have had tags
+ * removed from them.
+ */
public TagsDeletedEvent(Set updatedEventIDs) {
super(updatedEventIDs);
}
-
}
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/events/TagsUpdatedEvent.java b/Core/src/org/sleuthkit/autopsy/timeline/events/TagsUpdatedEvent.java
index 7d38458332..02ed6aef7f 100644
--- a/Core/src/org/sleuthkit/autopsy/timeline/events/TagsUpdatedEvent.java
+++ b/Core/src/org/sleuthkit/autopsy/timeline/events/TagsUpdatedEvent.java
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
- * Copyright 2015 Basis Technology Corp.
+ * Copyright 2015-16 Basis Technology Corp.
* Contact: carrier sleuthkit org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,19 +23,31 @@ import java.util.Set;
/**
* A "local" event published by filteredEventsModel to indicate that events have
- * been(un)tagged. This event is not intended for use out side of the timeline
- * module.
+ * been tagged or un-tagged. This event is not intended for use out side of the
+ * Timeline module.
*/
abstract public class TagsUpdatedEvent {
private final Set updatedEventIDs;
+ /**
+ * Get the set of event IDs for the events that have been tagged or
+ * un-tagged.
+ *
+ * @return The set of event IDs for the events that have been tagged or
+ * un-tagged.
+ */
public ImmutableSet getUpdatedEventIDs() {
return ImmutableSet.copyOf(updatedEventIDs);
}
- public TagsUpdatedEvent(Set updatedEventIDs) {
+ /**
+ * Constructor
+ *
+ * @param updatedEventIDs The set of event IDs for the events that have been
+ * tagged or un-tagged.
+ */
+ TagsUpdatedEvent(Set updatedEventIDs) {
this.updatedEventIDs = updatedEventIDs;
-
}
}
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/images/information-frame.png b/Core/src/org/sleuthkit/autopsy/timeline/images/information-frame.png
new file mode 100644
index 0000000000..a7b53a7f62
Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/timeline/images/information-frame.png differ
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/images/information-white.png b/Core/src/org/sleuthkit/autopsy/timeline/images/information-white.png
new file mode 100644
index 0000000000..70052384af
Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/timeline/images/information-white.png differ
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/images/warning.png b/Core/src/org/sleuthkit/autopsy/timeline/images/warning.png
new file mode 100644
index 0000000000..b6281848a7
Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/timeline/images/warning.png differ
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/images/warning_triangle.png b/Core/src/org/sleuthkit/autopsy/timeline/images/warning_triangle.png
new file mode 100644
index 0000000000..b7024717af
Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/timeline/images/warning_triangle.png differ
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/images/warning_triangle_small.png b/Core/src/org/sleuthkit/autopsy/timeline/images/warning_triangle_small.png
new file mode 100644
index 0000000000..06da735537
Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/timeline/images/warning_triangle_small.png differ
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java
index 3b10982070..edf74385f6 100644
--- a/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java
+++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java
@@ -18,7 +18,6 @@
*/
package org.sleuthkit.autopsy.timeline.ui;
-import com.google.common.eventbus.Subscribe;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -72,7 +71,6 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.timeline.TimeLineController;
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType;
-import org.sleuthkit.autopsy.timeline.events.RefreshRequestedEvent;
/**
* Abstract base class for TimeLineChart based visualizations.
@@ -98,18 +96,29 @@ public abstract class AbstractVisualizationPane> dataSeries = FXCollections.>observableArrayList();
protected final Map> eventTypeToSeriesMap = new HashMap<>();
@@ -131,7 +140,41 @@ public abstract class AbstractVisualizationPane selectedNodes = FXCollections.observableArrayList();
- private InvalidationListener updateListener = any -> update();
+ /**
+ * Listener that is attached to various properties that should trigger a vis
+ * update when they change.
+ */
+ private InvalidationListener updateListener = any -> refresh();
+
+ /**
+ * Does the visualization represent an out-of-date state of the DB. It might
+ * if, for example, tags have been updated but the vis. was not refreshed.
+ *
+ * @return True if the visualization does not represent the curent state of
+ * the DB.
+ */
+ public boolean isOutOfDate() {
+ return outOfDate.get();
+ }
+
+ /**
+ * Set this visualization out of date because, for example, tags have been
+ * updated but the vis. was not refreshed.
+ */
+ void setOutOfDate() {
+ outOfDate.set(true);
+ }
+
+ /**
+ * Get a ReadOnlyBooleanProperty that holds true if this visualization does
+ * not represent the current state of the DB>
+ *
+ * @return A ReadOnlyBooleanProperty that holds the out-of-date state for
+ * this visualization.
+ */
+ public ReadOnlyBooleanProperty outOfDateProperty() {
+ return outOfDate.getReadOnlyProperty();
+ }
/**
* The visualization nodes that are selected.
@@ -220,6 +263,17 @@ public abstract class AbstractVisualizationPane controller.setStatus(isHover() ? DEFAULT_TOOLTIP.getText() : ""));
+ hoverProperty().addListener(hoverProp -> controller.setStatusMessage(isHover() ? DEFAULT_TOOLTIP.getText() : ""));
}
- /**
- * Handle a RefreshRequestedEvent from the events model by updating the
- * visualization.
- *
- * @param event The RefreshRequestedEvent to handle.
- */
- @Subscribe
- public void handleRefreshRequested(RefreshRequestedEvent event) {
- update();
- }
-
/**
* Iterate through the list of tick-marks building a two level structure of
* replacement tick mark labels. (Visually) upper level has most
@@ -626,13 +669,13 @@ public abstract class AbstractVisualizationPane The type of a single object that can represent
* the range of data displayed along the X-Axis.
*/
- abstract protected class VisualizationUpdateTask extends LoggedTask {
+ abstract protected class VisualizationRefreshTask extends LoggedTask {
private final Node center;
@@ -640,10 +683,10 @@ public abstract class AbstractVisualizationPane
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
+
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java
index 7463aafc2f..e0f5171407 100644
--- a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java
@@ -31,7 +31,6 @@ import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
-import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.scene.control.Button;
@@ -68,55 +67,72 @@ import org.controlsfx.control.action.ActionUtils;
import org.joda.time.DateTime;
import org.joda.time.Interval;
import org.openide.util.NbBundle;
+import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent;
import org.sleuthkit.autopsy.coreutils.LoggedTask;
import org.sleuthkit.autopsy.coreutils.Logger;
+import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisCompletedEvent;
import org.sleuthkit.autopsy.timeline.FXMLConstructor;
import org.sleuthkit.autopsy.timeline.TimeLineController;
import org.sleuthkit.autopsy.timeline.VisualizationMode;
import org.sleuthkit.autopsy.timeline.actions.Back;
import org.sleuthkit.autopsy.timeline.actions.ResetFilters;
import org.sleuthkit.autopsy.timeline.actions.SaveSnapshotAsReport;
+import org.sleuthkit.autopsy.timeline.actions.UpdateDB;
import org.sleuthkit.autopsy.timeline.actions.ZoomIn;
import org.sleuthkit.autopsy.timeline.actions.ZoomOut;
import org.sleuthkit.autopsy.timeline.actions.ZoomToEvents;
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
+import org.sleuthkit.autopsy.timeline.events.DBUpdatedEvent;
+import org.sleuthkit.autopsy.timeline.events.RefreshRequestedEvent;
import org.sleuthkit.autopsy.timeline.events.TagsUpdatedEvent;
-import org.sleuthkit.autopsy.timeline.filters.TagsFilter;
import org.sleuthkit.autopsy.timeline.ui.countsview.CountsViewPane;
import org.sleuthkit.autopsy.timeline.ui.detailview.DetailViewPane;
import org.sleuthkit.autopsy.timeline.ui.detailview.tree.EventsTree;
import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo;
/**
- * A container for an {@link AbstractVisualizationPane}, has a toolbar on top to
- * hold settings widgets supplied by contained {@link AbstAbstractVisualization}
- * and, the histogram / time selection on bottom. Also supplies containers for
- * replacement axis to contained {@link AbstractAbstractVisualization}
+ * A container for an AbstractVisualizationPane. Has a Toolbar on top to hold
+ * settings widgets supplied by contained AbstractVisualizationPane, and the
+ * histogram / time selection on bottom.
*
- * TODO: refactor common code out of histogram and CountsView? -jm
+ * TODO: Refactor common code out of histogram and CountsView? -jm
*/
final public class VisualizationPanel extends BorderPane {
private static final Logger LOGGER = Logger.getLogger(VisualizationPanel.class.getName());
private static final Image INFORMATION = new Image("org/sleuthkit/autopsy/timeline/images/information.png", 16, 16, true, true); // NON-NLS
+ private static final Image WARNING = new Image("org/sleuthkit/autopsy/timeline/images/warning_triangle.png", 16, 16, true, true); // NON-NLS
private static final Image REFRESH = new Image("org/sleuthkit/autopsy/timeline/images/arrow-circle-double-135.png"); // NON-NLS
- private static final Background background = new Background(new BackgroundFill(Color.GREY, CornerRadii.EMPTY, Insets.EMPTY));
+ private static final Background GRAY_BACKGROUND = new Background(new BackgroundFill(Color.GREY, CornerRadii.EMPTY, Insets.EMPTY));
+
+ /**
+ * Region that will be stacked in between the no-events "dialog" and the
+ * hosted AbstractVisualizationPane in order to gray out the visualization.
+ */
+ private final static Region NO_EVENTS_BACKGROUND = new Region() {
+ {
+ setBackground(GRAY_BACKGROUND);
+ setOpacity(.3);
+ }
+ };
@GuardedBy("this")
private LoggedTask histogramTask;
private final EventsTree eventsTree;
private AbstractVisualizationPane, ?, ?, ?> visualization;
- //// range slider and histogram componenets
- /**
- * hbox that contains the histogram bars. //TODO: abstract this into a
- * seperate class, and/or use a real bar chart?
+
+ /*
+ * HBox that contains the histogram bars.
+ *
+ * //TODO: Abstract this into a seperate class, and/or use a real bar
+ * chart? -jm
*/
@FXML
private HBox histogramBox;
- /**
- * stack pane that superimposes rangeslider over histogram
+ /*
+ * Stack pane that superimposes rangeslider over histogram
*/
@FXML
private StackPane rangeHistogramStack;
@@ -126,7 +142,6 @@ final public class VisualizationPanel extends BorderPane {
//// time range selection components
@FXML
private MenuButton zoomMenuButton;
-
@FXML
private Button zoomOutButton;
@FXML
@@ -144,16 +159,20 @@ final public class VisualizationPanel extends BorderPane {
@FXML
private ToolBar toolBar;
@FXML
+ private Label visualizationModeLabel;
+ @FXML
private ToggleButton countsToggle;
@FXML
private ToggleButton detailsToggle;
@FXML
private Button snapShotButton;
@FXML
- private Label visualizationModeLabel;
+ private Button refreshButton;
+ @FXML
+ private Button updateDBButton;
- /**
- * wraps contained visualization so that we can show notifications over it.
+ /*
+ * Wraps contained visualization so that we can show notifications over it.
*/
private final NotificationPane notificationPane = new NotificationPane();
@@ -161,8 +180,8 @@ final public class VisualizationPanel extends BorderPane {
private final FilteredEventsModel filteredEvents;
/**
- * listen to change in range slider selected time and push to controller.
- * waits until the user releases thumb to send controller.
+ * Listen to changes in the range slider selection and forward to the
+ * controller. Waits until the user releases thumb to send to controller.
*/
private final InvalidationListener rangeSliderListener = new InvalidationListener() {
@Override
@@ -182,7 +201,7 @@ final public class VisualizationPanel extends BorderPane {
/**
* hides the notification pane on any event
*/
- private final InvalidationListener zoomListener = any -> notificationPane.hide();
+ private final InvalidationListener zoomListener = any -> handleRefreshRequested(null);
/**
* listen to change in end time picker and push to controller
@@ -195,29 +214,36 @@ final public class VisualizationPanel extends BorderPane {
private final InvalidationListener startListener = new PickerListener(() -> startPicker, Interval::withStartMillis);
/**
- * convert the given LocalDateTime to epoch millis USING THE CURERNT
- * TIMEZONE FROM TIMELINECONTROLLER
+ * Convert the given LocalDateTime to epoch millis USING THE CURRENT
+ * TIMEZONE FROM THE TIMELINECONTROLLER
*
- * @param localDateTime
+ * @param localDateTime The LocalDateTime to convert to millis since the
+ * Unix epoch.
*
- * @return the given localdatetime as epoch millis
+ * @return the given LocalDateTime as epoch millis
*/
private static long localDateTimeToEpochMilli(LocalDateTime localDateTime) {
return localDateTime.atZone(TimeLineController.getTimeZoneID()).toInstant().toEpochMilli();
}
/**
- * convert the given epoch millis to a LocalDateTime USING THE CURERNT
- * TIMEZONE FROM TIMELINECONTROLLER
+ * Convert the given "millis from the Unix Epoch" to a LocalDateTime USING
+ * THE CURRENT TIMEZONE FROM THE TIMELINECONTROLLER
*
- * @param millis
+ * @param millis The milliseconds to convert.
*
- * @return the given epoch millis as a LocalDateTime
+ * @return The given epoch millis as a LocalDateTime
*/
private static LocalDateTime epochMillisToLocalDateTime(long millis) {
return LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), TimeLineController.getTimeZoneID());
}
+ /**
+ * Constructor
+ *
+ * @param controller The TimeLineController for this VisualizationPanel
+ * @param eventsTree The EventsTree this VisualizationPanel hosts.
+ */
public VisualizationPanel(@Nonnull TimeLineController controller, @Nonnull EventsTree eventsTree) {
this.controller = controller;
this.filteredEvents = controller.getEventsModel();
@@ -225,14 +251,16 @@ final public class VisualizationPanel extends BorderPane {
FXMLConstructor.construct(this, "VisualizationPanel.fxml"); // NON-NLS
}
- @FXML // This method is called by the FXMLLoader when initialization is complete
- @NbBundle.Messages({"VisualizationPanel.refresh=refresh",
+ @FXML
+ @NbBundle.Messages({
"VisualizationPanel.visualizationModeLabel.text=Visualization Mode:",
"VisualizationPanel.startLabel.text=Start:",
"VisualizationPanel.endLabel.text=End:",
"VisualizationPanel.countsToggle.text=Counts",
"VisualizationPanel.detailsToggle.text=Details",
- "VisualizationPanel.zoomMenuButton.text=Zoom in/out to"})
+ "VisualizationPanel.zoomMenuButton.text=Zoom in/out to",
+ "VisualizationPanel.tagsAddedOrDeleted=Tags have been created and/or deleted. The visualization may not be up to date."
+ })
void initialize() {
assert endPicker != null : "fx:id=\"endPicker\" was not injected: check your FXML file 'ViewWrapper.fxml'."; // NON-NLS
assert histogramBox != null : "fx:id=\"histogramBox\" was not injected: check your FXML file 'ViewWrapper.fxml'."; // NON-NLS
@@ -243,15 +271,6 @@ final public class VisualizationPanel extends BorderPane {
//configure notification pane
notificationPane.getStyleClass().add(NotificationPane.STYLE_CLASS_DARK);
- notificationPane.getActions().setAll(new Action(Bundle.VisualizationPanel_refresh()) {
- {
- setGraphic(new ImageView(REFRESH));
- setEventHandler((ActionEvent t) -> {
- filteredEvents.refresh();
- notificationPane.hide();
- });
- }
- });
setCenter(notificationPane);
//configure visualization mode toggle
@@ -262,24 +281,25 @@ final public class VisualizationPanel extends BorderPane {
if (newValue == null) {
countsToggle.getToggleGroup().selectToggle(oldValue != null ? oldValue : countsToggle);
} else if (newValue == countsToggle && oldValue != null) {
- controller.setViewMode(VisualizationMode.COUNTS);
+ controller.setVisualizationMode(VisualizationMode.COUNTS);
} else if (newValue == detailsToggle && oldValue != null) {
- controller.setViewMode(VisualizationMode.DETAIL);
+ controller.setVisualizationMode(VisualizationMode.DETAIL);
}
};
if (countsToggle.getToggleGroup() != null) {
countsToggle.getToggleGroup().selectedToggleProperty().addListener(toggleListener);
} else {
- countsToggle.toggleGroupProperty().addListener((Observable observable) -> {
+ countsToggle.toggleGroupProperty().addListener((Observable toggleGroup) -> {
countsToggle.getToggleGroup().selectedToggleProperty().addListener(toggleListener);
});
}
- controller.viewModeProperty().addListener(observable -> setViewMode(controller.viewModeProperty().get()));
- setViewMode(controller.viewModeProperty().get());
- //configure snapshor button / action
+ controller.visualizationModeProperty().addListener(visualizationMode -> syncVisualizationMode());
+ syncVisualizationMode();
+
ActionUtils.configureButton(new SaveSnapshotAsReport(controller, notificationPane::getContent), snapShotButton);
+ ActionUtils.configureButton(new UpdateDB(controller), updateDBButton);
/////configure start and end pickers
startLabel.setText(Bundle.VisualizationPanel_startLabel_text());
@@ -337,81 +357,109 @@ final public class VisualizationPanel extends BorderPane {
filteredEvents.zoomParametersProperty().addListener(zoomListener);
refreshTimeUI(); //populate the viz
- //this should use an event(EventBus) , not this weird observable pattern
- controller.eventsDBStaleProperty().addListener(staleProperty -> {
- if (controller.isEventsDBStale()) {
- Platform.runLater(VisualizationPanel.this::refreshHistorgram);
- }
- });
refreshHistorgram();
}
- private void setViewMode(VisualizationMode visualizationMode) {
- switch (visualizationMode) {
- case COUNTS:
- setVisualization(new CountsViewPane(controller));
- countsToggle.setSelected(true);
- break;
- case DETAIL:
- setVisualization(new DetailViewPane(controller));
- detailsToggle.setSelected(true);
- break;
- }
- }
-
- private synchronized void setVisualization(final AbstractVisualizationPane, ?, ?, ?> newViz) {
+ /**
+ * Handle TagsUpdatedEvents by marking that the visualization needs to be
+ * refreshed.
+ *
+ * NOTE: This VisualizationPanel must be registered with the
+ * filteredEventsModel's EventBus in order for this handler to be invoked.
+ *
+ * @param event The TagsUpdatedEvent to handle.
+ */
+ @Subscribe
+ public void handleTimeLineTagUpdate(TagsUpdatedEvent event) {
+ visualization.setOutOfDate();
Platform.runLater(() -> {
- synchronized (VisualizationPanel.this) {
- if (visualization != null) {
- toolBar.getItems().removeAll(visualization.getSettingsNodes());
- visualization.dispose();
- }
-
- visualization = newViz;
- visualization.update();
- toolBar.getItems().addAll(newViz.getSettingsNodes());
-
- notificationPane.setContent(visualization);
- if (visualization instanceof DetailViewPane) {
- Platform.runLater(() -> {
- ((DetailViewPane) visualization).setHighLightedEvents(eventsTree.getSelectedEvents());
- eventsTree.setDetailViewPane((DetailViewPane) visualization);
- });
- }
- visualization.hasVisibleEventsProperty().addListener((observable, oldValue, newValue) -> {
- if (newValue == false) {
-
- notificationPane.setContent(
- new StackPane(visualization,
- new Region() {
- {
- setBackground(new Background(new BackgroundFill(Color.GREY, CornerRadii.EMPTY, Insets.EMPTY)));
- setOpacity(.3);
- }
- },
- new NoEventsDialog(() -> notificationPane.setContent(visualization))));
- } else {
- notificationPane.setContent(visualization);
- }
- });
+ if (notificationPane.isShowing() == false) {
+ notificationPane.getActions().setAll(new Refresh());
+ notificationPane.show(Bundle.VisualizationPanel_tagsAddedOrDeleted(), new ImageView(INFORMATION));
}
});
}
+ /**
+ * Handle a RefreshRequestedEvent from the events model by refreshing the
+ * visualization.
+ *
+ * NOTE: This VisualizationPanel must be registered with the
+ * filteredEventsModel's EventBus in order for this handler to be invoked.
+ *
+ * @param event The RefreshRequestedEvent to handle.
+ */
@Subscribe
- @NbBundle.Messages("VisualizationPanel.tagsAddedOrDeleted=Tags have been created and/or deleted. The visualization may not be up to date.")
- public void handleTimeLineTagEvent(TagsUpdatedEvent event) {
- TagsFilter tagsFilter = filteredEvents.getFilter().getTagsFilter();
- if (tagsFilter.isSelected() && tagsFilter.isDisabled() == false) {
- Platform.runLater(() -> {
- notificationPane.show(Bundle.VisualizationPanel_tagsAddedOrDeleted(), new ImageView(INFORMATION));
- });
- }
+ public void handleRefreshRequested(RefreshRequestedEvent event) {
+ visualization.refresh();
+ Platform.runLater(() -> {
+ if (Bundle.VisualizationPanel_tagsAddedOrDeleted().equals(notificationPane.getText())) {
+ notificationPane.hide();
+ }
+ });
}
- synchronized private void refreshHistorgram() {
+ /**
+ * Handle a DBUpdatedEvent from the events model by refreshing the
+ * visualization.
+ *
+ * NOTE: This VisualizationPanel must be registered with the
+ * filteredEventsModel's EventBus in order for this handler to be invoked.
+ *
+ * @param event The DBUpdatedEvent to handle.
+ */
+ @Subscribe
+ public void handleDBUpdated(DBUpdatedEvent event) {
+ visualization.refresh();
+ refreshHistorgram();
+ Platform.runLater(notificationPane::hide);
+ }
+ /**
+ * Handle a DataSourceAddedEvent from the events model by showing a
+ * notification.
+ *
+ * NOTE: This VisualizationPanel must be registered with the
+ * filteredEventsModel's EventBus in order for this handler to be invoked.
+ *
+ * @param event The DataSourceAddedEvent to handle.
+ */
+ @Subscribe
+ @NbBundle.Messages({
+ "# {0} - datasource name",
+ "VisualizationPanel.notification.newDataSource={0} has been added as a new datasource. The Timeline DB may be out of date."})
+ public void handlDataSourceAdded(DataSourceAddedEvent event) {
+ Platform.runLater(() -> {
+ notificationPane.getActions().setAll(new UpdateDB(controller));
+ notificationPane.show(Bundle.VisualizationPanel_notification_newDataSource(event.getDataSource().getName()), new ImageView(WARNING));
+ });
+ }
+
+ /**
+ * Handle a DataSourceAnalysisCompletedEvent from the events modelby showing
+ * a notification.
+ *
+ * NOTE: This VisualizationPanel must be registered with the
+ * filteredEventsModel's EventBus in order for this handler to be invoked.
+ *
+ * @param event The DataSourceAnalysisCompletedEvent to handle.
+ */
+ @Subscribe
+ @NbBundle.Messages({
+ "# {0} - datasource name",
+ "VisualizationPanel.notification.analysisComplete=Analysis has finished for {0}. The Timeline DB may be out of date."})
+ public void handleAnalysisCompleted(DataSourceAnalysisCompletedEvent event) {
+ Platform.runLater(() -> {
+ notificationPane.getActions().setAll(new UpdateDB(controller));
+ notificationPane.show(Bundle.VisualizationPanel_notification_analysisComplete(event.getDataSource().getName()), new ImageView(WARNING));
+ });
+ }
+
+ /**
+ * Refresh the Histogram to represent the current state of the DB.
+ */
+ synchronized private void refreshHistorgram() {
if (histogramTask != null) {
histogramTask.cancel(true);
}
@@ -476,7 +524,7 @@ final public class VisualizationPanel extends BorderPane {
bar.prefHeightProperty().bind(histogramBox.heightProperty().multiply(Math.log(bin)).divide(fMax));
bar.setMaxHeight(USE_PREF_SIZE);
bar.setMinHeight(USE_PREF_SIZE);
- bar.setBackground(background);
+ bar.setBackground(GRAY_BACKGROUND);
bar.setOnMouseEntered((MouseEvent event) -> {
Tooltip.install(bar, new Tooltip(bin.toString()));
});
@@ -532,6 +580,61 @@ final public class VisualizationPanel extends BorderPane {
}
}
+ /**
+ * Switch to the given VisualizationMode, by swapping out the hosted
+ * AbstractVislualization for one of the correct type.
+ */
+ private void syncVisualizationMode() {
+ AbstractVisualizationPane, ?, ?, ?> vizPane;
+ VisualizationMode visMode = controller.visualizationModeProperty().get();
+
+ //make new visualization.
+ switch (visMode) {
+ case COUNTS:
+ vizPane = new CountsViewPane(controller);
+ Platform.runLater(() -> countsToggle.setSelected(true));
+ break;
+ case DETAIL:
+ DetailViewPane detailViewPane = new DetailViewPane(controller);
+ Platform.runLater(() -> {
+ detailsToggle.setSelected(true);
+ detailViewPane.setHighLightedEvents(eventsTree.getSelectedEvents());
+ eventsTree.setDetailViewPane(detailViewPane);
+ });
+ vizPane = detailViewPane;
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown VisualizationMode: " + visMode.toString());
+ }
+
+ //Set the new AbstractVisualizationPane as the one hosted by this VisualizationPanel.
+ Platform.runLater(() -> {
+ //clear out old vis.
+ if (visualization != null) {
+ toolBar.getItems().removeAll(visualization.getSettingsNodes());
+ visualization.dispose();
+ }
+
+ visualization = vizPane;
+ //setup new vis.
+ ActionUtils.configureButton(new Refresh(), refreshButton);//configure new refresh action for new visualization
+ visualization.refresh();
+ toolBar.getItems().addAll(2, vizPane.getSettingsNodes());
+ notificationPane.setContent(visualization);
+
+ //listen to has events property and show "dialog" if it is false.
+ visualization.hasVisibleEventsProperty().addListener(hasEvents -> {
+ notificationPane.setContent(visualization.hasVisibleEvents()
+ ? visualization
+ : new StackPane(visualization,
+ NO_EVENTS_BACKGROUND,
+ new NoEventsDialog(() -> notificationPane.setContent(visualization))
+ )
+ );
+ });
+ });
+ }
+
@NbBundle.Messages("NoEventsDialog.titledPane.text=No Visible Events")
private class NoEventsDialog extends StackPane {
@@ -657,4 +760,21 @@ final public class VisualizationPanel extends BorderPane {
}
}
}
+
+ /**
+ * Action that refreshes the Visualization.
+ */
+ private class Refresh extends Action {
+
+ @NbBundle.Messages({
+ "VisualizationPanel.refresh.text=Refresh Vis.",
+ "VisualizationPanel.refresh.longText=Refresh the visualization to include information that is in the DB but not visualized, such as newly updated tags."})
+ Refresh() {
+ super(Bundle.VisualizationPanel_refresh_text());
+ setLongText(Bundle.VisualizationPanel_refresh_longText());
+ setGraphic(new ImageView(REFRESH));
+ setEventHandler(actionEvent -> filteredEvents.postRefreshRequest());
+ disabledProperty().bind(visualization.outOfDateProperty().not());
+ }
+ }
}
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java
index 91649dcf37..3221d797df 100644
--- a/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java
+++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java
@@ -132,7 +132,7 @@ public class CountsViewPane extends AbstractVisualizationPane {
- update();
+ refresh();
syncAxisScaleLabel();
});
syncAxisScaleLabel();
@@ -306,7 +306,7 @@ public class CountsViewPane extends AbstractVisualizationPane> {
+ private class CountsUpdateTask extends VisualizationRefreshTask> {
CountsUpdateTask() {
super(Bundle.CountsViewPane_loggedTask_name(), true);
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/EventCountsChart.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/EventCountsChart.java
index 477ef7eb64..031101ab1e 100644
--- a/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/EventCountsChart.java
+++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/EventCountsChart.java
@@ -403,7 +403,7 @@ final class EventCountsChart extends StackedBarChart implements
Bundle.CountsViewPane_detailSwitchMessage(),
Bundle.CountsViewPane_detailSwitchTitle(), JOptionPane.YES_NO_OPTION);
if (showConfirmDialog == JOptionPane.YES_OPTION) {
- controller.setViewMode(VisualizationMode.DETAIL);
+ controller.setVisualizationMode(VisualizationMode.DETAIL);
}
/*
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java
index 5b9dc12837..05e9165598 100644
--- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java
+++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java
@@ -344,7 +344,7 @@ public class DetailViewPane extends AbstractVisualizationPane {
+ private class DetailsUpdateTask extends VisualizationRefreshTask {
DetailsUpdateTask() {
super(Bundle.DetailViewPane_loggedTask_name(), true);
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterSetPanel.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterSetPanel.java
index 8512c3f819..d7168013ca 100644
--- a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterSetPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterSetPanel.java
@@ -129,9 +129,9 @@ final public class FilterSetPanel extends BorderPane {
hiddenDescriptionsListView.setItems(controller.getQuickHideFilters());
hiddenDescriptionsListView.setCellFactory(listView -> getNewDiscriptionFilterListCell());
- controller.viewModeProperty().addListener(observable -> {
+ controller.visualizationModeProperty().addListener(observable -> {
applyFilters();
- if (controller.viewModeProperty().get() == VisualizationMode.COUNTS) {
+ if (controller.visualizationModeProperty().get() == VisualizationMode.COUNTS) {
dividerPosition = splitPane.getDividerPositions()[0];
splitPane.setDividerPositions(1);
hiddenDescriptionsPane.setExpanded(false);
diff --git a/Core/src/org/sleuthkit/autopsy/timeline/zooming/ZoomSettingsPane.java b/Core/src/org/sleuthkit/autopsy/timeline/zooming/ZoomSettingsPane.java
index d56356d544..9877150e8b 100644
--- a/Core/src/org/sleuthkit/autopsy/timeline/zooming/ZoomSettingsPane.java
+++ b/Core/src/org/sleuthkit/autopsy/timeline/zooming/ZoomSettingsPane.java
@@ -102,7 +102,7 @@ public class ZoomSettingsPane extends TitledPane {
Function.identity());
descrLODLabel.setText(Bundle.ZoomSettingsPane_descrLODLabel_text());
//the description slider is only usefull in the detail view
- descrLODSlider.disableProperty().bind(controller.viewModeProperty().isEqualTo(VisualizationMode.COUNTS));
+ descrLODSlider.disableProperty().bind(controller.visualizationModeProperty().isEqualTo(VisualizationMode.COUNTS));
/**
* In order for the selected value in the time unit slider to correspond
diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanel.form b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanel.form
index 7670d6148a..4c999006a3 100644
--- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanel.form
+++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanel.form
@@ -23,164 +23,192 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+