mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-18 10:37:43 +00:00
Merge branch 'develop' into 7316-update-ra-tocreate-dataArtifacts
This commit is contained in:
commit
848bd4ec35
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2012-2020 Basis Technology Corp.
|
* Copyright 2012-2021 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -124,6 +124,7 @@ import org.sleuthkit.autopsy.ingest.IngestServices;
|
|||||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||||
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService;
|
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService;
|
||||||
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchServiceException;
|
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchServiceException;
|
||||||
|
import org.sleuthkit.autopsy.machinesettings.UserMachinePreferences;
|
||||||
import org.sleuthkit.autopsy.progress.LoggingProgressIndicator;
|
import org.sleuthkit.autopsy.progress.LoggingProgressIndicator;
|
||||||
import org.sleuthkit.autopsy.progress.ModalDialogProgressIndicator;
|
import org.sleuthkit.autopsy.progress.ModalDialogProgressIndicator;
|
||||||
import org.sleuthkit.autopsy.progress.ProgressIndicator;
|
import org.sleuthkit.autopsy.progress.ProgressIndicator;
|
||||||
@ -143,7 +144,6 @@ import org.sleuthkit.datamodel.HostManager.HostsUpdateEvent;
|
|||||||
import org.sleuthkit.datamodel.HostManager.HostsDeletionEvent;
|
import org.sleuthkit.datamodel.HostManager.HostsDeletionEvent;
|
||||||
import org.sleuthkit.datamodel.Image;
|
import org.sleuthkit.datamodel.Image;
|
||||||
import org.sleuthkit.datamodel.OsAccount;
|
import org.sleuthkit.datamodel.OsAccount;
|
||||||
import org.sleuthkit.datamodel.OsAccountManager;
|
|
||||||
import org.sleuthkit.datamodel.OsAccountManager.OsAccountsCreationEvent;
|
import org.sleuthkit.datamodel.OsAccountManager.OsAccountsCreationEvent;
|
||||||
import org.sleuthkit.datamodel.OsAccountManager.OsAccountsUpdateEvent;
|
import org.sleuthkit.datamodel.OsAccountManager.OsAccountsUpdateEvent;
|
||||||
import org.sleuthkit.datamodel.Person;
|
import org.sleuthkit.datamodel.Person;
|
||||||
@ -1478,16 +1478,7 @@ public class Case {
|
|||||||
* @return The temp subdirectory path.
|
* @return The temp subdirectory path.
|
||||||
*/
|
*/
|
||||||
public String getTempDirectory() {
|
public String getTempDirectory() {
|
||||||
// get temp folder scoped to the combination of case name and timestamp
|
return UserMachinePreferences.getTempDirectory();
|
||||||
// provided by getName()
|
|
||||||
Path path = Paths.get(UserPreferences.getAppTempDirectory(), CASE_TEMP_DIR, getName());
|
|
||||||
File f = path.toFile();
|
|
||||||
// verify that the folder exists
|
|
||||||
if (!f.exists()) {
|
|
||||||
f.mkdirs();
|
|
||||||
}
|
|
||||||
|
|
||||||
return path.toAbsolutePath().toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,25 +23,4 @@
|
|||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||||
<SubComponents>
|
|
||||||
<Container class="javax.swing.JScrollPane" name="caseTableScrollPane">
|
|
||||||
<Properties>
|
|
||||||
<Property name="horizontalScrollBarPolicy" type="int" value="31"/>
|
|
||||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
|
||||||
<Dimension value="[0, 5]"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="opaque" type="boolean" value="false"/>
|
|
||||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
|
||||||
<Dimension value="[500, 500]"/>
|
|
||||||
</Property>
|
|
||||||
</Properties>
|
|
||||||
<Constraints>
|
|
||||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
|
||||||
<BorderConstraints direction="Center"/>
|
|
||||||
</Constraint>
|
|
||||||
</Constraints>
|
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
|
||||||
</Container>
|
|
||||||
</SubComponents>
|
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2017-2019 Basis Technology Corp.
|
* Copyright 2017-2021 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.casemodule.multiusercasesbrowser;
|
package org.sleuthkit.autopsy.casemodule.multiusercasesbrowser;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -68,8 +69,7 @@ public final class MultiUserCasesBrowserPanel extends javax.swing.JPanel impleme
|
|||||||
outlineView = new org.openide.explorer.view.OutlineView();
|
outlineView = new org.openide.explorer.view.OutlineView();
|
||||||
outline = this.outlineView.getOutline();
|
outline = this.outlineView.getOutline();
|
||||||
configureOutlineView();
|
configureOutlineView();
|
||||||
caseTableScrollPane.add(outlineView);
|
add(outlineView, BorderLayout.CENTER);
|
||||||
caseTableScrollPane.setViewportView(outlineView);
|
|
||||||
this.setVisible(true);
|
this.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,20 +146,11 @@ public final class MultiUserCasesBrowserPanel extends javax.swing.JPanel impleme
|
|||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
|
|
||||||
caseTableScrollPane = new javax.swing.JScrollPane();
|
|
||||||
|
|
||||||
setMinimumSize(new java.awt.Dimension(0, 5));
|
setMinimumSize(new java.awt.Dimension(0, 5));
|
||||||
setPreferredSize(new java.awt.Dimension(5, 5));
|
setPreferredSize(new java.awt.Dimension(5, 5));
|
||||||
setLayout(new java.awt.BorderLayout());
|
setLayout(new java.awt.BorderLayout());
|
||||||
|
|
||||||
caseTableScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
|
||||||
caseTableScrollPane.setMinimumSize(new java.awt.Dimension(0, 5));
|
|
||||||
caseTableScrollPane.setOpaque(false);
|
|
||||||
caseTableScrollPane.setPreferredSize(new java.awt.Dimension(500, 500));
|
|
||||||
add(caseTableScrollPane, java.awt.BorderLayout.CENTER);
|
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
private javax.swing.JScrollPane caseTableScrollPane;
|
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,8 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.InvalidPathException;
|
import java.nio.file.InvalidPathException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.DriverManager;
|
import java.sql.DriverManager;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
@ -41,7 +43,15 @@ public final class SqliteCentralRepoSettings implements CentralRepoDbConnectivit
|
|||||||
|
|
||||||
public final static String DEFAULT_DBNAME = "central_repository.db"; // NON-NLS
|
public final static String DEFAULT_DBNAME = "central_repository.db"; // NON-NLS
|
||||||
private final static Logger LOGGER = Logger.getLogger(SqliteCentralRepoSettings.class.getName());
|
private final static Logger LOGGER = Logger.getLogger(SqliteCentralRepoSettings.class.getName());
|
||||||
|
private final Path userConfigDir = Paths.get(PlatformUtil.getUserDirectory().getAbsolutePath());
|
||||||
private final static String DEFAULT_DBDIRECTORY = PlatformUtil.getUserDirectory() + File.separator + "central_repository"; // NON-NLS
|
private final static String DEFAULT_DBDIRECTORY = PlatformUtil.getUserDirectory() + File.separator + "central_repository"; // NON-NLS
|
||||||
|
|
||||||
|
//property names
|
||||||
|
private static final String PROFILE_NAME = "CentralRepository";
|
||||||
|
private static final String DATABASE_NAME = "db.sqlite.dbName"; //NON-NLS
|
||||||
|
private static final String DATABASE_PATH = "db.sqlite.dbDirectory"; //NON-NLS
|
||||||
|
private static final String BULK_THRESHOLD = "db.sqlite.bulkThreshold"; //NON-NLS
|
||||||
|
|
||||||
private final static String JDBC_DRIVER = "org.sqlite.JDBC"; // NON-NLS
|
private final static String JDBC_DRIVER = "org.sqlite.JDBC"; // NON-NLS
|
||||||
private final static String JDBC_BASE_URI = "jdbc:sqlite:"; // NON-NLS
|
private final static String JDBC_BASE_URI = "jdbc:sqlite:"; // NON-NLS
|
||||||
private final static String VALIDATION_QUERY = "SELECT count(*) from sqlite_master"; // NON-NLS
|
private final static String VALIDATION_QUERY = "SELECT count(*) from sqlite_master"; // NON-NLS
|
||||||
@ -56,18 +66,18 @@ public final class SqliteCentralRepoSettings implements CentralRepoDbConnectivit
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void loadSettings() {
|
public void loadSettings() {
|
||||||
dbName = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.dbName"); // NON-NLS
|
dbName = ModuleSettings.getConfigSetting(PROFILE_NAME, DATABASE_NAME); // NON-NLS
|
||||||
if (dbName == null || dbName.isEmpty()) {
|
if (dbName == null || dbName.isEmpty()) {
|
||||||
dbName = DEFAULT_DBNAME;
|
dbName = DEFAULT_DBNAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
dbDirectory = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.dbDirectory"); // NON-NLS
|
dbDirectory = readDbPath(); // NON-NLS
|
||||||
if (dbDirectory == null || dbDirectory.isEmpty()) {
|
if (dbDirectory == null || dbDirectory.isEmpty()) {
|
||||||
dbDirectory = DEFAULT_DBDIRECTORY;
|
dbDirectory = DEFAULT_DBDIRECTORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String bulkThresholdString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.bulkThreshold"); // NON-NLS
|
String bulkThresholdString = ModuleSettings.getConfigSetting(PROFILE_NAME, BULK_THRESHOLD); // NON-NLS
|
||||||
if (bulkThresholdString == null || bulkThresholdString.isEmpty()) {
|
if (bulkThresholdString == null || bulkThresholdString.isEmpty()) {
|
||||||
this.bulkThreshold = RdbmsCentralRepo.DEFAULT_BULK_THRESHHOLD;
|
this.bulkThreshold = RdbmsCentralRepo.DEFAULT_BULK_THRESHHOLD;
|
||||||
} else {
|
} else {
|
||||||
@ -96,9 +106,64 @@ public final class SqliteCentralRepoSettings implements CentralRepoDbConnectivit
|
|||||||
public void saveSettings() {
|
public void saveSettings() {
|
||||||
createDbDirectory();
|
createDbDirectory();
|
||||||
|
|
||||||
ModuleSettings.setConfigSetting("CentralRepository", "db.sqlite.dbName", getDbName()); // NON-NLS
|
ModuleSettings.setConfigSetting(PROFILE_NAME, DATABASE_NAME, getDbName()); // NON-NLS
|
||||||
ModuleSettings.setConfigSetting("CentralRepository", "db.sqlite.dbDirectory", getDbDirectory()); // NON-NLS
|
saveDbPath(getDbDirectory()); // NON-NLS
|
||||||
ModuleSettings.setConfigSetting("CentralRepository", "db.sqlite.bulkThreshold", Integer.toString(getBulkThreshold())); // NON-NLS
|
ModuleSettings.setConfigSetting(PROFILE_NAME, BULK_THRESHOLD, Integer.toString(getBulkThreshold())); // NON-NLS
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save CR database path. If the path is inside user directory (e.g.
|
||||||
|
* "C:\Users\USER_NAME\AppData\Roaming\autopsy"), trim that off and save it
|
||||||
|
* as a relative path (i.e it will not start with a “/” or drive letter). Otherwise,
|
||||||
|
* full path is saved. See JIRA-7348.
|
||||||
|
*
|
||||||
|
* @param fullPath Full path to the SQLite db file.
|
||||||
|
*/
|
||||||
|
private void saveDbPath(String fullPath) {
|
||||||
|
Path relativePath = Paths.get(fullPath);
|
||||||
|
// check if the path is within user directory
|
||||||
|
if (Paths.get(fullPath).startsWith(userConfigDir)) {
|
||||||
|
// relativize the path
|
||||||
|
relativePath = userConfigDir.relativize(relativePath);
|
||||||
|
}
|
||||||
|
// Use properties to persist the logo to use.
|
||||||
|
ModuleSettings.setConfigSetting(PROFILE_NAME, DATABASE_PATH, relativePath.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read CD database path from preferences file. Reverses the path relativization performed
|
||||||
|
* in saveDbPath(). If the stored path starts with either “/” or drive letter,
|
||||||
|
* it is a full path, and is returned to the caller. Otherwise, append current user
|
||||||
|
* directory to the saved relative path. See JIRA-7348.
|
||||||
|
*
|
||||||
|
* @return Full path to the SQLite CR database file.
|
||||||
|
*/
|
||||||
|
private String readDbPath() {
|
||||||
|
|
||||||
|
String curPath = ModuleSettings.getConfigSetting(PROFILE_NAME, DATABASE_PATH);
|
||||||
|
|
||||||
|
|
||||||
|
//if has been set, validate it's correct, if not set, return null
|
||||||
|
if (curPath != null && !curPath.isEmpty()) {
|
||||||
|
|
||||||
|
// check if the path is an absolute path (starts with either drive letter or "/")
|
||||||
|
Path driveLetterOrNetwork = Paths.get(curPath).getRoot();
|
||||||
|
if (driveLetterOrNetwork != null) {
|
||||||
|
// absolute path
|
||||||
|
return curPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Path is a relative path. Reverse path relativization performed in saveDbPath()
|
||||||
|
Path absolutePath = userConfigDir.resolve(curPath);
|
||||||
|
curPath = absolutePath.toString();
|
||||||
|
if (new File(curPath).canRead() == false) {
|
||||||
|
//use default
|
||||||
|
LOGGER.log(Level.INFO, "Path to SQLite Central Repository database is not valid: {0}", curPath); //NON-NLS
|
||||||
|
curPath = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return curPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -252,9 +317,9 @@ public final class SqliteCentralRepoSettings implements CentralRepoDbConnectivit
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean isChanged() {
|
boolean isChanged() {
|
||||||
String dbNameString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.dbName"); // NON-NLS
|
String dbNameString = ModuleSettings.getConfigSetting(PROFILE_NAME, DATABASE_NAME); // NON-NLS
|
||||||
String dbDirectoryString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.dbDirectory"); // NON-NLS
|
String dbDirectoryString = readDbPath(); // NON-NLS
|
||||||
String bulkThresholdString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.bulkThreshold"); // NON-NLS
|
String bulkThresholdString = ModuleSettings.getConfigSetting(PROFILE_NAME, BULK_THRESHOLD); // NON-NLS
|
||||||
|
|
||||||
return !dbName.equals(dbNameString)
|
return !dbName.equals(dbNameString)
|
||||||
|| !dbDirectory.equals(dbDirectoryString)
|
|| !dbDirectory.equals(dbDirectoryString)
|
||||||
|
@ -192,7 +192,7 @@ final class MessageViewer extends JPanel implements RelationshipsViewer {
|
|||||||
if (isDescendingFrom(newFocusOwner, rootTablePane)) {
|
if (isDescendingFrom(newFocusOwner, rootTablePane)) {
|
||||||
proxyLookup.setNewLookups(createLookup(rootTablePane.getExplorerManager(), getActionMap()));
|
proxyLookup.setNewLookups(createLookup(rootTablePane.getExplorerManager(), getActionMap()));
|
||||||
} else if (isDescendingFrom(newFocusOwner, this)) {
|
} else if (isDescendingFrom(newFocusOwner, this)) {
|
||||||
proxyLookup.setNewLookups(createLookup(currentPanel.getExplorerManager(), getActionMap()));
|
proxyLookup.setNewLookups(createLookup(threadMessagesPanel.getExplorerManager(), getActionMap()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ class MessagesPanel extends javax.swing.JPanel implements Lookup.Provider {
|
|||||||
outlineViewPanel.setTableColumnsWidth(5, 10, 10, 15, 50, 10);
|
outlineViewPanel.setTableColumnsWidth(5, 10, 10, 15, 50, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessagesPanel(ChildFactory<?> nodeFactory) {
|
MessagesPanel(ChildFactory<?> nodeFactory) {
|
||||||
this();
|
this();
|
||||||
setChildFactory(nodeFactory);
|
setChildFactory(nodeFactory);
|
||||||
}
|
}
|
||||||
@ -123,6 +123,15 @@ class MessagesPanel extends javax.swing.JPanel implements Lookup.Provider {
|
|||||||
return proxyLookup;
|
return proxyLookup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the explorerManager for the table.
|
||||||
|
*
|
||||||
|
* @return The explorer manager for the table.
|
||||||
|
*/
|
||||||
|
ExplorerManager getExplorerManager() {
|
||||||
|
return outlineViewPanel.getExplorerManager();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addNotify() {
|
public void addNotify() {
|
||||||
super.addNotify();
|
super.addNotify();
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
* Copyright 2011-2021 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -50,6 +50,7 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
|||||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||||
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
|
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
|
||||||
import org.sleuthkit.autopsy.python.JythonModuleLoader;
|
import org.sleuthkit.autopsy.python.JythonModuleLoader;
|
||||||
|
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper over Installers in packages in Core module. This is the main
|
* Wrapper over Installers in packages in Core module. This is the main
|
||||||
@ -369,6 +370,7 @@ public class Installer extends ModuleInstall {
|
|||||||
}
|
}
|
||||||
logger.log(Level.INFO, "Autopsy Core restore completed"); //NON-NLS
|
logger.log(Level.INFO, "Autopsy Core restore completed"); //NON-NLS
|
||||||
preloadJython();
|
preloadJython();
|
||||||
|
preloadTranslationServices();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -376,7 +378,7 @@ public class Installer extends ModuleInstall {
|
|||||||
* because we encountered issues related to file locking when initialization
|
* because we encountered issues related to file locking when initialization
|
||||||
* was performed closer to where the bindings are used. See JIRA-6528.
|
* was performed closer to where the bindings are used. See JIRA-6528.
|
||||||
*/
|
*/
|
||||||
private void initializeSevenZip() {
|
private static void initializeSevenZip() {
|
||||||
try {
|
try {
|
||||||
SevenZip.initSevenZipFromPlatformJAR();
|
SevenZip.initSevenZipFromPlatformJAR();
|
||||||
logger.log(Level.INFO, "7zip-java bindings loaded"); //NON-NLS
|
logger.log(Level.INFO, "7zip-java bindings loaded"); //NON-NLS
|
||||||
@ -388,7 +390,7 @@ public class Installer extends ModuleInstall {
|
|||||||
/**
|
/**
|
||||||
* Runs an initial load of the Jython modules to speed up subsequent loads.
|
* Runs an initial load of the Jython modules to speed up subsequent loads.
|
||||||
*/
|
*/
|
||||||
private void preloadJython() {
|
private static void preloadJython() {
|
||||||
Runnable loader = () -> {
|
Runnable loader = () -> {
|
||||||
try {
|
try {
|
||||||
JythonModuleLoader.getIngestModuleFactories();
|
JythonModuleLoader.getIngestModuleFactories();
|
||||||
@ -403,6 +405,22 @@ public class Installer extends ModuleInstall {
|
|||||||
new Thread(loader).start();
|
new Thread(loader).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs an initial load of the translation services to speed up subsequent loads.
|
||||||
|
*/
|
||||||
|
private static void preloadTranslationServices() {
|
||||||
|
Runnable loader = () -> {
|
||||||
|
try {
|
||||||
|
TextTranslationService.getInstance();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
// This is a firewall exception to ensure that any possible exception caused
|
||||||
|
// by this initial load of the translation modules are caught and logged.
|
||||||
|
logger.log(Level.SEVERE, "There was an error while doing an initial load of translation services.", ex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
new Thread(loader).start();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validate() throws IllegalStateException {
|
public void validate() throws IllegalStateException {
|
||||||
super.validate();
|
super.validate();
|
||||||
|
@ -674,8 +674,7 @@ public final class UserPreferences {
|
|||||||
* @return The absolute path to the application temp directory.
|
* @return The absolute path to the application temp directory.
|
||||||
*/
|
*/
|
||||||
public static String getAppTempDirectory() {
|
public static String getAppTempDirectory() {
|
||||||
return Paths.get(UserMachinePreferences.getBaseTempDirectory(), getAppName())
|
return UserMachinePreferences.getTempDirectory();
|
||||||
.toAbsolutePath().toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,6 +27,7 @@ import org.openide.windows.TopComponent;
|
|||||||
import org.openide.windows.WindowManager;
|
import org.openide.windows.WindowManager;
|
||||||
import org.sleuthkit.autopsy.corecomponents.DataContentTopComponent;
|
import org.sleuthkit.autopsy.corecomponents.DataContentTopComponent;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Responsible for opening and closing the core windows when a case is opened
|
* Responsible for opening and closing the core windows when a case is opened
|
||||||
@ -49,7 +50,8 @@ final public class CoreComponentControl {
|
|||||||
* ({@link DataExplorer}, {@link DataResult}, and {@link DataContent})
|
* ({@link DataExplorer}, {@link DataResult}, and {@link DataContent})
|
||||||
*/
|
*/
|
||||||
public static void openCoreWindows() {
|
public static void openCoreWindows() {
|
||||||
// TODO: there has to be a better way to do this.
|
// preload UI components (JIRA-7345). This only takes place the first time Autopsy opens a case.
|
||||||
|
DirectoryTreeTopComponent dtc = DirectoryTreeTopComponent.findInstance();
|
||||||
|
|
||||||
// find the data explorer top components
|
// find the data explorer top components
|
||||||
Collection<? extends DataExplorer> dataExplorers = Lookup.getDefault().lookupAll(DataExplorer.class);
|
Collection<? extends DataExplorer> dataExplorers = Lookup.getDefault().lookupAll(DataExplorer.class);
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.ButtonGroup" name="logoSourceButtonGroup">
|
<Component class="javax.swing.ButtonGroup" name="logoSourceButtonGroup">
|
||||||
</Component>
|
</Component>
|
||||||
|
<Component class="javax.swing.ButtonGroup" name="tempDirChoiceGroup">
|
||||||
|
</Component>
|
||||||
</NonVisualComponents>
|
</NonVisualComponents>
|
||||||
<AuxValues>
|
<AuxValues>
|
||||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||||
@ -24,12 +26,12 @@
|
|||||||
<Layout>
|
<Layout>
|
||||||
<DimensionLayout dim="0">
|
<DimensionLayout dim="0">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Component id="jScrollPane1" alignment="0" pref="648" max="32767" attributes="0"/>
|
<Component id="jScrollPane1" alignment="0" pref="860" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
<DimensionLayout dim="1">
|
<DimensionLayout dim="1">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Component id="jScrollPane1" alignment="0" pref="382" max="32767" attributes="0"/>
|
<Component id="jScrollPane1" alignment="0" pref="620" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
</Layout>
|
</Layout>
|
||||||
@ -418,7 +420,7 @@
|
|||||||
<Properties>
|
<Properties>
|
||||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
||||||
<TitledBorder title="Temp Directory">
|
<TitledBorder title="Root Temp Directory">
|
||||||
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.tempDirectoryPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.tempDirectoryPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</TitledBorder>
|
</TitledBorder>
|
||||||
</Border>
|
</Border>
|
||||||
@ -444,37 +446,53 @@
|
|||||||
<Group type="102" attributes="0">
|
<Group type="102" attributes="0">
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Component id="tempDirectoryWarningLabel" min="-2" pref="615" max="-2" attributes="0"/>
|
<Component id="tempLocalRadio" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="tempCaseRadio" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="tempDirectoryWarningLabel" alignment="0" min="-2" pref="615" max="-2" attributes="0"/>
|
||||||
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<Component id="tempCustomRadio" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Component id="tempOnCustomNoPath" min="-2" max="-2" attributes="0"/>
|
||||||
<Group type="102" attributes="0">
|
<Group type="102" attributes="0">
|
||||||
<Component id="tempDirectoryField" min="-2" pref="367" max="-2" attributes="0"/>
|
<Component id="tempCustomField" min="-2" pref="459" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="tempDirectoryBrowseButton" min="-2" max="-2" attributes="0"/>
|
<Component id="tempDirectoryBrowseButton" min="-2" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
</Group>
|
||||||
|
</Group>
|
||||||
|
<EmptySpace pref="158" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
<DimensionLayout dim="1">
|
<DimensionLayout dim="1">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="tempLocalRadio" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="tempCaseRadio" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Group type="103" groupAlignment="3" attributes="0">
|
<Group type="103" groupAlignment="3" attributes="0">
|
||||||
<Component id="tempDirectoryField" alignment="3" max="32767" attributes="0"/>
|
<Component id="tempCustomRadio" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="tempCustomField" alignment="3" max="32767" attributes="0"/>
|
||||||
<Component id="tempDirectoryBrowseButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
<Component id="tempDirectoryBrowseButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||||
|
<Component id="tempOnCustomNoPath" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace type="unrelated" max="32767" attributes="0"/>
|
||||||
<Component id="tempDirectoryWarningLabel" min="-2" max="-2" attributes="0"/>
|
<Component id="tempDirectoryWarningLabel" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
<EmptySpace min="-2" pref="14" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
</Layout>
|
</Layout>
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Component class="javax.swing.JTextField" name="tempDirectoryField">
|
<Component class="javax.swing.JTextField" name="tempCustomField">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.tempDirectoryField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.tempCustomField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
@ -498,6 +516,55 @@
|
|||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
|
<Component class="javax.swing.JRadioButton" name="tempLocalRadio">
|
||||||
|
<Properties>
|
||||||
|
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||||
|
<ComponentRef name="tempDirChoiceGroup"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.tempLocalRadio.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="tempLocalRadioActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JRadioButton" name="tempCaseRadio">
|
||||||
|
<Properties>
|
||||||
|
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||||
|
<ComponentRef name="tempDirChoiceGroup"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.tempCaseRadio.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="tempCaseRadioActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JRadioButton" name="tempCustomRadio">
|
||||||
|
<Properties>
|
||||||
|
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||||
|
<ComponentRef name="tempDirChoiceGroup"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.tempCustomRadio.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="tempCustomRadioActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JLabel" name="tempOnCustomNoPath">
|
||||||
|
<Properties>
|
||||||
|
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||||
|
<Connection code="java.awt.Color.RED" type="code"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.tempOnCustomNoPath.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Container>
|
</Container>
|
||||||
<Container class="javax.swing.JPanel" name="rdpPanel">
|
<Container class="javax.swing.JPanel" name="rdpPanel">
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2019 Basis Technology Corp.
|
* Copyright 2011-2021 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -38,6 +38,7 @@ import javax.swing.JOptionPane;
|
|||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.event.DocumentEvent;
|
import javax.swing.event.DocumentEvent;
|
||||||
import javax.swing.event.DocumentListener;
|
import javax.swing.event.DocumentListener;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.netbeans.spi.options.OptionsPanelController;
|
import org.netbeans.spi.options.OptionsPanelController;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
@ -47,9 +48,9 @@ import org.sleuthkit.autopsy.casemodule.GeneralFilter;
|
|||||||
import org.sleuthkit.autopsy.machinesettings.UserMachinePreferences;
|
import org.sleuthkit.autopsy.machinesettings.UserMachinePreferences;
|
||||||
import org.sleuthkit.autopsy.machinesettings.UserMachinePreferencesException;
|
import org.sleuthkit.autopsy.machinesettings.UserMachinePreferencesException;
|
||||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||||
import org.sleuthkit.autopsy.coreutils.Version;
|
import org.sleuthkit.autopsy.coreutils.Version;
|
||||||
|
import org.sleuthkit.autopsy.machinesettings.UserMachinePreferences.TempDirChoice;
|
||||||
import org.sleuthkit.autopsy.report.ReportBranding;
|
import org.sleuthkit.autopsy.report.ReportBranding;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,7 +78,6 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private final JFileChooser logoFileChooser;
|
private final JFileChooser logoFileChooser;
|
||||||
private final JFileChooser tempDirChooser;
|
private final JFileChooser tempDirChooser;
|
||||||
private final TextFieldListener textFieldListener;
|
|
||||||
private static final String ETC_FOLDER_NAME = "etc";
|
private static final String ETC_FOLDER_NAME = "etc";
|
||||||
private static final String CONFIG_FILE_EXTENSION = ".conf";
|
private static final String CONFIG_FILE_EXTENSION = ".conf";
|
||||||
private static final long ONE_BILLION = 1000000000L; //used to roughly convert system memory from bytes to gigabytes
|
private static final long ONE_BILLION = 1000000000L; //used to roughly convert system memory from bytes to gigabytes
|
||||||
@ -87,6 +87,8 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
private static final Logger logger = Logger.getLogger(AutopsyOptionsPanel.class.getName());
|
private static final Logger logger = Logger.getLogger(AutopsyOptionsPanel.class.getName());
|
||||||
private String initialMemValue = Long.toString(Runtime.getRuntime().maxMemory() / ONE_BILLION);
|
private String initialMemValue = Long.toString(Runtime.getRuntime().maxMemory() / ONE_BILLION);
|
||||||
|
|
||||||
|
private final ReportBranding reportBranding;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiate the Autopsy options panel.
|
* Instantiate the Autopsy options panel.
|
||||||
*/
|
*/
|
||||||
@ -116,10 +118,12 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
solrMaxHeapSpinner.setModel(new javax.swing.SpinnerNumberModel(UserPreferences.getMaxSolrVMSize(),
|
solrMaxHeapSpinner.setModel(new javax.swing.SpinnerNumberModel(UserPreferences.getMaxSolrVMSize(),
|
||||||
JVM_MEMORY_STEP_SIZE_MB, ((int) getSystemMemoryInGB()) * MEGA_IN_GIGA, JVM_MEMORY_STEP_SIZE_MB));
|
JVM_MEMORY_STEP_SIZE_MB, ((int) getSystemMemoryInGB()) * MEGA_IN_GIGA, JVM_MEMORY_STEP_SIZE_MB));
|
||||||
|
|
||||||
textFieldListener = new TextFieldListener();
|
TextFieldListener textFieldListener = new TextFieldListener();
|
||||||
agencyLogoPathField.getDocument().addDocumentListener(textFieldListener);
|
agencyLogoPathField.getDocument().addDocumentListener(textFieldListener);
|
||||||
tempDirectoryField.getDocument().addDocumentListener(textFieldListener);
|
tempCustomField.getDocument().addDocumentListener(new TempCustomTextListener());
|
||||||
logFileCount.setText(String.valueOf(UserPreferences.getLogFileCount()));
|
logFileCount.setText(String.valueOf(UserPreferences.getLogFileCount()));
|
||||||
|
|
||||||
|
reportBranding = new ReportBranding();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -299,20 +303,45 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
return new String[]{};
|
return new String[]{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void evaluateTempDirState() {
|
||||||
|
boolean caseOpen = Case.isCaseOpen();
|
||||||
|
boolean customSelected = tempCustomRadio.isSelected();
|
||||||
|
|
||||||
|
tempDirectoryBrowseButton.setEnabled(!caseOpen && customSelected);
|
||||||
|
tempCustomField.setEnabled(!caseOpen && customSelected);
|
||||||
|
|
||||||
|
tempOnCustomNoPath.setVisible(customSelected && StringUtils.isBlank(tempCustomField.getText()));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the saved user preferences.
|
* Load the saved user preferences.
|
||||||
*/
|
*/
|
||||||
void load() {
|
void load() {
|
||||||
String path = ModuleSettings.getConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP);
|
String path = reportBranding.getAgencyLogoPath();
|
||||||
boolean useDefault = (path == null || path.isEmpty());
|
boolean useDefault = (path == null || path.isEmpty());
|
||||||
defaultLogoRB.setSelected(useDefault);
|
defaultLogoRB.setSelected(useDefault);
|
||||||
specifyLogoRB.setSelected(!useDefault);
|
specifyLogoRB.setSelected(!useDefault);
|
||||||
agencyLogoPathField.setEnabled(!useDefault);
|
agencyLogoPathField.setEnabled(!useDefault);
|
||||||
browseLogosButton.setEnabled(!useDefault);
|
browseLogosButton.setEnabled(!useDefault);
|
||||||
tempDirectoryField.setText(UserMachinePreferences.getBaseTempDirectory());
|
|
||||||
|
tempCustomField.setText(UserMachinePreferences.getCustomTempDirectory());
|
||||||
|
switch (UserMachinePreferences.getTempDirChoice()) {
|
||||||
|
case CASE:
|
||||||
|
tempCaseRadio.setSelected(true);
|
||||||
|
break;
|
||||||
|
case CUSTOM:
|
||||||
|
tempCustomRadio.setSelected(true);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case SYSTEM:
|
||||||
|
tempLocalRadio.setSelected(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
evaluateTempDirState();
|
||||||
|
|
||||||
logFileCount.setText(String.valueOf(UserPreferences.getLogFileCount()));
|
logFileCount.setText(String.valueOf(UserPreferences.getLogFileCount()));
|
||||||
solrMaxHeapSpinner.setValue(UserPreferences.getMaxSolrVMSize());
|
solrMaxHeapSpinner.setValue(UserPreferences.getMaxSolrVMSize());
|
||||||
tempDirectoryField.setText(UserMachinePreferences.getBaseTempDirectory());
|
|
||||||
try {
|
try {
|
||||||
updateAgencyLogo(path);
|
updateAgencyLogo(path);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
@ -333,9 +362,13 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
|
|
||||||
private void setTempDirEnabled() {
|
private void setTempDirEnabled() {
|
||||||
boolean enabled = !Case.isCaseOpen();
|
boolean enabled = !Case.isCaseOpen();
|
||||||
this.tempDirectoryBrowseButton.setEnabled(enabled);
|
|
||||||
this.tempDirectoryField.setEnabled(enabled);
|
this.tempCaseRadio.setEnabled(enabled);
|
||||||
|
this.tempCustomRadio.setEnabled(enabled);
|
||||||
|
this.tempLocalRadio.setEnabled(enabled);
|
||||||
|
|
||||||
this.tempDirectoryWarningLabel.setVisible(!enabled);
|
this.tempDirectoryWarningLabel.setVisible(!enabled);
|
||||||
|
evaluateTempDirState();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -367,12 +400,14 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
@Messages({
|
@Messages({
|
||||||
"AutopsyOptionsPanel_storeTempDir_onError_title=Error Saving Temporary Directory",
|
"AutopsyOptionsPanel_storeTempDir_onError_title=Error Saving Temporary Directory",
|
||||||
"# {0} - path",
|
"# {0} - path",
|
||||||
"AutopsyOptionsPanel_storeTempDir_onError_description=There was an error creating the temporary directory on the filesystem at: {0}.",})
|
"AutopsyOptionsPanel_storeTempDir_onError_description=There was an error creating the temporary directory on the filesystem at: {0}.",
|
||||||
|
"AutopsyOptionsPanel_storeTempDir_onChoiceError_title=Error Saving Temporary Directory Choice",
|
||||||
|
"AutopsyOptionsPanel_storeTempDir_onChoiceError_description=There was an error updating temporary directory choice selection.",})
|
||||||
private void storeTempDir() {
|
private void storeTempDir() {
|
||||||
String tempDirectoryPath = tempDirectoryField.getText();
|
String tempDirectoryPath = tempCustomField.getText();
|
||||||
if (!UserMachinePreferences.getBaseTempDirectory().equals(tempDirectoryPath)) {
|
if (!UserMachinePreferences.getCustomTempDirectory().equals(tempDirectoryPath)) {
|
||||||
try {
|
try {
|
||||||
UserMachinePreferences.setBaseTempDirectory(tempDirectoryPath);
|
UserMachinePreferences.setCustomTempDirectory(tempDirectoryPath);
|
||||||
} catch (UserMachinePreferencesException ex) {
|
} catch (UserMachinePreferencesException ex) {
|
||||||
logger.log(Level.WARNING, "There was an error creating the temporary directory defined by the user: " + tempDirectoryPath, ex);
|
logger.log(Level.WARNING, "There was an error creating the temporary directory defined by the user: " + tempDirectoryPath, ex);
|
||||||
SwingUtilities.invokeLater(() -> {
|
SwingUtilities.invokeLater(() -> {
|
||||||
@ -383,6 +418,29 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TempDirChoice choice;
|
||||||
|
if (tempCaseRadio.isSelected()) {
|
||||||
|
choice = TempDirChoice.CASE;
|
||||||
|
} else if (tempCustomRadio.isSelected()) {
|
||||||
|
choice = TempDirChoice.CUSTOM;
|
||||||
|
} else {
|
||||||
|
choice = TempDirChoice.SYSTEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!choice.equals(UserMachinePreferences.getTempDirChoice())) {
|
||||||
|
try {
|
||||||
|
UserMachinePreferences.setTempDirChoice(choice);
|
||||||
|
} catch (UserMachinePreferencesException ex) {
|
||||||
|
logger.log(Level.WARNING, "There was an error updating choice to: " + choice.name(), ex);
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
JOptionPane.showMessageDialog(this,
|
||||||
|
String.format("<html>%s</html>", Bundle.AutopsyOptionsPanel_storeTempDir_onChoiceError_description()),
|
||||||
|
Bundle.AutopsyOptionsPanel_storeTempDir_onChoiceError_title(),
|
||||||
|
JOptionPane.ERROR_MESSAGE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -395,10 +453,10 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
if (!agencyLogoPathField.getText().isEmpty()) {
|
if (!agencyLogoPathField.getText().isEmpty()) {
|
||||||
File file = new File(agencyLogoPathField.getText());
|
File file = new File(agencyLogoPathField.getText());
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
ModuleSettings.setConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP, agencyLogoPathField.getText());
|
reportBranding.setAgencyLogoPath(agencyLogoPathField.getText());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ModuleSettings.setConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP, "");
|
reportBranding.setAgencyLogoPath("");
|
||||||
}
|
}
|
||||||
UserPreferences.setMaxSolrVMSize((int) solrMaxHeapSpinner.getValue());
|
UserPreferences.setMaxSolrVMSize((int) solrMaxHeapSpinner.getValue());
|
||||||
if (memField.isEnabled()) { //if the field could of been changed we need to try and save it
|
if (memField.isEnabled()) { //if the field could of been changed we need to try and save it
|
||||||
@ -551,6 +609,32 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listens for changes in the temp directory custom directory text field.
|
||||||
|
*/
|
||||||
|
private class TempCustomTextListener extends TextFieldListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void changedUpdate(DocumentEvent e) {
|
||||||
|
evaluateTempDirState();
|
||||||
|
super.changedUpdate(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUpdate(DocumentEvent e) {
|
||||||
|
evaluateTempDirState();
|
||||||
|
super.changedUpdate(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insertUpdate(DocumentEvent e) {
|
||||||
|
evaluateTempDirState();
|
||||||
|
super.changedUpdate(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called from within the constructor to initialize the form.
|
* This method is called from within the constructor to initialize the form.
|
||||||
* WARNING: Do NOT modify this code. The content of this method is always
|
* WARNING: Do NOT modify this code. The content of this method is always
|
||||||
@ -563,6 +647,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
fileSelectionButtonGroup = new javax.swing.ButtonGroup();
|
fileSelectionButtonGroup = new javax.swing.ButtonGroup();
|
||||||
displayTimesButtonGroup = new javax.swing.ButtonGroup();
|
displayTimesButtonGroup = new javax.swing.ButtonGroup();
|
||||||
logoSourceButtonGroup = new javax.swing.ButtonGroup();
|
logoSourceButtonGroup = new javax.swing.ButtonGroup();
|
||||||
|
tempDirChoiceGroup = new javax.swing.ButtonGroup();
|
||||||
jScrollPane1 = new javax.swing.JScrollPane();
|
jScrollPane1 = new javax.swing.JScrollPane();
|
||||||
javax.swing.JPanel mainPanel = new javax.swing.JPanel();
|
javax.swing.JPanel mainPanel = new javax.swing.JPanel();
|
||||||
logoPanel = new javax.swing.JPanel();
|
logoPanel = new javax.swing.JPanel();
|
||||||
@ -589,9 +674,13 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
solrMaxHeapSpinner = new javax.swing.JSpinner();
|
solrMaxHeapSpinner = new javax.swing.JSpinner();
|
||||||
solrJVMHeapWarning = new javax.swing.JLabel();
|
solrJVMHeapWarning = new javax.swing.JLabel();
|
||||||
tempDirectoryPanel = new javax.swing.JPanel();
|
tempDirectoryPanel = new javax.swing.JPanel();
|
||||||
tempDirectoryField = new javax.swing.JTextField();
|
tempCustomField = new javax.swing.JTextField();
|
||||||
tempDirectoryBrowseButton = new javax.swing.JButton();
|
tempDirectoryBrowseButton = new javax.swing.JButton();
|
||||||
tempDirectoryWarningLabel = new javax.swing.JLabel();
|
tempDirectoryWarningLabel = new javax.swing.JLabel();
|
||||||
|
tempLocalRadio = new javax.swing.JRadioButton();
|
||||||
|
tempCaseRadio = new javax.swing.JRadioButton();
|
||||||
|
tempCustomRadio = new javax.swing.JRadioButton();
|
||||||
|
tempOnCustomNoPath = new javax.swing.JLabel();
|
||||||
rdpPanel = new javax.swing.JPanel();
|
rdpPanel = new javax.swing.JPanel();
|
||||||
javax.swing.JScrollPane sizingScrollPane = new javax.swing.JScrollPane();
|
javax.swing.JScrollPane sizingScrollPane = new javax.swing.JScrollPane();
|
||||||
javax.swing.JTextPane sizingTextPane = new javax.swing.JTextPane();
|
javax.swing.JTextPane sizingTextPane = new javax.swing.JTextPane();
|
||||||
@ -818,7 +907,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
tempDirectoryPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.tempDirectoryPanel.border.title"))); // NOI18N
|
tempDirectoryPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.tempDirectoryPanel.border.title"))); // NOI18N
|
||||||
tempDirectoryPanel.setName(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.tempDirectoryPanel.name")); // NOI18N
|
tempDirectoryPanel.setName(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.tempDirectoryPanel.name")); // NOI18N
|
||||||
|
|
||||||
tempDirectoryField.setText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.tempDirectoryField.text")); // NOI18N
|
tempCustomField.setText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.tempCustomField.text")); // NOI18N
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(tempDirectoryBrowseButton, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.tempDirectoryBrowseButton.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(tempDirectoryBrowseButton, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.tempDirectoryBrowseButton.text")); // NOI18N
|
||||||
tempDirectoryBrowseButton.addActionListener(new java.awt.event.ActionListener() {
|
tempDirectoryBrowseButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
@ -830,6 +919,33 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
tempDirectoryWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/warning16.png"))); // NOI18N
|
tempDirectoryWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/warning16.png"))); // NOI18N
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(tempDirectoryWarningLabel, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.tempDirectoryWarningLabel.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(tempDirectoryWarningLabel, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.tempDirectoryWarningLabel.text")); // NOI18N
|
||||||
|
|
||||||
|
tempDirChoiceGroup.add(tempLocalRadio);
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(tempLocalRadio, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.tempLocalRadio.text")); // NOI18N
|
||||||
|
tempLocalRadio.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
tempLocalRadioActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tempDirChoiceGroup.add(tempCaseRadio);
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(tempCaseRadio, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.tempCaseRadio.text")); // NOI18N
|
||||||
|
tempCaseRadio.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
tempCaseRadioActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tempDirChoiceGroup.add(tempCustomRadio);
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(tempCustomRadio, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.tempCustomRadio.text")); // NOI18N
|
||||||
|
tempCustomRadio.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
tempCustomRadioActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tempOnCustomNoPath.setForeground(java.awt.Color.RED);
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(tempOnCustomNoPath, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.tempOnCustomNoPath.text")); // NOI18N
|
||||||
|
|
||||||
javax.swing.GroupLayout tempDirectoryPanelLayout = new javax.swing.GroupLayout(tempDirectoryPanel);
|
javax.swing.GroupLayout tempDirectoryPanelLayout = new javax.swing.GroupLayout(tempDirectoryPanel);
|
||||||
tempDirectoryPanel.setLayout(tempDirectoryPanelLayout);
|
tempDirectoryPanel.setLayout(tempDirectoryPanelLayout);
|
||||||
tempDirectoryPanelLayout.setHorizontalGroup(
|
tempDirectoryPanelLayout.setHorizontalGroup(
|
||||||
@ -837,23 +953,37 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
.addGroup(tempDirectoryPanelLayout.createSequentialGroup()
|
.addGroup(tempDirectoryPanelLayout.createSequentialGroup()
|
||||||
.addContainerGap()
|
.addContainerGap()
|
||||||
.addGroup(tempDirectoryPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(tempDirectoryPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addComponent(tempLocalRadio)
|
||||||
|
.addComponent(tempCaseRadio)
|
||||||
.addComponent(tempDirectoryWarningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 615, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(tempDirectoryWarningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 615, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addGroup(tempDirectoryPanelLayout.createSequentialGroup()
|
.addGroup(tempDirectoryPanelLayout.createSequentialGroup()
|
||||||
.addComponent(tempDirectoryField, javax.swing.GroupLayout.PREFERRED_SIZE, 367, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(tempCustomRadio)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addComponent(tempDirectoryBrowseButton)))
|
.addGroup(tempDirectoryPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addGap(0, 0, Short.MAX_VALUE))
|
.addComponent(tempOnCustomNoPath)
|
||||||
|
.addGroup(tempDirectoryPanelLayout.createSequentialGroup()
|
||||||
|
.addComponent(tempCustomField, javax.swing.GroupLayout.PREFERRED_SIZE, 459, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(tempDirectoryBrowseButton)))))
|
||||||
|
.addContainerGap(158, Short.MAX_VALUE))
|
||||||
);
|
);
|
||||||
tempDirectoryPanelLayout.setVerticalGroup(
|
tempDirectoryPanelLayout.setVerticalGroup(
|
||||||
tempDirectoryPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
tempDirectoryPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addGroup(tempDirectoryPanelLayout.createSequentialGroup()
|
.addGroup(tempDirectoryPanelLayout.createSequentialGroup()
|
||||||
.addContainerGap()
|
.addContainerGap()
|
||||||
|
.addComponent(tempLocalRadio)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(tempCaseRadio)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addGroup(tempDirectoryPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
.addGroup(tempDirectoryPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
.addComponent(tempDirectoryField)
|
.addComponent(tempCustomRadio)
|
||||||
|
.addComponent(tempCustomField)
|
||||||
.addComponent(tempDirectoryBrowseButton))
|
.addComponent(tempDirectoryBrowseButton))
|
||||||
.addGap(18, 18, 18)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||||
|
.addComponent(tempOnCustomNoPath)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||||
.addComponent(tempDirectoryWarningLabel)
|
.addComponent(tempDirectoryWarningLabel)
|
||||||
.addContainerGap())
|
.addGap(14, 14, 14))
|
||||||
);
|
);
|
||||||
|
|
||||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
@ -906,11 +1036,11 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
this.setLayout(layout);
|
this.setLayout(layout);
|
||||||
layout.setHorizontalGroup(
|
layout.setHorizontalGroup(
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 648, Short.MAX_VALUE)
|
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 860, Short.MAX_VALUE)
|
||||||
);
|
);
|
||||||
layout.setVerticalGroup(
|
layout.setVerticalGroup(
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 382, Short.MAX_VALUE)
|
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 620, Short.MAX_VALUE)
|
||||||
);
|
);
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
@ -927,7 +1057,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
if (!f.exists() && !f.mkdirs()) {
|
if (!f.exists() && !f.mkdirs()) {
|
||||||
throw new InvalidPathException(specifiedPath, "Unable to create parent directories leading to " + specifiedPath);
|
throw new InvalidPathException(specifiedPath, "Unable to create parent directories leading to " + specifiedPath);
|
||||||
}
|
}
|
||||||
tempDirectoryField.setText(specifiedPath);
|
tempCustomField.setText(specifiedPath);
|
||||||
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
||||||
} catch (InvalidPathException ex) {
|
} catch (InvalidPathException ex) {
|
||||||
logger.log(Level.WARNING, "Unable to create temporary directory in " + specifiedPath, ex);
|
logger.log(Level.WARNING, "Unable to create temporary directory in " + specifiedPath, ex);
|
||||||
@ -971,7 +1101,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
browseLogosButton.setEnabled(true);
|
browseLogosButton.setEnabled(true);
|
||||||
try {
|
try {
|
||||||
if (agencyLogoPathField.getText().isEmpty()) {
|
if (agencyLogoPathField.getText().isEmpty()) {
|
||||||
String path = ModuleSettings.getConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP);
|
String path = reportBranding.getAgencyLogoPath();
|
||||||
if (path != null && !path.isEmpty()) {
|
if (path != null && !path.isEmpty()) {
|
||||||
updateAgencyLogo(path);
|
updateAgencyLogo(path);
|
||||||
}
|
}
|
||||||
@ -1017,6 +1147,21 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
}
|
}
|
||||||
}//GEN-LAST:event_browseLogosButtonActionPerformed
|
}//GEN-LAST:event_browseLogosButtonActionPerformed
|
||||||
|
|
||||||
|
private void tempLocalRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tempLocalRadioActionPerformed
|
||||||
|
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
||||||
|
evaluateTempDirState();
|
||||||
|
}//GEN-LAST:event_tempLocalRadioActionPerformed
|
||||||
|
|
||||||
|
private void tempCaseRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tempCaseRadioActionPerformed
|
||||||
|
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
||||||
|
evaluateTempDirState();
|
||||||
|
}//GEN-LAST:event_tempCaseRadioActionPerformed
|
||||||
|
|
||||||
|
private void tempCustomRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tempCustomRadioActionPerformed
|
||||||
|
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
||||||
|
evaluateTempDirState();
|
||||||
|
}//GEN-LAST:event_tempCustomRadioActionPerformed
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
private javax.swing.JTextField agencyLogoPathField;
|
private javax.swing.JTextField agencyLogoPathField;
|
||||||
private javax.swing.JLabel agencyLogoPathFieldValidationLabel;
|
private javax.swing.JLabel agencyLogoPathFieldValidationLabel;
|
||||||
@ -1045,10 +1190,15 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
private javax.swing.JSpinner solrMaxHeapSpinner;
|
private javax.swing.JSpinner solrMaxHeapSpinner;
|
||||||
private javax.swing.JRadioButton specifyLogoRB;
|
private javax.swing.JRadioButton specifyLogoRB;
|
||||||
private javax.swing.JLabel systemMemoryTotal;
|
private javax.swing.JLabel systemMemoryTotal;
|
||||||
|
private javax.swing.JRadioButton tempCaseRadio;
|
||||||
|
private javax.swing.JTextField tempCustomField;
|
||||||
|
private javax.swing.JRadioButton tempCustomRadio;
|
||||||
|
private javax.swing.ButtonGroup tempDirChoiceGroup;
|
||||||
private javax.swing.JButton tempDirectoryBrowseButton;
|
private javax.swing.JButton tempDirectoryBrowseButton;
|
||||||
private javax.swing.JTextField tempDirectoryField;
|
|
||||||
private javax.swing.JPanel tempDirectoryPanel;
|
private javax.swing.JPanel tempDirectoryPanel;
|
||||||
private javax.swing.JLabel tempDirectoryWarningLabel;
|
private javax.swing.JLabel tempDirectoryWarningLabel;
|
||||||
|
private javax.swing.JRadioButton tempLocalRadio;
|
||||||
|
private javax.swing.JLabel tempOnCustomNoPath;
|
||||||
private javax.swing.JLabel totalMemoryLabel;
|
private javax.swing.JLabel totalMemoryLabel;
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
|
@ -188,12 +188,11 @@ MultiUserSettingsPanel.restartRequiredLabel.text=Application restart required to
|
|||||||
MultiUserSettingsPanel.MustRestart=Autopsy must be restarted for new configuration to take effect
|
MultiUserSettingsPanel.MustRestart=Autopsy must be restarted for new configuration to take effect
|
||||||
MultiUserSettingsPanel.lbSolrNote1.text=Enter Solr 8 and/or Solr 4 server settings.
|
MultiUserSettingsPanel.lbSolrNote1.text=Enter Solr 8 and/or Solr 4 server settings.
|
||||||
MultiUserSettingsPanel.lbSolrNote2.text=New text indexing can only be done with Solr 8.
|
MultiUserSettingsPanel.lbSolrNote2.text=New text indexing can only be done with Solr 8.
|
||||||
AutopsyOptionsPanel.tempDirectoryField.text=
|
|
||||||
AutopsyOptionsPanel.tempDirectoryBrowseButton.text=Browse
|
AutopsyOptionsPanel.tempDirectoryBrowseButton.text=Browse
|
||||||
AutopsyOptionsPanel.a.AccessibleContext.accessibleName=Temp Directory
|
AutopsyOptionsPanel.a.AccessibleContext.accessibleName=Temp Directory
|
||||||
AutopsyOptionsPanel.tempDirectoryPanel.AccessibleContext.accessibleName=Temp Directory
|
AutopsyOptionsPanel.tempDirectoryPanel.AccessibleContext.accessibleName=Temp Directory
|
||||||
AutopsyOptionsPanel.tempDirectoryPanel.name=Temp Directory
|
AutopsyOptionsPanel.tempDirectoryPanel.name=Temp Directory
|
||||||
AutopsyOptionsPanel.tempDirectoryPanel.border.title=Temp Directory
|
AutopsyOptionsPanel.tempDirectoryPanel.border.title=Root Temp Directory
|
||||||
AutopsyOptionsPanel.tempDirectoryWarningLabel.text=Close the current case to change the temporary directory.
|
AutopsyOptionsPanel.tempDirectoryWarningLabel.text=Close the current case to change the temporary directory.
|
||||||
AutopsyOptionsPanel.solrJVMHeapWarning.text=NOTE: Setting this too large may impact overall performance.
|
AutopsyOptionsPanel.solrJVMHeapWarning.text=NOTE: Setting this too large may impact overall performance.
|
||||||
AutopsyOptionsPanel.maxMemoryUnitsLabel2.text=MB
|
AutopsyOptionsPanel.maxMemoryUnitsLabel2.text=MB
|
||||||
@ -247,3 +246,8 @@ AutopsyOptionsPanel.agencyLogoPathField.text=
|
|||||||
AutopsyOptionsPanel.logoPanel.border.title=Logo
|
AutopsyOptionsPanel.logoPanel.border.title=Logo
|
||||||
ViewPreferencesPanel.radioGroupByPersonHost.text=Group by Person/Host
|
ViewPreferencesPanel.radioGroupByPersonHost.text=Group by Person/Host
|
||||||
ViewPreferencesPanel.radioGroupByDataType.text=Group by Data Type
|
ViewPreferencesPanel.radioGroupByDataType.text=Group by Data Type
|
||||||
|
AutopsyOptionsPanel.tempLocalRadio.text=Local temp directory
|
||||||
|
AutopsyOptionsPanel.tempCaseRadio.text=Temp folder in case directory
|
||||||
|
AutopsyOptionsPanel.tempCustomRadio.text=Custom
|
||||||
|
AutopsyOptionsPanel.tempCustomField.text=
|
||||||
|
AutopsyOptionsPanel.tempOnCustomNoPath.text=Please select a path for the custom root temp directory.
|
||||||
|
@ -12,6 +12,8 @@ AutopsyOptionsPanel.memFieldValidationLabel.noValueEntered.text=No value entered
|
|||||||
AutopsyOptionsPanel.memFieldValidationLabel.overMaxMemory.text=Value must be less than the total system memory of {0}GB
|
AutopsyOptionsPanel.memFieldValidationLabel.overMaxMemory.text=Value must be less than the total system memory of {0}GB
|
||||||
# {0} - minimumMemory
|
# {0} - minimumMemory
|
||||||
AutopsyOptionsPanel.memFieldValidationLabel.underMinMemory.text=Value must be at least {0}GB
|
AutopsyOptionsPanel.memFieldValidationLabel.underMinMemory.text=Value must be at least {0}GB
|
||||||
|
AutopsyOptionsPanel_storeTempDir_onChoiceError_description=There was an error updating temporary directory choice selection.
|
||||||
|
AutopsyOptionsPanel_storeTempDir_onChoiceError_title=Error Saving Temporary Directory Choice
|
||||||
# {0} - path
|
# {0} - path
|
||||||
AutopsyOptionsPanel_storeTempDir_onError_description=There was an error creating the temporary directory on the filesystem at: {0}.
|
AutopsyOptionsPanel_storeTempDir_onError_description=There was an error creating the temporary directory on the filesystem at: {0}.
|
||||||
AutopsyOptionsPanel_storeTempDir_onError_title=Error Saving Temporary Directory
|
AutopsyOptionsPanel_storeTempDir_onError_title=Error Saving Temporary Directory
|
||||||
@ -246,12 +248,11 @@ MultiUserSettingsPanel.restartRequiredLabel.text=Application restart required to
|
|||||||
MultiUserSettingsPanel.MustRestart=Autopsy must be restarted for new configuration to take effect
|
MultiUserSettingsPanel.MustRestart=Autopsy must be restarted for new configuration to take effect
|
||||||
MultiUserSettingsPanel.lbSolrNote1.text=Enter Solr 8 and/or Solr 4 server settings.
|
MultiUserSettingsPanel.lbSolrNote1.text=Enter Solr 8 and/or Solr 4 server settings.
|
||||||
MultiUserSettingsPanel.lbSolrNote2.text=New text indexing can only be done with Solr 8.
|
MultiUserSettingsPanel.lbSolrNote2.text=New text indexing can only be done with Solr 8.
|
||||||
AutopsyOptionsPanel.tempDirectoryField.text=
|
|
||||||
AutopsyOptionsPanel.tempDirectoryBrowseButton.text=Browse
|
AutopsyOptionsPanel.tempDirectoryBrowseButton.text=Browse
|
||||||
AutopsyOptionsPanel.a.AccessibleContext.accessibleName=Temp Directory
|
AutopsyOptionsPanel.a.AccessibleContext.accessibleName=Temp Directory
|
||||||
AutopsyOptionsPanel.tempDirectoryPanel.AccessibleContext.accessibleName=Temp Directory
|
AutopsyOptionsPanel.tempDirectoryPanel.AccessibleContext.accessibleName=Temp Directory
|
||||||
AutopsyOptionsPanel.tempDirectoryPanel.name=Temp Directory
|
AutopsyOptionsPanel.tempDirectoryPanel.name=Temp Directory
|
||||||
AutopsyOptionsPanel.tempDirectoryPanel.border.title=Temp Directory
|
AutopsyOptionsPanel.tempDirectoryPanel.border.title=Root Temp Directory
|
||||||
AutopsyOptionsPanel.tempDirectoryWarningLabel.text=Close the current case to change the temporary directory.
|
AutopsyOptionsPanel.tempDirectoryWarningLabel.text=Close the current case to change the temporary directory.
|
||||||
AutopsyOptionsPanel.solrJVMHeapWarning.text=NOTE: Setting this too large may impact overall performance.
|
AutopsyOptionsPanel.solrJVMHeapWarning.text=NOTE: Setting this too large may impact overall performance.
|
||||||
AutopsyOptionsPanel.maxMemoryUnitsLabel2.text=MB
|
AutopsyOptionsPanel.maxMemoryUnitsLabel2.text=MB
|
||||||
@ -305,3 +306,8 @@ AutopsyOptionsPanel.agencyLogoPathField.text=
|
|||||||
AutopsyOptionsPanel.logoPanel.border.title=Logo
|
AutopsyOptionsPanel.logoPanel.border.title=Logo
|
||||||
ViewPreferencesPanel.radioGroupByPersonHost.text=Group by Person/Host
|
ViewPreferencesPanel.radioGroupByPersonHost.text=Group by Person/Host
|
||||||
ViewPreferencesPanel.radioGroupByDataType.text=Group by Data Type
|
ViewPreferencesPanel.radioGroupByDataType.text=Group by Data Type
|
||||||
|
AutopsyOptionsPanel.tempLocalRadio.text=Local temp directory
|
||||||
|
AutopsyOptionsPanel.tempCaseRadio.text=Temp folder in case directory
|
||||||
|
AutopsyOptionsPanel.tempCustomRadio.text=Custom
|
||||||
|
AutopsyOptionsPanel.tempCustomField.text=
|
||||||
|
AutopsyOptionsPanel.tempOnCustomNoPath.text=Please select a path for the custom root temp directory.
|
||||||
|
@ -35,6 +35,7 @@ import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
|||||||
import org.sleuthkit.autopsy.actions.ReplaceBlackboardArtifactTagAction;
|
import org.sleuthkit.autopsy.actions.ReplaceBlackboardArtifactTagAction;
|
||||||
import org.sleuthkit.autopsy.actions.ReplaceContentTagAction;
|
import org.sleuthkit.autopsy.actions.ReplaceContentTagAction;
|
||||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.OsAccounts.OsAccountNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.Reports.ReportNode;
|
import org.sleuthkit.autopsy.datamodel.Reports.ReportNode;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExportCSVAction;
|
import org.sleuthkit.autopsy.directorytree.ExportCSVAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
@ -53,6 +54,7 @@ import org.sleuthkit.datamodel.File;
|
|||||||
import org.sleuthkit.datamodel.LayoutFile;
|
import org.sleuthkit.datamodel.LayoutFile;
|
||||||
import org.sleuthkit.datamodel.LocalFile;
|
import org.sleuthkit.datamodel.LocalFile;
|
||||||
import org.sleuthkit.datamodel.LocalDirectory;
|
import org.sleuthkit.datamodel.LocalDirectory;
|
||||||
|
import org.sleuthkit.datamodel.OsAccount;
|
||||||
import org.sleuthkit.datamodel.Report;
|
import org.sleuthkit.datamodel.Report;
|
||||||
import org.sleuthkit.datamodel.SlackFile;
|
import org.sleuthkit.datamodel.SlackFile;
|
||||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||||
@ -447,6 +449,18 @@ public class DataModelActionsFactory {
|
|||||||
return actionsList;
|
return actionsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<Action> getActions(OsAccount osAccount) {
|
||||||
|
List<Action> actionsList = new ArrayList<>();
|
||||||
|
|
||||||
|
OsAccountNode node = new OsAccountNode(osAccount);
|
||||||
|
actionsList.add(null); // creates a menu separator
|
||||||
|
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, node));
|
||||||
|
actionsList.add(null);
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
return actionsList;
|
||||||
|
}
|
||||||
|
|
||||||
public static List<Action> getActions(Content content, boolean isArtifactSource) {
|
public static List<Action> getActions(Content content, boolean isArtifactSource) {
|
||||||
if (content instanceof File) {
|
if (content instanceof File) {
|
||||||
return getActions((File) content, isArtifactSource);
|
return getActions((File) content, isArtifactSource);
|
||||||
@ -464,7 +478,9 @@ public class DataModelActionsFactory {
|
|||||||
return getActions((SlackFile) content, isArtifactSource);
|
return getActions((SlackFile) content, isArtifactSource);
|
||||||
} else if (content instanceof Report) {
|
} else if (content instanceof Report) {
|
||||||
return getActions((Report) content, isArtifactSource);
|
return getActions((Report) content, isArtifactSource);
|
||||||
} else {
|
} else if (content instanceof OsAccount) {
|
||||||
|
return getActions((OsAccount) content, isArtifactSource);
|
||||||
|
}else {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,9 @@ import java.beans.PropertyChangeEvent;
|
|||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import org.openide.nodes.ChildFactory;
|
import org.openide.nodes.ChildFactory;
|
||||||
import org.openide.nodes.Children;
|
import org.openide.nodes.Children;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
@ -48,13 +50,23 @@ public class DataSourcesByTypeNode extends DisplayableItemNode {
|
|||||||
*/
|
*/
|
||||||
public static class DataSourcesByTypeChildren extends ChildFactory.Detachable<HostDataSources> {
|
public static class DataSourcesByTypeChildren extends ChildFactory.Detachable<HostDataSources> {
|
||||||
|
|
||||||
|
private static final Set<Case.Events> UPDATE_EVTS = EnumSet.of(
|
||||||
|
Case.Events.DATA_SOURCE_ADDED,
|
||||||
|
Case.Events.HOSTS_ADDED,
|
||||||
|
Case.Events.HOSTS_DELETED,
|
||||||
|
Case.Events.HOSTS_CHANGED);
|
||||||
|
|
||||||
|
private static final Set<String> UPDATE_EVT_STRS = UPDATE_EVTS.stream()
|
||||||
|
.map(evt -> evt.name())
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(DataSourcesByTypeChildren.class.getName());
|
private static final Logger logger = Logger.getLogger(DataSourcesByTypeChildren.class.getName());
|
||||||
|
|
||||||
private final PropertyChangeListener pcl = new PropertyChangeListener() {
|
private final PropertyChangeListener pcl = new PropertyChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void propertyChange(PropertyChangeEvent evt) {
|
public void propertyChange(PropertyChangeEvent evt) {
|
||||||
String eventType = evt.getPropertyName();
|
String eventType = evt.getPropertyName();
|
||||||
if (eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
|
if (UPDATE_EVT_STRS.contains(eventType)) {
|
||||||
refresh(true);
|
refresh(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -62,12 +74,12 @@ public class DataSourcesByTypeNode extends DisplayableItemNode {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addNotify() {
|
protected void addNotify() {
|
||||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED), pcl);
|
Case.addEventTypeSubscriber(UPDATE_EVTS, pcl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void removeNotify() {
|
protected void removeNotify() {
|
||||||
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED), pcl);
|
Case.removeEventTypeSubscriber(UPDATE_EVTS, pcl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.datamodel;
|
|||||||
|
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -40,6 +41,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
|||||||
import org.sleuthkit.autopsy.casemodule.events.HostsChangedEvent;
|
import org.sleuthkit.autopsy.casemodule.events.HostsChangedEvent;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.datamodel.hosts.AssociatePersonsMenuAction;
|
import org.sleuthkit.autopsy.datamodel.hosts.AssociatePersonsMenuAction;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.hosts.MergeHostMenuAction;
|
||||||
import org.sleuthkit.autopsy.datamodel.hosts.RemoveParentPersonAction;
|
import org.sleuthkit.autopsy.datamodel.hosts.RemoveParentPersonAction;
|
||||||
import org.sleuthkit.datamodel.DataSource;
|
import org.sleuthkit.datamodel.DataSource;
|
||||||
import org.sleuthkit.datamodel.Host;
|
import org.sleuthkit.datamodel.Host;
|
||||||
@ -287,10 +289,13 @@ public class HostNode extends DisplayableItemNode {
|
|||||||
"HostNode_actions_removeFromPerson=Remove from person ({0})"})
|
"HostNode_actions_removeFromPerson=Remove from person ({0})"})
|
||||||
public Action[] getActions(boolean context) {
|
public Action[] getActions(boolean context) {
|
||||||
|
|
||||||
Optional<Person> parent = Optional.empty();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
|
|
||||||
// if there is a host, then provide actions
|
// if there is a host, then provide actions
|
||||||
if (this.host != null) {
|
if (this.host != null) {
|
||||||
|
|
||||||
|
// Add the appropriate Person action
|
||||||
|
Optional<Person> parent;
|
||||||
try {
|
try {
|
||||||
parent = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getPerson(this.host);
|
parent = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getPerson(this.host);
|
||||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||||
@ -300,17 +305,14 @@ public class HostNode extends DisplayableItemNode {
|
|||||||
|
|
||||||
// if there is a parent, only give option to remove parent person.
|
// if there is a parent, only give option to remove parent person.
|
||||||
if (parent.isPresent()) {
|
if (parent.isPresent()) {
|
||||||
return new Action[]{
|
actionsList.add(new RemoveParentPersonAction(this.host, parent.get()));
|
||||||
new RemoveParentPersonAction(this.host, parent.get()),
|
|
||||||
null
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
return new Action[]{
|
actionsList.add(new AssociatePersonsMenuAction(this.host));
|
||||||
new AssociatePersonsMenuAction(this.host),
|
|
||||||
null
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add option to merge hosts
|
||||||
|
actionsList.add(new MergeHostMenuAction(this.host));
|
||||||
}
|
}
|
||||||
return new Action[0];
|
return actionsList.toArray(new Action[actionsList.size()]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,12 +21,14 @@ package org.sleuthkit.autopsy.datamodel;
|
|||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import javax.swing.Action;
|
||||||
import org.openide.nodes.ChildFactory;
|
import org.openide.nodes.ChildFactory;
|
||||||
import org.openide.nodes.Children;
|
import org.openide.nodes.Children;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
@ -51,7 +53,7 @@ public final class OsAccounts implements AutopsyVisitableItem {
|
|||||||
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/os-account.png";
|
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/os-account.png";
|
||||||
private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
|
private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
|
||||||
|
|
||||||
private final SleuthkitCase skCase;
|
private SleuthkitCase skCase;
|
||||||
private final long filteringDSObjId;
|
private final long filteringDSObjId;
|
||||||
|
|
||||||
public OsAccounts(SleuthkitCase skCase) {
|
public OsAccounts(SleuthkitCase skCase) {
|
||||||
@ -111,22 +113,34 @@ public final class OsAccounts implements AutopsyVisitableItem {
|
|||||||
private final PropertyChangeListener listener = new PropertyChangeListener() {
|
private final PropertyChangeListener listener = new PropertyChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void propertyChange(PropertyChangeEvent evt) {
|
public void propertyChange(PropertyChangeEvent evt) {
|
||||||
|
String eventType = evt.getPropertyName();
|
||||||
|
if(eventType.equals(Case.Events.OS_ACCOUNT_ADDED.toString())) {
|
||||||
refresh(true);
|
refresh(true);
|
||||||
|
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
|
||||||
|
// case was closed. Remove listeners so that we don't get called with a stale case handle
|
||||||
|
if (evt.getNewValue() == null) {
|
||||||
|
removeNotify();
|
||||||
|
skCase = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addNotify() {
|
protected void addNotify() {
|
||||||
Case.addEventTypeSubscriber(Collections.singleton(Case.Events.OS_ACCOUNT_ADDED), listener);
|
Case.addEventTypeSubscriber(Collections.singleton(Case.Events.OS_ACCOUNT_ADDED), listener);
|
||||||
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void removeNotify() {
|
protected void removeNotify() {
|
||||||
Case.removeEventTypeSubscriber(Collections.singleton(Case.Events.OS_ACCOUNT_ADDED), listener);
|
Case.removeEventTypeSubscriber(Collections.singleton(Case.Events.OS_ACCOUNT_ADDED), listener);
|
||||||
|
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean createKeys(List<OsAccount> list) {
|
protected boolean createKeys(List<OsAccount> list) {
|
||||||
|
if(skCase != null) {
|
||||||
try {
|
try {
|
||||||
if (filteringDSObjId == 0) {
|
if (filteringDSObjId == 0) {
|
||||||
list.addAll(skCase.getOsAccountManager().getAccounts());
|
list.addAll(skCase.getOsAccountManager().getAccounts());
|
||||||
@ -138,7 +152,7 @@ public final class OsAccounts implements AutopsyVisitableItem {
|
|||||||
logger.log(Level.SEVERE, "Unable to retrieve list of OsAccounts for case", ex);
|
logger.log(Level.SEVERE, "Unable to retrieve list of OsAccounts for case", ex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,5 +274,14 @@ public final class OsAccounts implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
return sheet;
|
return sheet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Action[] getActions(boolean popup) {
|
||||||
|
List<Action> actionsList = new ArrayList<>();
|
||||||
|
actionsList.addAll(Arrays.asList(super.getActions(popup)));
|
||||||
|
actionsList.addAll(DataModelActionsFactory.getActions(account));
|
||||||
|
|
||||||
|
return actionsList.toArray(new Action[actionsList.size()]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,21 @@ AddEditHostDialog.okButton.text=OK
|
|||||||
AddEditHostDialog.cancelButton.text=Cancel
|
AddEditHostDialog.cancelButton.text=Cancel
|
||||||
AddEditHostDialog.inputTextField.text=jTextField1
|
AddEditHostDialog.inputTextField.text=jTextField1
|
||||||
ManageHostsDialog_title_text=Manage Hosts
|
ManageHostsDialog_title_text=Manage Hosts
|
||||||
|
# {0} - sourceHost
|
||||||
|
# {1} - destHost
|
||||||
|
MergeHostAction.confirmText=Are you sure you want to merge {0} into {1}?\nThis may include merging OS Accounts and cannot be undone.
|
||||||
|
MergeHostAction.confirmTitle=Confirmation
|
||||||
|
MergeHostAction.errorText=An error occurred while merging hosts.\nTry again in a few minutes or check the log for details.
|
||||||
|
MergeHostAction.errorTitle=Error Merging Hosts
|
||||||
|
MergeHostAction.progressIndicatorName=Merging Hosts
|
||||||
|
# {0} - sourceHost
|
||||||
|
# {1} - destHost
|
||||||
|
MergeHostAction.progressText=Merging {0} into {1}...
|
||||||
|
# {0} - sourceHostName
|
||||||
|
# {1} - destHostName
|
||||||
|
MergeHostAction_onError_description=There was an error merging host {0} into host {1}.
|
||||||
|
MergeHostAction_onError_title=Error Merging Hosts
|
||||||
|
MergeHostMenuAction_menuTitle=Merge Into Other Host
|
||||||
OpenHostsAction_displayName=Hosts
|
OpenHostsAction_displayName=Hosts
|
||||||
# {0} - personName
|
# {0} - personName
|
||||||
RemoveParentPersonAction_menuTitle=Remove from Person ({0})
|
RemoveParentPersonAction_menuTitle=Remove from Person ({0})
|
||||||
|
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2021 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.datamodel.hosts;
|
||||||
|
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import javax.swing.AbstractAction;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
import javax.swing.SwingWorker;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.NbBundle.Messages;
|
||||||
|
import org.openide.windows.WindowManager;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.progress.ModalDialogProgressIndicator;
|
||||||
|
import org.sleuthkit.autopsy.progress.ProgressIndicator;
|
||||||
|
import org.sleuthkit.datamodel.Host;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Menu action to merge a host into another host.
|
||||||
|
*/
|
||||||
|
@Messages({
|
||||||
|
"MergeHostAction_onError_title=Error Merging Hosts",
|
||||||
|
"# {0} - sourceHostName",
|
||||||
|
"# {1} - destHostName",
|
||||||
|
"MergeHostAction_onError_description=There was an error merging host {0} into host {1}.",})
|
||||||
|
public class MergeHostAction extends AbstractAction {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(MergeHostAction.class.getName());
|
||||||
|
|
||||||
|
private final Host sourceHost;
|
||||||
|
private final Host destHost;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param sourceHost The source host.
|
||||||
|
* @param destHost The destination host.
|
||||||
|
*/
|
||||||
|
public MergeHostAction(Host sourceHost, Host destHost) {
|
||||||
|
super(destHost.getName());
|
||||||
|
|
||||||
|
this.sourceHost = sourceHost;
|
||||||
|
this.destHost = destHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"MergeHostAction.progressIndicatorName=Merging Hosts",
|
||||||
|
"MergeHostAction.confirmTitle=Confirmation",
|
||||||
|
"# {0} - sourceHost",
|
||||||
|
"# {1} - destHost",
|
||||||
|
"MergeHostAction.confirmText=Are you sure you want to merge {0} into {1}?\nThis may include merging OS Accounts and cannot be undone.",
|
||||||
|
"# {0} - sourceHost",
|
||||||
|
"# {1} - destHost",
|
||||||
|
"MergeHostAction.progressText=Merging {0} into {1}..."
|
||||||
|
})
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
|
||||||
|
// Display confirmation dialog
|
||||||
|
int response = JOptionPane.showConfirmDialog(
|
||||||
|
WindowManager.getDefault().getMainWindow(),
|
||||||
|
NbBundle.getMessage(this.getClass(), "MergeHostAction.confirmText", sourceHost.getName(), destHost.getName()),
|
||||||
|
NbBundle.getMessage(this.getClass(), "MergeHostAction.confirmTitle"),
|
||||||
|
JOptionPane.YES_NO_OPTION);
|
||||||
|
if (response == JOptionPane.NO_OPTION) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModalDialogProgressIndicator progressDialog = new ModalDialogProgressIndicator(WindowManager.getDefault().getMainWindow(),
|
||||||
|
Bundle.MergeHostAction_progressIndicatorName());
|
||||||
|
|
||||||
|
MergeHostsBackgroundTask mergeTask = new MergeHostsBackgroundTask(sourceHost, destHost, progressDialog);
|
||||||
|
progressDialog.start(NbBundle.getMessage(this.getClass(), "MergeHostAction.progressText", sourceHost.getName(), destHost.getName()));
|
||||||
|
mergeTask.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges the host in a background worker.
|
||||||
|
*/
|
||||||
|
private class MergeHostsBackgroundTask extends SwingWorker<Void, Void> {
|
||||||
|
|
||||||
|
private final Host sourceHost;
|
||||||
|
private final Host destHost;
|
||||||
|
private final ProgressIndicator progress;
|
||||||
|
|
||||||
|
public MergeHostsBackgroundTask(Host sourceHost, Host destHost, ProgressIndicator progress) {
|
||||||
|
this.sourceHost = sourceHost;
|
||||||
|
this.destHost = destHost;
|
||||||
|
this.progress = progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground() throws Exception {
|
||||||
|
Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().mergeHosts(sourceHost, destHost);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"MergeHostAction.errorTitle=Error Merging Hosts",
|
||||||
|
"MergeHostAction.errorText=An error occurred while merging hosts.\nTry again in a few minutes or check the log for details."
|
||||||
|
})
|
||||||
|
@Override
|
||||||
|
protected void done() {
|
||||||
|
progress.finish();
|
||||||
|
try {
|
||||||
|
get();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.log(Level.SEVERE, "Error merging " + sourceHost.getName() + " into " + destHost.getName(), ex);
|
||||||
|
|
||||||
|
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
||||||
|
NbBundle.getMessage(this.getClass(), "MergeHostAction.errorText"),
|
||||||
|
NbBundle.getMessage(this.getClass(), "MergeHostAction.errorTitle"),
|
||||||
|
JOptionPane.ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2021 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.datamodel.hosts;
|
||||||
|
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import javax.swing.AbstractAction;
|
||||||
|
import javax.swing.JMenu;
|
||||||
|
import javax.swing.JMenuItem;
|
||||||
|
import org.openide.util.NbBundle.Messages;
|
||||||
|
import org.openide.util.actions.Presenter;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.datamodel.Host;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* JMenu item to show a menu allowing the selected host to be merged into another host.
|
||||||
|
*/
|
||||||
|
@Messages({
|
||||||
|
"MergeHostMenuAction_menuTitle=Merge Into Other Host",})
|
||||||
|
public class MergeHostMenuAction extends AbstractAction implements Presenter.Popup {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(MergeHostMenuAction.class.getName());
|
||||||
|
|
||||||
|
private final Host sourceHost;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param host The original host.
|
||||||
|
*/
|
||||||
|
public MergeHostMenuAction(Host host) {
|
||||||
|
super("");
|
||||||
|
this.sourceHost = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("NoopMethodInAbstractClass")
|
||||||
|
public void actionPerformed(ActionEvent event) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JMenuItem getPopupPresenter() {
|
||||||
|
JMenu menu = new JMenu(Bundle.MergeHostMenuAction_menuTitle());
|
||||||
|
|
||||||
|
// Get a list of all other hosts
|
||||||
|
List<Host> otherHosts = Collections.emptyList();
|
||||||
|
try {
|
||||||
|
otherHosts = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getHosts();
|
||||||
|
otherHosts.remove(sourceHost);
|
||||||
|
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||||
|
logger.log(Level.WARNING, "Error getting hosts for case.", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are no other hosts, disable the menu item. Otherwise add
|
||||||
|
// the other hosts to the menu.
|
||||||
|
if (otherHosts.isEmpty()) {
|
||||||
|
menu.setEnabled(false);
|
||||||
|
} else {
|
||||||
|
menu.setEnabled(true);
|
||||||
|
otherHosts.stream()
|
||||||
|
.filter(p -> p != null && p.getName() != null)
|
||||||
|
.sorted((a, b) -> a.getName().compareToIgnoreCase(b.getName()))
|
||||||
|
.map(p -> new JMenuItem(new MergeHostAction(sourceHost, p)))
|
||||||
|
.forEach(menu::add);
|
||||||
|
}
|
||||||
|
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -47,7 +47,7 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.EventUpdateHandler;
|
|||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelExportException;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelExportException;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelSheetExport;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelSheetExport;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelTableExport;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelTableExport;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelTableExport.ExcelCellModel;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelCellModel;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.GuiCellModel.DefaultMenuItem;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.GuiCellModel.DefaultMenuItem;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.GuiCellModel.MenuItem;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.GuiCellModel.MenuItem;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent;
|
||||||
|
@ -6,7 +6,21 @@ AnalysisPanel_keywordHits_tabName=Keyword Hits
|
|||||||
AnalysisPanel_keywordSearchModuleName=Keyword Search
|
AnalysisPanel_keywordSearchModuleName=Keyword Search
|
||||||
BaseDataSourceSummaryPanel_goToArtifact=View Source Result
|
BaseDataSourceSummaryPanel_goToArtifact=View Source Result
|
||||||
BaseDataSourceSummaryPanel_goToFile=View Source File in Directory
|
BaseDataSourceSummaryPanel_goToFile=View Source File in Directory
|
||||||
|
ContainerPanel_export_acquisitionDetails=Acquisition Details:
|
||||||
|
ContainerPanel_export_deviceId=Device ID:
|
||||||
|
ContainerPanel_export_displayName=Display Name:
|
||||||
|
ContainerPanel_export_filePaths=File Paths:
|
||||||
|
ContainerPanel_export_imageType=Image Type:
|
||||||
|
ContainerPanel_export_md5=MD5:
|
||||||
|
ContainerPanel_export_originalName=Name:
|
||||||
|
ContainerPanel_export_sectorSize=Sector Size:
|
||||||
|
ContainerPanel_export_sha1=SHA1:
|
||||||
|
ContainerPanel_export_sha256=SHA256:
|
||||||
|
ContainerPanel_export_size=Size:
|
||||||
|
ContainerPanel_export_timeZone=Time Zone:
|
||||||
|
ContainerPanel_export_unallocatedSize=Unallocated Space:
|
||||||
ContainerPanel_setFieldsForNonImageDataSource_na=N/A
|
ContainerPanel_setFieldsForNonImageDataSource_na=N/A
|
||||||
|
ContainerPanel_tabName=Container
|
||||||
CTL_DataSourceSummaryAction=Data Source Summary
|
CTL_DataSourceSummaryAction=Data Source Summary
|
||||||
DataSourceSummaryDialog.closeButton.text=Close
|
DataSourceSummaryDialog.closeButton.text=Close
|
||||||
ContainerPanel.displayNameLabel.text=Display Name:
|
ContainerPanel.displayNameLabel.text=Display Name:
|
||||||
@ -73,6 +87,12 @@ GeolocationPanel_mostCommon_tabName=Most Common Cities
|
|||||||
GeolocationPanel_mostRecent_tabName=Most Recent Cities
|
GeolocationPanel_mostRecent_tabName=Most Recent Cities
|
||||||
GeolocationPanel_onNoCrIngest_message=No results will be shown because the GPX Parser was not run.
|
GeolocationPanel_onNoCrIngest_message=No results will be shown because the GPX Parser was not run.
|
||||||
GeolocationPanel_unknownRow_title=Unknown
|
GeolocationPanel_unknownRow_title=Unknown
|
||||||
|
IngestJobExcelExport_endTimeColumn=End Time
|
||||||
|
IngestJobExcelExport_ingestStatusTimeColumn=Ingest Status
|
||||||
|
IngestJobExcelExport_moduleNameTimeColumn=Module Name
|
||||||
|
IngestJobExcelExport_sheetName=Ingest History
|
||||||
|
IngestJobExcelExport_startTimeColumn=Start Time
|
||||||
|
IngestJobExcelExport_versionColumn=Module Version
|
||||||
PastCasesPanel_caseColumn_title=Case
|
PastCasesPanel_caseColumn_title=Case
|
||||||
PastCasesPanel_countColumn_title=Count
|
PastCasesPanel_countColumn_title=Count
|
||||||
PastCasesPanel_notableFileTable_tabName=Cases with Common Notable
|
PastCasesPanel_notableFileTable_tabName=Cases with Common Notable
|
||||||
@ -87,18 +107,19 @@ RecentFilesPanel_attachmentsTable_tabName=Recent Attachments
|
|||||||
RecentFilesPanel_col_head_date=Date
|
RecentFilesPanel_col_head_date=Date
|
||||||
RecentFilesPanel_docsTable_tabName=Recently Opened Documents
|
RecentFilesPanel_docsTable_tabName=Recently Opened Documents
|
||||||
RecentFilesPanel_downloadsTable_tabName=Recently Downloads
|
RecentFilesPanel_downloadsTable_tabName=Recently Downloads
|
||||||
SizeRepresentationUtil_units_bytes=\ bytes
|
SizeRepresentationUtil_units_bytes=bytes
|
||||||
SizeRepresentationUtil_units_gigabytes=\ GB
|
SizeRepresentationUtil_units_gigabytes=GB
|
||||||
SizeRepresentationUtil_units_kilobytes=\ kB
|
SizeRepresentationUtil_units_kilobytes=KB
|
||||||
SizeRepresentationUtil_units_megabytes=\ MB
|
SizeRepresentationUtil_units_megabytes=MB
|
||||||
SizeRepresentationUtil_units_petabytes=\ PB
|
SizeRepresentationUtil_units_petabytes=PB
|
||||||
SizeRepresentationUtil_units_terabytes=\ TB
|
SizeRepresentationUtil_units_terabytes=TB
|
||||||
TimelinePanel_earliestLabel_title=Earliest
|
TimelinePanel_earliestLabel_title=Earliest
|
||||||
TimelinePanel_latestLabel_title=Latest
|
TimelinePanel_latestLabel_title=Latest
|
||||||
TimlinePanel_last30DaysChart_artifactEvts_title=Result Events
|
TimlinePanel_last30DaysChart_artifactEvts_title=Result Events
|
||||||
TimlinePanel_last30DaysChart_fileEvts_title=File Events
|
TimlinePanel_last30DaysChart_fileEvts_title=File Events
|
||||||
TimlinePanel_last30DaysChart_title=Last 30 Days
|
TimlinePanel_last30DaysChart_title=Last 30 Days
|
||||||
TypesPanel_artifactsTypesPieChart_title=Artifact Types
|
TypesPanel_artifactsTypesPieChart_title=Artifact Types
|
||||||
|
TypesPanel_excelTabName=Types
|
||||||
TypesPanel_fileMimeTypesChart_audio_title=Audio
|
TypesPanel_fileMimeTypesChart_audio_title=Audio
|
||||||
TypesPanel_fileMimeTypesChart_documents_title=Documents
|
TypesPanel_fileMimeTypesChart_documents_title=Documents
|
||||||
TypesPanel_fileMimeTypesChart_executables_title=Executables
|
TypesPanel_fileMimeTypesChart_executables_title=Executables
|
||||||
|
@ -19,21 +19,35 @@
|
|||||||
package org.sleuthkit.autopsy.datasourcesummary.ui;
|
package org.sleuthkit.autopsy.datasourcesummary.ui;
|
||||||
|
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import javax.swing.table.DefaultTableModel;
|
import javax.swing.table.DefaultTableModel;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary;
|
import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||||
|
import static org.sleuthkit.autopsy.datasourcesummary.ui.BaseDataSourceSummaryPanel.getFetchResult;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelSheetExport;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.ExcelItemExportable;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.KeyValueItemExportable;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.SingleCellExportable;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.TitledExportable;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.UpdateGovernor;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.UpdateGovernor;
|
||||||
import org.sleuthkit.datamodel.DataSource;
|
import org.sleuthkit.datamodel.DataSource;
|
||||||
import org.sleuthkit.datamodel.Image;
|
import org.sleuthkit.datamodel.Image;
|
||||||
@ -42,39 +56,184 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
/**
|
/**
|
||||||
* Panel to display additional details associated with a specific DataSource
|
* Panel to display additional details associated with a specific DataSource
|
||||||
*/
|
*/
|
||||||
|
@Messages({
|
||||||
|
"ContainerPanel_tabName=Container"
|
||||||
|
})
|
||||||
class ContainerPanel extends BaseDataSourceSummaryPanel {
|
class ContainerPanel extends BaseDataSourceSummaryPanel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data payload for the Container panel.
|
* View model data for data source images.
|
||||||
*/
|
*/
|
||||||
private static class ContainerPanelData {
|
private static class ImageViewModel {
|
||||||
|
|
||||||
private final DataSource dataSource;
|
private final long unallocatedSize;
|
||||||
private final Long unallocatedFilesSize;
|
private final long size;
|
||||||
|
private final long sectorSize;
|
||||||
|
|
||||||
|
private final String timeZone;
|
||||||
|
private final String imageType;
|
||||||
|
|
||||||
|
private final List<String> paths;
|
||||||
|
private final String md5Hash;
|
||||||
|
private final String sha1Hash;
|
||||||
|
private final String sha256Hash;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main constructor.
|
* Main constructor.
|
||||||
*
|
*
|
||||||
* @param dataSource The original datasource.
|
* @param unallocatedSize Size in bytes of unallocated space.
|
||||||
* @param unallocatedFilesSize The unallocated file size.
|
* @param size Total size in bytes.
|
||||||
|
* @param sectorSize Sector size in bytes.
|
||||||
|
* @param timeZone The time zone.
|
||||||
|
* @param imageType The type of image.
|
||||||
|
* @param paths The source paths for the image.
|
||||||
|
* @param md5Hash The md5 hash or null.
|
||||||
|
* @param sha1Hash The sha1 hash or null.
|
||||||
|
* @param sha256Hash The sha256 hash or null.
|
||||||
*/
|
*/
|
||||||
ContainerPanelData(DataSource dataSource, Long unallocatedFilesSize) {
|
ImageViewModel(long unallocatedSize, long size, long sectorSize,
|
||||||
this.dataSource = dataSource;
|
String timeZone, String imageType, List<String> paths, String md5Hash,
|
||||||
this.unallocatedFilesSize = unallocatedFilesSize;
|
String sha1Hash, String sha256Hash) {
|
||||||
|
this.unallocatedSize = unallocatedSize;
|
||||||
|
this.size = size;
|
||||||
|
this.sectorSize = sectorSize;
|
||||||
|
this.timeZone = timeZone;
|
||||||
|
this.imageType = imageType;
|
||||||
|
this.paths = paths == null ? Collections.emptyList() : new ArrayList<>(paths);
|
||||||
|
this.md5Hash = md5Hash;
|
||||||
|
this.sha1Hash = sha1Hash;
|
||||||
|
this.sha256Hash = sha256Hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The original datasource.
|
* @return Size in bytes of unallocated space.
|
||||||
*/
|
*/
|
||||||
DataSource getDataSource() {
|
long getUnallocatedSize() {
|
||||||
return dataSource;
|
return unallocatedSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The unallocated file size.
|
* @return Total size in bytes.
|
||||||
*/
|
*/
|
||||||
Long getUnallocatedFilesSize() {
|
long getSize() {
|
||||||
return unallocatedFilesSize;
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Sector size in bytes.
|
||||||
|
*/
|
||||||
|
long getSectorSize() {
|
||||||
|
return sectorSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The time zone.
|
||||||
|
*/
|
||||||
|
String getTimeZone() {
|
||||||
|
return timeZone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The type of image.
|
||||||
|
*/
|
||||||
|
String getImageType() {
|
||||||
|
return imageType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The source paths for the image.
|
||||||
|
*/
|
||||||
|
List<String> getPaths() {
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The md5 hash or null.
|
||||||
|
*/
|
||||||
|
String getMd5Hash() {
|
||||||
|
return md5Hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The sha1 hash or null.
|
||||||
|
*/
|
||||||
|
String getSha1Hash() {
|
||||||
|
return sha1Hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The sha256 hash or null.
|
||||||
|
*/
|
||||||
|
String getSha256Hash() {
|
||||||
|
return sha256Hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View model for container data.
|
||||||
|
*/
|
||||||
|
private static class ContainerViewModel {
|
||||||
|
|
||||||
|
private final String displayName;
|
||||||
|
private final String originalName;
|
||||||
|
private final String deviceIdValue;
|
||||||
|
private final String acquisitionDetails;
|
||||||
|
private final ImageViewModel imageViewModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param displayName The display name for this data source.
|
||||||
|
* @param originalName The original name for this data source.
|
||||||
|
* @param deviceIdValue The device id value for this data source.
|
||||||
|
* @param acquisitionDetails The acquisition details for this data
|
||||||
|
* source or null.
|
||||||
|
* @param imageViewModel If the data source is an image, the image view
|
||||||
|
* model for this data source or null if non-image.
|
||||||
|
*/
|
||||||
|
ContainerViewModel(String displayName, String originalName, String deviceIdValue,
|
||||||
|
String acquisitionDetails, ImageViewModel imageViewModel) {
|
||||||
|
this.displayName = displayName;
|
||||||
|
this.originalName = originalName;
|
||||||
|
this.deviceIdValue = deviceIdValue;
|
||||||
|
this.acquisitionDetails = acquisitionDetails;
|
||||||
|
this.imageViewModel = imageViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The display name for this data source.
|
||||||
|
*/
|
||||||
|
String getDisplayName() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The original name for this data source.
|
||||||
|
*/
|
||||||
|
String getOriginalName() {
|
||||||
|
return originalName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The device id value for this data source.
|
||||||
|
*/
|
||||||
|
String getDeviceId() {
|
||||||
|
return deviceIdValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The acquisition details for this data source or null.
|
||||||
|
*/
|
||||||
|
String getAcquisitionDetails() {
|
||||||
|
return acquisitionDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return If the data source is an image, the image view model for this
|
||||||
|
* data source or null if non-image.
|
||||||
|
*/
|
||||||
|
ImageViewModel getImageViewModel() {
|
||||||
|
return imageViewModel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,6 +262,7 @@ class ContainerPanel extends BaseDataSourceSummaryPanel {
|
|||||||
private static final Logger logger = Logger.getLogger(ContainerPanel.class.getName());
|
private static final Logger logger = Logger.getLogger(ContainerPanel.class.getName());
|
||||||
|
|
||||||
private final List<DataFetchComponents<DataSource, ?>> dataFetchComponents;
|
private final List<DataFetchComponents<DataSource, ?>> dataFetchComponents;
|
||||||
|
private final DataFetcher<DataSource, ContainerViewModel> containerDataFetcher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new form ContainerPanel.
|
* Creates a new form ContainerPanel.
|
||||||
@ -117,21 +277,15 @@ class ContainerPanel extends BaseDataSourceSummaryPanel {
|
|||||||
ContainerPanel(ContainerSummary containerSummary) {
|
ContainerPanel(ContainerSummary containerSummary) {
|
||||||
super(containerSummary, CONTAINER_UPDATES);
|
super(containerSummary, CONTAINER_UPDATES);
|
||||||
|
|
||||||
|
containerDataFetcher = (dataSource) -> getContainerViewModel(containerSummary, dataSource);
|
||||||
|
|
||||||
dataFetchComponents = Arrays.asList(
|
dataFetchComponents = Arrays.asList(
|
||||||
new DataFetchComponents<>(
|
new DataFetchComponents<>(
|
||||||
(dataSource) -> {
|
containerDataFetcher,
|
||||||
return new ContainerPanelData(
|
|
||||||
dataSource,
|
|
||||||
containerSummary.getSizeOfUnallocatedFiles(dataSource)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
(result) -> {
|
(result) -> {
|
||||||
if (result != null && result.getResultType() == ResultType.SUCCESS) {
|
if (result != null && result.getResultType() == ResultType.SUCCESS) {
|
||||||
ContainerPanelData data = result.getData();
|
ContainerViewModel data = result.getData();
|
||||||
DataSource dataSource = (data == null) ? null : data.getDataSource();
|
updateDetailsPanelData(data);
|
||||||
Long unallocatedFileSize = (data == null) ? null : data.getUnallocatedFilesSize();
|
|
||||||
|
|
||||||
updateDetailsPanelData(dataSource, unallocatedFileSize);
|
|
||||||
} else {
|
} else {
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
logger.log(Level.WARNING, "No data fetch result was provided to the ContainerPanel.");
|
logger.log(Level.WARNING, "No data fetch result was provided to the ContainerPanel.");
|
||||||
@ -139,8 +293,7 @@ class ContainerPanel extends BaseDataSourceSummaryPanel {
|
|||||||
logger.log(Level.WARNING, "An exception occurred while attempting to fetch data for the ContainerPanel.",
|
logger.log(Level.WARNING, "An exception occurred while attempting to fetch data for the ContainerPanel.",
|
||||||
result.getException());
|
result.getException());
|
||||||
}
|
}
|
||||||
|
updateDetailsPanelData(null);
|
||||||
updateDetailsPanelData(null, null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -161,33 +314,113 @@ class ContainerPanel extends BaseDataSourceSummaryPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update which DataSource this panel should display details about
|
* A means of retrieving data that could potentially throw an exception.
|
||||||
*
|
|
||||||
* @param selectedDataSource the DataSource to display details about.
|
|
||||||
*/
|
*/
|
||||||
private void updateDetailsPanelData(DataSource selectedDataSource, Long unallocatedFilesSize) {
|
private interface Retriever<O> {
|
||||||
clearTableValues();
|
|
||||||
if (selectedDataSource != null) {
|
|
||||||
displayNameValue.setText(selectedDataSource.getName());
|
|
||||||
originalNameValue.setText(selectedDataSource.getName());
|
|
||||||
deviceIdValue.setText(selectedDataSource.getDeviceId());
|
|
||||||
|
|
||||||
try {
|
/**
|
||||||
acquisitionDetailsTextArea.setText(selectedDataSource.getAcquisitionDetails());
|
* Retrieves data of a certain type and possibly throws an exception.
|
||||||
} catch (TskCoreException ex) {
|
*
|
||||||
logger.log(Level.WARNING, "Unable to get acquisition details for selected data source", ex);
|
* @return The data type.
|
||||||
|
* @throws TskCoreException
|
||||||
|
* @throws SleuthkitCaseProviderException
|
||||||
|
* @throws SQLException
|
||||||
|
*/
|
||||||
|
O retrieve() throws TskCoreException, SleuthkitCaseProviderException, SQLException;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedDataSource instanceof Image) {
|
/**
|
||||||
setFieldsForImage((Image) selectedDataSource, unallocatedFilesSize);
|
* Retrieves data of a particular type and handles any exceptions that may
|
||||||
|
* be thrown by logging.
|
||||||
|
*
|
||||||
|
* @param retriever The retrieving function.
|
||||||
|
* @return The retrieved data.
|
||||||
|
*/
|
||||||
|
private static <O> O retrieve(Retriever<O> retriever) {
|
||||||
|
try {
|
||||||
|
return retriever.retrieve();
|
||||||
|
} catch (TskCoreException | SleuthkitCaseProviderException | SQLException ex) {
|
||||||
|
logger.log(Level.WARNING, "Error while retrieving data.", ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a container view model object containing data to display about
|
||||||
|
* the data source.
|
||||||
|
*
|
||||||
|
* @param containerSummary The service providing data about the data source.
|
||||||
|
* @param ds The data source.
|
||||||
|
* @return The generated view model.
|
||||||
|
*/
|
||||||
|
private static ContainerViewModel getContainerViewModel(ContainerSummary containerSummary, DataSource ds) {
|
||||||
|
if (ds == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ContainerViewModel(
|
||||||
|
ds.getName(),
|
||||||
|
ds.getName(),
|
||||||
|
ds.getDeviceId(),
|
||||||
|
retrieve(() -> ds.getAcquisitionDetails()),
|
||||||
|
ds instanceof Image ? getImageViewModel(containerSummary, (Image) ds) : null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an image view model object containing data to display about the
|
||||||
|
* image.
|
||||||
|
*
|
||||||
|
* @param containerSummary The service providing data about the image.
|
||||||
|
* @param image The image.
|
||||||
|
* @return The generated view model.
|
||||||
|
*/
|
||||||
|
private static ImageViewModel getImageViewModel(ContainerSummary containerSummary, Image image) {
|
||||||
|
if (image == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Long unallocSize = retrieve(() -> containerSummary.getSizeOfUnallocatedFiles(image));
|
||||||
|
String imageType = image.getType().getName();
|
||||||
|
Long size = image.getSize();
|
||||||
|
Long sectorSize = image.getSsize();
|
||||||
|
String timeZone = image.getTimeZone();
|
||||||
|
List<String> paths = image.getPaths() == null ? Collections.emptyList() : Arrays.asList(image.getPaths());
|
||||||
|
String md5 = retrieve(() -> image.getMd5());
|
||||||
|
String sha1 = retrieve(() -> image.getSha1());
|
||||||
|
String sha256 = retrieve(() -> image.getSha256());
|
||||||
|
|
||||||
|
return new ImageViewModel(unallocSize, size, sectorSize, timeZone, imageType, paths, md5, sha1, sha256);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the swing components with fetched data.
|
||||||
|
*
|
||||||
|
* @param viewModel The data source view model data.
|
||||||
|
*/
|
||||||
|
private void updateDetailsPanelData(ContainerViewModel viewModel) {
|
||||||
|
clearTableValues();
|
||||||
|
if (viewModel == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
displayNameValue.setText(viewModel.getDisplayName());
|
||||||
|
originalNameValue.setText(viewModel.getOriginalName());
|
||||||
|
deviceIdValue.setText(viewModel.getDeviceId());
|
||||||
|
acquisitionDetailsTextArea.setText(viewModel.getAcquisitionDetails());
|
||||||
|
|
||||||
|
if (viewModel.getImageViewModel() != null) {
|
||||||
|
setFieldsForImage(viewModel.getImageViewModel());
|
||||||
} else {
|
} else {
|
||||||
setFieldsForNonImageDataSource();
|
setFieldsForNonImageDataSource();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
this.repaint();
|
this.repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets image-only fields to N/A.
|
||||||
|
*/
|
||||||
@Messages({
|
@Messages({
|
||||||
"ContainerPanel_setFieldsForNonImageDataSource_na=N/A"
|
"ContainerPanel_setFieldsForNonImageDataSource_na=N/A"
|
||||||
})
|
})
|
||||||
@ -208,54 +441,24 @@ class ContainerPanel extends BaseDataSourceSummaryPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets text fields for an image. This should be called after
|
* Sets fields for images.
|
||||||
* clearTableValues and before updateFieldVisibility to ensure the proper
|
|
||||||
* rendering.
|
|
||||||
*
|
*
|
||||||
* @param selectedImage The selected image.
|
* @param viewModel The image view model data.
|
||||||
* @param unallocatedFilesSize Unallocated file size in bytes.
|
|
||||||
*/
|
*/
|
||||||
private void setFieldsForImage(Image selectedImage, Long unallocatedFilesSize) {
|
private void setFieldsForImage(ImageViewModel viewModel) {
|
||||||
unallocatedSizeValue.setText(SizeRepresentationUtil.getSizeString(unallocatedFilesSize));
|
unallocatedSizeValue.setText(SizeRepresentationUtil.getSizeString(viewModel.getUnallocatedSize()));
|
||||||
imageTypeValue.setText(selectedImage.getType().getName());
|
imageTypeValue.setText(viewModel.getImageType());
|
||||||
sizeValue.setText(SizeRepresentationUtil.getSizeString(selectedImage.getSize()));
|
sizeValue.setText(SizeRepresentationUtil.getSizeString(viewModel.getSize()));
|
||||||
sectorSizeValue.setText(SizeRepresentationUtil.getSizeString(selectedImage.getSsize()));
|
sectorSizeValue.setText(SizeRepresentationUtil.getSizeString(viewModel.getSectorSize()));
|
||||||
timeZoneValue.setText(selectedImage.getTimeZone());
|
timeZoneValue.setText(viewModel.getTimeZone());
|
||||||
|
|
||||||
for (String path : selectedImage.getPaths()) {
|
for (String path : viewModel.getPaths()) {
|
||||||
((DefaultTableModel) filePathsTable.getModel()).addRow(new Object[]{path});
|
((DefaultTableModel) filePathsTable.getModel()).addRow(new Object[]{path});
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
md5HashValue.setText(viewModel.getMd5Hash());
|
||||||
//older databases may have null as the hash values
|
sha1HashValue.setText(viewModel.getSha1Hash());
|
||||||
String md5String = selectedImage.getMd5();
|
sha256HashValue.setText(viewModel.getSha256Hash());
|
||||||
if (md5String == null) {
|
|
||||||
md5String = "";
|
|
||||||
}
|
|
||||||
md5HashValue.setText(md5String);
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
logger.log(Level.WARNING, "Unable to get MD5 for selected data source", ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
String sha1String = selectedImage.getSha1();
|
|
||||||
if (sha1String == null) {
|
|
||||||
sha1String = "";
|
|
||||||
}
|
|
||||||
sha1HashValue.setText(sha1String);
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
logger.log(Level.WARNING, "Unable to get SHA1 for selected data source", ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
String sha256String = selectedImage.getSha256();
|
|
||||||
if (sha256String == null) {
|
|
||||||
sha256String = "";
|
|
||||||
}
|
|
||||||
sha256HashValue.setText(sha256String);
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
logger.log(Level.WARNING, "Unable to get SHA256 for selected data source", ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -277,9 +480,82 @@ class ContainerPanel extends BaseDataSourceSummaryPanel {
|
|||||||
((DefaultTableModel) filePathsTable.getModel()).setRowCount(0);
|
((DefaultTableModel) filePathsTable.getModel()).setRowCount(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
List<ExcelExport.ExcelSheetExport> getExports(DataSource ds) {
|
* Divides acquisition details into key/value pairs to be displayed in
|
||||||
|
* separate cells in an excel export.
|
||||||
|
*
|
||||||
|
* @param acquisitionDetails The acquisition details.
|
||||||
|
* @return The list of key value pairs that can be incorporated into the
|
||||||
|
* excel export.
|
||||||
|
*/
|
||||||
|
private static List<? extends ExcelItemExportable> getAcquisitionDetails(String acquisitionDetails) {
|
||||||
|
if (StringUtils.isBlank(acquisitionDetails)) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
|
} else {
|
||||||
|
return Stream.of(acquisitionDetails.split("\\r?\\n"))
|
||||||
|
.map((line) -> (StringUtils.isBlank(line)) ? null : new SingleCellExportable(line))
|
||||||
|
.filter(item -> item != null)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Messages({
|
||||||
|
"ContainerPanel_export_displayName=Display Name:",
|
||||||
|
"ContainerPanel_export_originalName=Name:",
|
||||||
|
"ContainerPanel_export_deviceId=Device ID:",
|
||||||
|
"ContainerPanel_export_timeZone=Time Zone:",
|
||||||
|
"ContainerPanel_export_acquisitionDetails=Acquisition Details:",
|
||||||
|
"ContainerPanel_export_imageType=Image Type:",
|
||||||
|
"ContainerPanel_export_size=Size:",
|
||||||
|
"ContainerPanel_export_sectorSize=Sector Size:",
|
||||||
|
"ContainerPanel_export_md5=MD5:",
|
||||||
|
"ContainerPanel_export_sha1=SHA1:",
|
||||||
|
"ContainerPanel_export_sha256=SHA256:",
|
||||||
|
"ContainerPanel_export_unallocatedSize=Unallocated Space:",
|
||||||
|
"ContainerPanel_export_filePaths=File Paths:",})
|
||||||
|
protected List<ExcelSheetExport> getExports(DataSource ds) {
|
||||||
|
ContainerViewModel result = getFetchResult(containerDataFetcher, "Container sheets", ds);
|
||||||
|
if (ds == null || result == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
String NA = Bundle.ContainerPanel_setFieldsForNonImageDataSource_na();
|
||||||
|
DefaultCellModel<?> NACell = new DefaultCellModel<>(NA);
|
||||||
|
|
||||||
|
ImageViewModel imageModel = result.getImageViewModel();
|
||||||
|
boolean hasImage = imageModel != null;
|
||||||
|
|
||||||
|
DefaultCellModel<?> timeZone = hasImage ? new DefaultCellModel<>(imageModel.getTimeZone()) : NACell;
|
||||||
|
DefaultCellModel<?> imageType = hasImage ? new DefaultCellModel<>(imageModel.getImageType()) : NACell;
|
||||||
|
DefaultCellModel<?> size = hasImage ? SizeRepresentationUtil.getBytesCell(imageModel.getSize()) : NACell;
|
||||||
|
DefaultCellModel<?> sectorSize = hasImage ? SizeRepresentationUtil.getBytesCell(imageModel.getSectorSize()) : NACell;
|
||||||
|
DefaultCellModel<?> md5 = hasImage ? new DefaultCellModel<>(imageModel.getMd5Hash()) : NACell;
|
||||||
|
DefaultCellModel<?> sha1 = hasImage ? new DefaultCellModel<>(imageModel.getSha1Hash()) : NACell;
|
||||||
|
DefaultCellModel<?> sha256 = hasImage ? new DefaultCellModel<>(imageModel.getSha256Hash()) : NACell;
|
||||||
|
DefaultCellModel<?> unallocatedSize = hasImage ? SizeRepresentationUtil.getBytesCell(imageModel.getUnallocatedSize()) : NACell;
|
||||||
|
List<String> paths = result.getImageViewModel() == null ? Collections.singletonList(NA) : result.getImageViewModel().getPaths();
|
||||||
|
List<SingleCellExportable> cellPaths = paths.stream()
|
||||||
|
.map(SingleCellExportable::new)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
return Arrays.asList(
|
||||||
|
new ExcelSpecialFormatExport(Bundle.ContainerPanel_tabName(), Arrays.asList(
|
||||||
|
new KeyValueItemExportable(Bundle.ContainerPanel_export_displayName(), new DefaultCellModel<>(result.getDisplayName())),
|
||||||
|
new KeyValueItemExportable(Bundle.ContainerPanel_export_originalName(), new DefaultCellModel<>(result.getOriginalName())),
|
||||||
|
new KeyValueItemExportable(Bundle.ContainerPanel_export_deviceId(), new DefaultCellModel<>(result.getDeviceId())),
|
||||||
|
new KeyValueItemExportable(Bundle.ContainerPanel_export_timeZone(), timeZone),
|
||||||
|
new TitledExportable(Bundle.ContainerPanel_export_acquisitionDetails(), getAcquisitionDetails(result.getAcquisitionDetails())),
|
||||||
|
new KeyValueItemExportable(Bundle.ContainerPanel_export_imageType(), imageType),
|
||||||
|
new KeyValueItemExportable(Bundle.ContainerPanel_export_size(), size),
|
||||||
|
new KeyValueItemExportable(Bundle.ContainerPanel_export_sectorSize(), sectorSize),
|
||||||
|
new KeyValueItemExportable(Bundle.ContainerPanel_export_md5(), md5),
|
||||||
|
new KeyValueItemExportable(Bundle.ContainerPanel_export_sha1(), sha1),
|
||||||
|
new KeyValueItemExportable(Bundle.ContainerPanel_export_sha256(), sha256),
|
||||||
|
new KeyValueItemExportable(Bundle.ContainerPanel_export_unallocatedSize(), unallocatedSize),
|
||||||
|
new TitledExportable(Bundle.ContainerPanel_export_filePaths(), cellPaths)
|
||||||
|
)));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,7 +68,6 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel {
|
|||||||
*
|
*
|
||||||
* @param tabTitle The title of the tab.
|
* @param tabTitle The title of the tab.
|
||||||
* @param panel The component to be displayed in the tab.
|
* @param panel The component to be displayed in the tab.
|
||||||
* @param notifyParentClose Notifies parent to trigger a close.
|
|
||||||
*/
|
*/
|
||||||
DataSourceTab(String tabTitle, BaseDataSourceSummaryPanel panel) {
|
DataSourceTab(String tabTitle, BaseDataSourceSummaryPanel panel) {
|
||||||
this(tabTitle, panel, panel::setDataSource, panel::getExports, panel::close);
|
this(tabTitle, panel, panel::setDataSource, panel::getExports, panel::close);
|
||||||
@ -155,7 +154,7 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel {
|
|||||||
Bundle.DataSourceSummaryTabbedPane_ingestHistoryTab_title(),
|
Bundle.DataSourceSummaryTabbedPane_ingestHistoryTab_title(),
|
||||||
ingestHistoryPanel,
|
ingestHistoryPanel,
|
||||||
ingestHistoryPanel::setDataSource,
|
ingestHistoryPanel::setDataSource,
|
||||||
null,
|
IngestJobExcelExport::getExports,
|
||||||
null),
|
null),
|
||||||
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_detailsTab_title(), new ContainerPanel()),
|
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_detailsTab_title(), new ContainerPanel()),
|
||||||
new DataSourceTab(
|
new DataSourceTab(
|
||||||
@ -270,7 +269,6 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel {
|
|||||||
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), caseEventsListener);
|
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), caseEventsListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called from within the constructor to initialize the form.
|
* This method is called from within the constructor to initialize the form.
|
||||||
* WARNING: Do NOT modify this code. The content of this method is always
|
* WARNING: Do NOT modify this code. The content of this method is always
|
||||||
|
@ -0,0 +1,253 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2021 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.datasourcesummary.ui;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import org.openide.util.NbBundle.Messages;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelSheetExport;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelTableExport;
|
||||||
|
import org.sleuthkit.datamodel.DataSource;
|
||||||
|
import org.sleuthkit.datamodel.IngestJobInfo;
|
||||||
|
import org.sleuthkit.datamodel.IngestModuleInfo;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class that handles exporting information in IngestJobInfoPanel to excel.
|
||||||
|
*/
|
||||||
|
@Messages({
|
||||||
|
"IngestJobExcelExport_startTimeColumn=Start Time",
|
||||||
|
"IngestJobExcelExport_endTimeColumn=End Time",
|
||||||
|
"IngestJobExcelExport_ingestStatusTimeColumn=Ingest Status",
|
||||||
|
"IngestJobExcelExport_moduleNameTimeColumn=Module Name",
|
||||||
|
"IngestJobExcelExport_versionColumn=Module Version",
|
||||||
|
"IngestJobExcelExport_sheetName=Ingest History"
|
||||||
|
})
|
||||||
|
class IngestJobExcelExport {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entry to display in an excel export.
|
||||||
|
*/
|
||||||
|
private static class IngestJobEntry {
|
||||||
|
|
||||||
|
private final Date startTime;
|
||||||
|
private final Date endTime;
|
||||||
|
private final String status;
|
||||||
|
private final String ingestModule;
|
||||||
|
private final String ingestModuleVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param startTime The ingest start time.
|
||||||
|
* @param endTime The ingest stop time.
|
||||||
|
* @param status The ingest status.
|
||||||
|
* @param ingestModule The ingest module.
|
||||||
|
* @param ingestModuleVersion The ingest module version.
|
||||||
|
*/
|
||||||
|
IngestJobEntry(Date startTime, Date endTime, String status, String ingestModule, String ingestModuleVersion) {
|
||||||
|
this.startTime = startTime;
|
||||||
|
this.endTime = endTime;
|
||||||
|
this.status = status;
|
||||||
|
this.ingestModule = ingestModule;
|
||||||
|
this.ingestModuleVersion = ingestModuleVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The ingest start time.
|
||||||
|
*/
|
||||||
|
Date getStartTime() {
|
||||||
|
return startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The ingest stop time.
|
||||||
|
*/
|
||||||
|
Date getEndTime() {
|
||||||
|
return endTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The ingest status.
|
||||||
|
*/
|
||||||
|
String getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The ingest module.
|
||||||
|
*/
|
||||||
|
String getIngestModule() {
|
||||||
|
return ingestModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The ingest module version.
|
||||||
|
*/
|
||||||
|
String getIngestModuleVersion() {
|
||||||
|
return ingestModuleVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(IngestJobExcelExport.class.getName());
|
||||||
|
private static final String DATETIME_FORMAT_STR = "yyyy/MM/dd HH:mm:ss";
|
||||||
|
private static final DateFormat DATETIME_FORMAT = new SimpleDateFormat(DATETIME_FORMAT_STR, Locale.getDefault());
|
||||||
|
|
||||||
|
// columns in the excel export table to be created.
|
||||||
|
private static final List<ColumnModel<IngestJobEntry, DefaultCellModel<?>>> COLUMNS = Arrays.asList(
|
||||||
|
new ColumnModel<>(
|
||||||
|
Bundle.IngestJobExcelExport_startTimeColumn(),
|
||||||
|
(entry) -> getDateCell(entry.getStartTime())),
|
||||||
|
new ColumnModel<>(
|
||||||
|
Bundle.IngestJobExcelExport_endTimeColumn(),
|
||||||
|
(entry) -> getDateCell(entry.getEndTime())),
|
||||||
|
new ColumnModel<>(
|
||||||
|
Bundle.IngestJobExcelExport_ingestStatusTimeColumn(),
|
||||||
|
(entry) -> new DefaultCellModel<>(entry.getStatus())),
|
||||||
|
new ColumnModel<>(
|
||||||
|
Bundle.IngestJobExcelExport_moduleNameTimeColumn(),
|
||||||
|
(entry) -> new DefaultCellModel<>(entry.getIngestModule())),
|
||||||
|
new ColumnModel<>(
|
||||||
|
Bundle.IngestJobExcelExport_versionColumn(),
|
||||||
|
(entry) -> new DefaultCellModel<>(entry.getIngestModuleVersion()))
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves data for a date cell.
|
||||||
|
*
|
||||||
|
* @param date The date.
|
||||||
|
* @return The data cell to be used in the excel export.
|
||||||
|
*/
|
||||||
|
private static DefaultCellModel<?> getDateCell(Date date) {
|
||||||
|
Function<Date, String> dateParser = (dt) -> dt == null ? "" : DATETIME_FORMAT.format(dt);
|
||||||
|
return new DefaultCellModel<>(date, dateParser, DATETIME_FORMAT_STR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves all the ingest job modules and versions for a job.
|
||||||
|
*
|
||||||
|
* @param job The ingest job.
|
||||||
|
* @return All of the corresponding entries sorted by module name.
|
||||||
|
*/
|
||||||
|
private static List<IngestJobEntry> getEntries(IngestJobInfo job) {
|
||||||
|
List<IngestModuleInfo> infoList = job.getIngestModuleInfo();
|
||||||
|
if (infoList == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
} else {
|
||||||
|
Date startTime = job.getStartDateTime();
|
||||||
|
Date endTime = job.getEndDateTime();
|
||||||
|
String status = job.getStatus().getDisplayName();
|
||||||
|
|
||||||
|
return infoList.stream()
|
||||||
|
.filter(info -> info != null)
|
||||||
|
.map(info -> new IngestJobEntry(startTime, endTime, status, info.getDisplayName(), info.getVersion()))
|
||||||
|
.sorted((a, b) -> {
|
||||||
|
boolean aIsNull = a == null || a.getIngestModule() == null;
|
||||||
|
boolean bIsNull = b == null || b.getIngestModule() == null;
|
||||||
|
if (aIsNull || bIsNull) {
|
||||||
|
return Boolean.compare(aIsNull, bIsNull);
|
||||||
|
} else {
|
||||||
|
return a.getIngestModule().compareTo(b.getIngestModule());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For output, show ingest job details in first row present. Otherwise, set
|
||||||
|
* to null.
|
||||||
|
*
|
||||||
|
* @param list The list of entries for an ingest job.
|
||||||
|
* @return The stream of entries to be displayed.
|
||||||
|
*/
|
||||||
|
private static Stream<IngestJobEntry> showFirstRowOnly(List<IngestJobEntry> list) {
|
||||||
|
return IntStream.range(0, list.size())
|
||||||
|
.mapToObj(idx -> {
|
||||||
|
IngestJobEntry entry = list.get(idx);
|
||||||
|
if (entry == null || idx == 0) {
|
||||||
|
return entry;
|
||||||
|
} else {
|
||||||
|
return new IngestJobEntry(null, null, null, entry.getIngestModule(), entry.getIngestModuleVersion());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of sheets to be exported for the Ingest History tab.
|
||||||
|
*
|
||||||
|
* @param dataSource The data source.
|
||||||
|
* @return The list of sheets to be included in an export.
|
||||||
|
*/
|
||||||
|
static List<ExcelSheetExport> getExports(DataSource dataSource) {
|
||||||
|
if (dataSource == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<IngestJobInfo> info = null;
|
||||||
|
try {
|
||||||
|
info = Case.getCurrentCaseThrows().getSleuthkitCase().getIngestJobs();
|
||||||
|
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||||
|
logger.log(Level.WARNING, "There was an error fetching ingest jobs", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info == null) {
|
||||||
|
info = Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<IngestJobEntry> toDisplay = info.stream()
|
||||||
|
.filter(job -> job != null && dataSource.getId() == job.getObjectId())
|
||||||
|
.sorted((a, b) -> {
|
||||||
|
// sort ingest jobs by time.
|
||||||
|
boolean aIsNull = a.getStartDateTime() == null;
|
||||||
|
boolean bIsNull = b.getStartDateTime() == null;
|
||||||
|
if (aIsNull || bIsNull) {
|
||||||
|
return Boolean.compare(aIsNull, bIsNull);
|
||||||
|
} else {
|
||||||
|
return a.getStartDateTime().compareTo(b.getStartDateTime());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map((job) -> getEntries(job))
|
||||||
|
.filter(lst -> lst != null)
|
||||||
|
.flatMap((lst) -> showFirstRowOnly(lst))
|
||||||
|
.filter(item -> item != null)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
return Arrays.asList(new ExcelTableExport<>(Bundle.IngestJobExcelExport_sheetName(), COLUMNS, toDisplay));
|
||||||
|
}
|
||||||
|
|
||||||
|
private IngestJobExcelExport() {
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,7 @@ import java.text.DecimalFormat;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides utilities for representing storage size in most relevant
|
* This class provides utilities for representing storage size in most relevant
|
||||||
@ -32,14 +33,64 @@ public final class SizeRepresentationUtil {
|
|||||||
private static final int SIZE_CONVERSION_CONSTANT = 1000;
|
private static final int SIZE_CONVERSION_CONSTANT = 1000;
|
||||||
private static final DecimalFormat APPROXIMATE_SIZE_FORMAT = new DecimalFormat("#.##");
|
private static final DecimalFormat APPROXIMATE_SIZE_FORMAT = new DecimalFormat("#.##");
|
||||||
|
|
||||||
private static List<String> UNITS = Arrays.asList(
|
/**
|
||||||
Bundle.SizeRepresentationUtil_units_bytes(),
|
* A size unit corresponding to orders of magnitude of bytes (kilobyte, gigabytes, etc.).
|
||||||
Bundle.SizeRepresentationUtil_units_kilobytes(),
|
*/
|
||||||
Bundle.SizeRepresentationUtil_units_megabytes(),
|
@NbBundle.Messages({
|
||||||
Bundle.SizeRepresentationUtil_units_gigabytes(),
|
"SizeRepresentationUtil_units_bytes=bytes",
|
||||||
Bundle.SizeRepresentationUtil_units_terabytes(),
|
"SizeRepresentationUtil_units_kilobytes=KB",
|
||||||
Bundle.SizeRepresentationUtil_units_petabytes()
|
"SizeRepresentationUtil_units_megabytes=MB",
|
||||||
);
|
"SizeRepresentationUtil_units_gigabytes=GB",
|
||||||
|
"SizeRepresentationUtil_units_terabytes=TB",
|
||||||
|
"SizeRepresentationUtil_units_petabytes=PB"
|
||||||
|
})
|
||||||
|
enum SizeUnit {
|
||||||
|
BYTES(Bundle.SizeRepresentationUtil_units_bytes(), "#", 0),
|
||||||
|
KB(Bundle.SizeRepresentationUtil_units_kilobytes(), "#,##0.00,", 1),
|
||||||
|
MB(Bundle.SizeRepresentationUtil_units_megabytes(), "#,##0.00,,", 2),
|
||||||
|
GB(Bundle.SizeRepresentationUtil_units_gigabytes(), "#,##0.00,,,", 3),
|
||||||
|
TB(Bundle.SizeRepresentationUtil_units_terabytes(), "#,##0.00,,,,", 4),
|
||||||
|
PB(Bundle.SizeRepresentationUtil_units_petabytes(), "#,##0.00,,,,,", 5);
|
||||||
|
|
||||||
|
private final String suffix;
|
||||||
|
private final String excelFormatString;
|
||||||
|
private final long divisor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
* @param suffix The string suffix to use for size unit.
|
||||||
|
* @param excelFormatString The excel format string to use for this size unit.
|
||||||
|
* @param power The power of 1000 of bytes for this size unit.
|
||||||
|
*/
|
||||||
|
SizeUnit(String suffix, String excelFormatString, int power) {
|
||||||
|
this.suffix = suffix;
|
||||||
|
|
||||||
|
// based on https://www.mrexcel.com/board/threads/how-do-i-format-cells-to-show-gb-mb-kb.140135/
|
||||||
|
this.excelFormatString = String.format("%s \"%s\"", excelFormatString, suffix);
|
||||||
|
this.divisor = (long) Math.pow(SIZE_CONVERSION_CONSTANT, power);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The string suffix to use for size unit.
|
||||||
|
*/
|
||||||
|
public String getSuffix() {
|
||||||
|
return suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The excel format string to use for this size unit.
|
||||||
|
*/
|
||||||
|
public String getExcelFormatString() {
|
||||||
|
return excelFormatString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The divisor to convert from bytes to this unit.
|
||||||
|
*/
|
||||||
|
public long getDivisor() {
|
||||||
|
return divisor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a long size in bytes as a string formated to be read by users.
|
* Get a long size in bytes as a string formated to be read by users.
|
||||||
@ -49,10 +100,31 @@ public final class SizeRepresentationUtil {
|
|||||||
* @return Return a string formated with a user friendly version of the size
|
* @return Return a string formated with a user friendly version of the size
|
||||||
* as a string, returns empty String when provided empty size.
|
* as a string, returns empty String when provided empty size.
|
||||||
*/
|
*/
|
||||||
public static String getSizeString(Long size) {
|
static String getSizeString(Long size) {
|
||||||
return getSizeString(size, APPROXIMATE_SIZE_FORMAT, true);
|
return getSizeString(size, APPROXIMATE_SIZE_FORMAT, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the relevant size unit that should be used for a particular size.
|
||||||
|
* @param size The size in bytes.
|
||||||
|
* @return The relevant size unit.
|
||||||
|
*/
|
||||||
|
static SizeUnit getSizeUnit(Long size) {
|
||||||
|
if (size == null) {
|
||||||
|
return SizeUnit.values()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int unitsIndex = 0; unitsIndex < SizeUnit.values().length; unitsIndex++) {
|
||||||
|
SizeUnit unit = SizeUnit.values()[unitsIndex];
|
||||||
|
long result = size / unit.getDivisor();
|
||||||
|
if (result < SIZE_CONVERSION_CONSTANT) {
|
||||||
|
return unit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SizeUnit.values()[SizeUnit.values().length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a long size in bytes as a string formated to be read by users.
|
* Get a long size in bytes as a string formated to be read by users.
|
||||||
*
|
*
|
||||||
@ -64,32 +136,21 @@ public final class SizeRepresentationUtil {
|
|||||||
* @return Return a string formated with a user friendly version of the size
|
* @return Return a string formated with a user friendly version of the size
|
||||||
* as a string, returns empty String when provided empty size.
|
* as a string, returns empty String when provided empty size.
|
||||||
*/
|
*/
|
||||||
@NbBundle.Messages({
|
static String getSizeString(Long size, DecimalFormat format, boolean showFullSize) {
|
||||||
"SizeRepresentationUtil_units_bytes= bytes",
|
|
||||||
"SizeRepresentationUtil_units_kilobytes= kB",
|
|
||||||
"SizeRepresentationUtil_units_megabytes= MB",
|
|
||||||
"SizeRepresentationUtil_units_gigabytes= GB",
|
|
||||||
"SizeRepresentationUtil_units_terabytes= TB",
|
|
||||||
"SizeRepresentationUtil_units_petabytes= PB"
|
|
||||||
})
|
|
||||||
public static String getSizeString(Long size, DecimalFormat format, boolean showFullSize) {
|
|
||||||
if (size == null) {
|
if (size == null) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
double approximateSize = size;
|
|
||||||
int unitsIndex = 0;
|
SizeUnit sizeUnit = getSizeUnit(size);
|
||||||
for (; unitsIndex < UNITS.size(); unitsIndex++) {
|
if (sizeUnit == null) {
|
||||||
if (approximateSize < SIZE_CONVERSION_CONSTANT) {
|
sizeUnit = SizeUnit.BYTES;
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
approximateSize /= SIZE_CONVERSION_CONSTANT;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String fullSize = size + UNITS.get(0);
|
String closestUnitSize = String.format("%s %s",
|
||||||
String closestUnitSize = format.format(approximateSize) + UNITS.get(unitsIndex);
|
format.format(((double) size) / sizeUnit.getDivisor()), sizeUnit.getSuffix());
|
||||||
|
|
||||||
if (unitsIndex == 0) {
|
String fullSize = String.format("%d %s", size, SizeUnit.BYTES.getSuffix());
|
||||||
|
if (sizeUnit.equals(SizeUnit.BYTES)) {
|
||||||
return fullSize;
|
return fullSize;
|
||||||
} else if (showFullSize) {
|
} else if (showFullSize) {
|
||||||
return String.format("%s (%s)", closestUnitSize, fullSize);
|
return String.format("%s (%s)", closestUnitSize, fullSize);
|
||||||
@ -98,6 +159,24 @@ public final class SizeRepresentationUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a default cell model using size units.
|
||||||
|
* @param bytes The number of bytes.
|
||||||
|
* @return The default cell model.
|
||||||
|
*/
|
||||||
|
static DefaultCellModel<?> getBytesCell(Long bytes) {
|
||||||
|
if (bytes == null) {
|
||||||
|
return new DefaultCellModel<>("");
|
||||||
|
} else {
|
||||||
|
SizeUnit unit = SizeRepresentationUtil.getSizeUnit(bytes);
|
||||||
|
if (unit == null) {
|
||||||
|
unit = SizeUnit.BYTES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DefaultCellModel<Long>(bytes, SizeRepresentationUtil::getSizeString, unit.getExcelFormatString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private SizeRepresentationUtil() {
|
private SizeRepresentationUtil() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,6 @@ import java.util.stream.Collectors;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory;
|
import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary;
|
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary;
|
import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.MimeTypeSummary;
|
import org.sleuthkit.autopsy.datasourcesummary.datamodel.MimeTypeSummary;
|
||||||
@ -40,13 +39,16 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
|
|||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.KeyValueItemExportable;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableLabel;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableLabel;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartPanel;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartPanel;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartPanel.PieChartItem;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartPanel.PieChartItem;
|
||||||
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeIdModuleFactory;
|
|
||||||
|
|
||||||
import org.sleuthkit.datamodel.DataSource;
|
import org.sleuthkit.datamodel.DataSource;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
@ -72,7 +74,8 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
"TypesPanel_fileMimeTypesChart_notAnalyzed_title=Not Analyzed",
|
"TypesPanel_fileMimeTypesChart_notAnalyzed_title=Not Analyzed",
|
||||||
"TypesPanel_usageLabel_title=Usage",
|
"TypesPanel_usageLabel_title=Usage",
|
||||||
"TypesPanel_osLabel_title=OS",
|
"TypesPanel_osLabel_title=OS",
|
||||||
"TypesPanel_sizeLabel_title=Size"})
|
"TypesPanel_sizeLabel_title=Size",
|
||||||
|
"TypesPanel_excelTabName=Types"})
|
||||||
class TypesPanel extends BaseDataSourceSummaryPanel {
|
class TypesPanel extends BaseDataSourceSummaryPanel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -167,10 +170,9 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
|||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private static final DecimalFormat INTEGER_SIZE_FORMAT = new DecimalFormat("#");
|
private static final DecimalFormat INTEGER_SIZE_FORMAT = new DecimalFormat("#");
|
||||||
private static final DecimalFormat COMMA_FORMATTER = new DecimalFormat("#,###");
|
private static final String COMMA_FORMAT_STR = "#,###";
|
||||||
private static final String FILE_TYPE_FACTORY = FileTypeIdModuleFactory.class.getCanonicalName();
|
|
||||||
private static final String FILE_TYPE_MODULE_NAME = FileTypeIdModuleFactory.getModuleName();
|
private static final DecimalFormat COMMA_FORMATTER = new DecimalFormat(COMMA_FORMAT_STR);
|
||||||
private static final Logger logger = Logger.getLogger(TypesPanel.class.getName());
|
|
||||||
|
|
||||||
private static final Color IMAGES_COLOR = new Color(156, 39, 176);
|
private static final Color IMAGES_COLOR = new Color(156, 39, 176);
|
||||||
private static final Color VIDEOS_COLOR = Color.YELLOW;
|
private static final Color VIDEOS_COLOR = Color.YELLOW;
|
||||||
@ -191,6 +193,15 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
|||||||
new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_unknown_title(), new HashSet<>(Arrays.asList("application/octet-stream")), UNKNOWN_COLOR)
|
new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_unknown_title(), new HashSet<>(Arrays.asList("application/octet-stream")), UNKNOWN_COLOR)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private final DataFetcher<DataSource, String> usageFetcher;
|
||||||
|
private final DataFetcher<DataSource, String> osFetcher;
|
||||||
|
private final DataFetcher<DataSource, Long> sizeFetcher;
|
||||||
|
|
||||||
|
private final DataFetcher<DataSource, Long> allocatedFetcher;
|
||||||
|
private final DataFetcher<DataSource, Long> unallocatedFetcher;
|
||||||
|
private final DataFetcher<DataSource, Long> slackFetcher;
|
||||||
|
private final DataFetcher<DataSource, Long> directoriesFetcher;
|
||||||
|
|
||||||
private final LoadableLabel usageLabel = new LoadableLabel(Bundle.TypesPanel_usageLabel_title());
|
private final LoadableLabel usageLabel = new LoadableLabel(Bundle.TypesPanel_usageLabel_title());
|
||||||
private final LoadableLabel osLabel = new LoadableLabel(Bundle.TypesPanel_osLabel_title());
|
private final LoadableLabel osLabel = new LoadableLabel(Bundle.TypesPanel_osLabel_title());
|
||||||
private final LoadableLabel sizeLabel = new LoadableLabel(Bundle.TypesPanel_sizeLabel_title());
|
private final LoadableLabel sizeLabel = new LoadableLabel(Bundle.TypesPanel_sizeLabel_title());
|
||||||
@ -246,42 +257,34 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
|||||||
|
|
||||||
super(mimeTypeData, typeData, containerData);
|
super(mimeTypeData, typeData, containerData);
|
||||||
|
|
||||||
|
this.usageFetcher = containerData::getDataSourceType;
|
||||||
|
this.osFetcher = containerData::getOperatingSystems;
|
||||||
|
|
||||||
|
this.sizeFetcher = (dataSource) -> dataSource == null ? null : dataSource.getSize();
|
||||||
|
|
||||||
|
this.allocatedFetcher = (dataSource) -> typeData.getCountOfAllocatedFiles(dataSource);
|
||||||
|
this.unallocatedFetcher = (dataSource) -> typeData.getCountOfUnallocatedFiles(dataSource);
|
||||||
|
this.slackFetcher = (dataSource) -> typeData.getCountOfSlackFiles(dataSource);
|
||||||
|
this.directoriesFetcher = (dataSource) -> typeData.getCountOfDirectories(dataSource);
|
||||||
|
|
||||||
this.dataFetchComponents = Arrays.asList(
|
this.dataFetchComponents = Arrays.asList(
|
||||||
// usage label worker
|
new DataFetchWorker.DataFetchComponents<>(usageFetcher, usageLabel::showDataFetchResult),
|
||||||
new DataFetchWorker.DataFetchComponents<>(
|
new DataFetchWorker.DataFetchComponents<>(osFetcher, osLabel::showDataFetchResult),
|
||||||
containerData::getDataSourceType,
|
new DataFetchWorker.DataFetchComponents<>(sizeFetcher,
|
||||||
(result) -> usageLabel.showDataFetchResult(result)),
|
(sizeResult) -> sizeLabel.showDataFetchResult(
|
||||||
// os label worker
|
DataFetchResult.getSubResult(sizeResult,
|
||||||
new DataFetchWorker.DataFetchComponents<>(
|
size -> SizeRepresentationUtil.getSizeString(size, INTEGER_SIZE_FORMAT, false)))),
|
||||||
containerData::getOperatingSystems,
|
|
||||||
(result) -> osLabel.showDataFetchResult(result)),
|
|
||||||
// size label worker
|
|
||||||
new DataFetchWorker.DataFetchComponents<>(
|
|
||||||
(dataSource) -> {
|
|
||||||
Long size = dataSource == null ? null : dataSource.getSize();
|
|
||||||
return SizeRepresentationUtil.getSizeString(size, INTEGER_SIZE_FORMAT, false);
|
|
||||||
},
|
|
||||||
sizeLabel::showDataFetchResult),
|
|
||||||
// file types worker
|
|
||||||
new DataFetchWorker.DataFetchComponents<>(
|
new DataFetchWorker.DataFetchComponents<>(
|
||||||
(dataSource) -> getMimeTypeCategoriesModel(mimeTypeData, dataSource),
|
(dataSource) -> getMimeTypeCategoriesModel(mimeTypeData, dataSource),
|
||||||
this::showMimeTypeCategories),
|
this::showMimeTypeCategories),
|
||||||
// allocated files worker
|
new DataFetchWorker.DataFetchComponents<>(allocatedFetcher,
|
||||||
new DataFetchWorker.DataFetchComponents<>(
|
countRes -> allocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count)))),
|
||||||
(dataSource) -> getStringOrZero(typeData.getCountOfAllocatedFiles(dataSource)),
|
new DataFetchWorker.DataFetchComponents<>(unallocatedFetcher,
|
||||||
allocatedLabel::showDataFetchResult),
|
countRes -> unallocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count)))),
|
||||||
// unallocated files worker
|
new DataFetchWorker.DataFetchComponents<>(slackFetcher,
|
||||||
new DataFetchWorker.DataFetchComponents<>(
|
countRes -> slackLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count)))),
|
||||||
(dataSource) -> getStringOrZero(typeData.getCountOfUnallocatedFiles(dataSource)),
|
new DataFetchWorker.DataFetchComponents<>(directoriesFetcher,
|
||||||
unallocatedLabel::showDataFetchResult),
|
countRes -> directoriesLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count))))
|
||||||
// slack files worker
|
|
||||||
new DataFetchWorker.DataFetchComponents<>(
|
|
||||||
(dataSource) -> getStringOrZero(typeData.getCountOfSlackFiles(dataSource)),
|
|
||||||
slackLabel::showDataFetchResult),
|
|
||||||
// directories worker
|
|
||||||
new DataFetchWorker.DataFetchComponents<>(
|
|
||||||
(dataSource) -> getStringOrZero(typeData.getCountOfDirectories(dataSource)),
|
|
||||||
directoriesLabel::showDataFetchResult)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
initComponents();
|
initComponents();
|
||||||
@ -406,11 +409,55 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
|||||||
return longVal == null ? "0" : COMMA_FORMATTER.format(longVal);
|
return longVal == null ? "0" : COMMA_FORMATTER.format(longVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a key value pair to be exported in a sheet.
|
||||||
|
*
|
||||||
|
* @param fetcher The means of fetching the data.
|
||||||
|
* @param key The key to use.
|
||||||
|
* @param dataSource The data source containing the data.
|
||||||
|
* @return The key value pair to be exported.
|
||||||
|
*/
|
||||||
|
private static KeyValueItemExportable getStrExportable(DataFetcher<DataSource, String> fetcher, String key, DataSource dataSource) {
|
||||||
|
String result = getFetchResult(fetcher, "Types", dataSource);
|
||||||
|
return (result == null) ? null : new KeyValueItemExportable(key, new DefaultCellModel<>(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a key value pair to be exported in a sheet formatting the long
|
||||||
|
* with commas separated by orders of 1000.
|
||||||
|
*
|
||||||
|
* @param fetcher The means of fetching the data.
|
||||||
|
* @param key The string key for this key value pair.
|
||||||
|
* @param dataSource The data source.
|
||||||
|
* @return The key value pair.
|
||||||
|
*/
|
||||||
|
private static KeyValueItemExportable getCountExportable(DataFetcher<DataSource, Long> fetcher, String key, DataSource dataSource) {
|
||||||
|
Long count = getFetchResult(fetcher, "Types", dataSource);
|
||||||
|
return (count == null) ? null : new KeyValueItemExportable(key,
|
||||||
|
new DefaultCellModel<Long>(count, COMMA_FORMATTER::format, COMMA_FORMAT_STR));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
List<ExcelExport.ExcelSheetExport> getExports(DataSource dataSource) {
|
List<ExcelExport.ExcelSheetExport> getExports(DataSource dataSource) {
|
||||||
|
if (dataSource == null) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Arrays.asList(new ExcelSpecialFormatExport(Bundle.TypesPanel_excelTabName(),
|
||||||
|
Stream.of(
|
||||||
|
getStrExportable(usageFetcher, Bundle.TypesPanel_usageLabel_title(), dataSource),
|
||||||
|
getStrExportable(osFetcher, Bundle.TypesPanel_osLabel_title(), dataSource),
|
||||||
|
new KeyValueItemExportable(Bundle.TypesPanel_sizeLabel_title(),
|
||||||
|
SizeRepresentationUtil.getBytesCell(getFetchResult(sizeFetcher, "Types", dataSource))),
|
||||||
|
getCountExportable(allocatedFetcher, Bundle.TypesPanel_filesByCategoryTable_allocatedRow_title(), dataSource),
|
||||||
|
getCountExportable(unallocatedFetcher, Bundle.TypesPanel_filesByCategoryTable_unallocatedRow_title(), dataSource),
|
||||||
|
getCountExportable(slackFetcher, Bundle.TypesPanel_filesByCategoryTable_slackRow_title(), dataSource),
|
||||||
|
getCountExportable(directoriesFetcher, Bundle.TypesPanel_filesByCategoryTable_directoryRow_title(), dataSource))
|
||||||
|
.filter(sheet -> sheet != null)
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called from within the constructor to initialize the form.
|
* This method is called from within the constructor to initialize the form.
|
||||||
* WARNING: Do NOT modify this code. The content of this method is always
|
* WARNING: Do NOT modify this code. The content of this method is always
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
|
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
|
||||||
|
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
|
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basic interface for a cell model.
|
* Basic interface for a cell model.
|
||||||
@ -29,20 +30,23 @@ public interface CellModel {
|
|||||||
* Describes the horizontal alignment.
|
* Describes the horizontal alignment.
|
||||||
*/
|
*/
|
||||||
public enum HorizontalAlign {
|
public enum HorizontalAlign {
|
||||||
LEFT(JLabel.LEFT),
|
LEFT(JLabel.LEFT, HorizontalAlignment.LEFT),
|
||||||
CENTER(JLabel.CENTER),
|
CENTER(JLabel.CENTER, HorizontalAlignment.CENTER),
|
||||||
RIGHT(JLabel.RIGHT);
|
RIGHT(JLabel.RIGHT, HorizontalAlignment.RIGHT);
|
||||||
|
|
||||||
private final int jlabelAlignment;
|
private final int jlabelAlignment;
|
||||||
|
private final HorizontalAlignment poiAlignment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for a HorizontalAlign enum.
|
* Constructor for a HorizontalAlign enum.
|
||||||
*
|
*
|
||||||
* @param jlabelAlignment The corresponding JLabel horizontal alignment
|
* @param jlabelAlignment The corresponding JLabel horizontal alignment
|
||||||
* number.
|
* number.
|
||||||
|
* @param poiAlignment Horizontal alignment for Apache POI.
|
||||||
*/
|
*/
|
||||||
HorizontalAlign(int jlabelAlignment) {
|
HorizontalAlign(int jlabelAlignment, HorizontalAlignment poiAlignment) {
|
||||||
this.jlabelAlignment = jlabelAlignment;
|
this.jlabelAlignment = jlabelAlignment;
|
||||||
|
this.poiAlignment = poiAlignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -52,6 +56,13 @@ public interface CellModel {
|
|||||||
int getJLabelAlignment() {
|
int getJLabelAlignment() {
|
||||||
return this.jlabelAlignment;
|
return this.jlabelAlignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Horizontal alignment for Apache POI.
|
||||||
|
*/
|
||||||
|
HorizontalAlignment getPoiAlignment() {
|
||||||
|
return poiAlignment;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,21 +24,21 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelTableExport.ExcelCellModel;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelCellModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default cell model.
|
* The default cell model.
|
||||||
*/
|
*/
|
||||||
public class DefaultCellModel<T> implements GuiCellModel, ExcelCellModel {
|
public class DefaultCellModel<T> implements GuiCellModel, ExcelCellModel {
|
||||||
|
|
||||||
private final T data;
|
final T data;
|
||||||
private final Function<T, String> stringConverter;
|
final Function<T, String> stringConverter;
|
||||||
String tooltip;
|
String tooltip;
|
||||||
CellModel.HorizontalAlign horizontalAlignment;
|
CellModel.HorizontalAlign horizontalAlignment;
|
||||||
Insets insets;
|
Insets insets;
|
||||||
List<MenuItem> popupMenu;
|
List<MenuItem> popupMenu;
|
||||||
Supplier<List<MenuItem>> menuItemSupplier;
|
Supplier<List<MenuItem>> menuItemSupplier;
|
||||||
private final String excelFormatString;
|
final String excelFormatString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main constructor.
|
* Main constructor.
|
||||||
@ -76,6 +76,7 @@ public class DefaultCellModel<T> implements GuiCellModel, ExcelCellModel {
|
|||||||
this.data = data;
|
this.data = data;
|
||||||
this.stringConverter = stringConverter;
|
this.stringConverter = stringConverter;
|
||||||
this.excelFormatString = excelFormatString;
|
this.excelFormatString = excelFormatString;
|
||||||
|
this.tooltip = getText();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2021 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic interface for a cell model.
|
||||||
|
*/
|
||||||
|
public interface ExcelCellModel extends CellModel {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The format string to be used with Apache POI during excel
|
||||||
|
* export or null if none necessary.
|
||||||
|
*/
|
||||||
|
String getExcelFormatString();
|
||||||
|
|
||||||
|
}
|
@ -21,13 +21,23 @@ package org.sleuthkit.autopsy.datasourcesummary.uiutils;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import org.apache.poi.ss.usermodel.Cell;
|
||||||
import org.apache.poi.ss.usermodel.CellStyle;
|
import org.apache.poi.ss.usermodel.CellStyle;
|
||||||
import org.apache.poi.ss.usermodel.Font;
|
import org.apache.poi.ss.usermodel.Font;
|
||||||
|
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
||||||
|
import org.apache.poi.ss.usermodel.Row;
|
||||||
import org.apache.poi.ss.usermodel.Workbook;
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
import org.apache.poi.ss.usermodel.Sheet;
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModel.HorizontalAlign;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for handling Excel exporting.
|
* Class for handling Excel exporting.
|
||||||
@ -59,6 +69,87 @@ public class ExcelExport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A cell style key that can be used with the WorksheetEnv to generate a
|
||||||
|
* cell style to be used in a POI excel document.
|
||||||
|
*/
|
||||||
|
static class CellStyleKey {
|
||||||
|
|
||||||
|
private final String formatString;
|
||||||
|
private final CellStyle cellStyle;
|
||||||
|
private final HorizontalAlign alignment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param formatString The format string or null if no special
|
||||||
|
* formatting.
|
||||||
|
* @param cellStyle The base cell style or null if default is to be
|
||||||
|
* used.
|
||||||
|
* @param alignment The horizontal alignment or null if default is to be
|
||||||
|
* used.
|
||||||
|
*/
|
||||||
|
CellStyleKey(String formatString, CellStyle cellStyle, HorizontalAlign alignment) {
|
||||||
|
this.formatString = formatString;
|
||||||
|
this.cellStyle = cellStyle;
|
||||||
|
this.alignment = alignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The format string or null if no special formatting.
|
||||||
|
*/
|
||||||
|
String getFormatString() {
|
||||||
|
return formatString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The base cell style or null if default is to be used.
|
||||||
|
*/
|
||||||
|
CellStyle getCellStyle() {
|
||||||
|
return cellStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The horizontal alignment or null if default is to be used.
|
||||||
|
*/
|
||||||
|
HorizontalAlign getAlignment() {
|
||||||
|
return alignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hash = 7;
|
||||||
|
hash = 29 * hash + Objects.hashCode(this.formatString);
|
||||||
|
hash = 29 * hash + Objects.hashCode(this.cellStyle);
|
||||||
|
hash = 29 * hash + Objects.hashCode(this.alignment);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final CellStyleKey other = (CellStyleKey) obj;
|
||||||
|
if (!Objects.equals(this.formatString, other.formatString)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Objects.equals(this.cellStyle, other.cellStyle)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.alignment != other.alignment) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class detailing aspects of the worksheet.
|
* Class detailing aspects of the worksheet.
|
||||||
*/
|
*/
|
||||||
@ -66,18 +157,47 @@ public class ExcelExport {
|
|||||||
|
|
||||||
private final CellStyle headerStyle;
|
private final CellStyle headerStyle;
|
||||||
private final Workbook parentWorkbook;
|
private final Workbook parentWorkbook;
|
||||||
|
private final CellStyle defaultStyle;
|
||||||
|
|
||||||
|
// maps a data format string / original cell style combination to a created cell style
|
||||||
|
private final Map<CellStyleKey, CellStyle> cellStyleCache = new HashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main constructor.
|
* Main constructor.
|
||||||
*
|
*
|
||||||
* @param headerStyle The cell style to use for headers.
|
* @param headerStyle The cell style to use for headers.
|
||||||
|
* @param defaultStyle The cell style to use as a default.
|
||||||
* @param parentWorkbook The parent workbook.
|
* @param parentWorkbook The parent workbook.
|
||||||
*/
|
*/
|
||||||
WorksheetEnv(CellStyle headerStyle, Workbook parentWorkbook) {
|
WorksheetEnv(CellStyle headerStyle, CellStyle defaultStyle, Workbook parentWorkbook) {
|
||||||
this.headerStyle = headerStyle;
|
this.headerStyle = headerStyle;
|
||||||
|
this.defaultStyle = defaultStyle;
|
||||||
this.parentWorkbook = parentWorkbook;
|
this.parentWorkbook = parentWorkbook;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a cell style signified by the given cell style key. If the
|
||||||
|
* key is already present, a cached version is returned.
|
||||||
|
*
|
||||||
|
* @param cellStyleKey The key.
|
||||||
|
* @return The cell style representing this key.
|
||||||
|
*/
|
||||||
|
public CellStyle getCellStyle(CellStyleKey cellStyleKey) {
|
||||||
|
return cellStyleCache.computeIfAbsent(cellStyleKey, (pair) -> {
|
||||||
|
CellStyle computed = this.parentWorkbook.createCellStyle();
|
||||||
|
computed.cloneStyleFrom(cellStyleKey.getCellStyle() == null ? defaultStyle : cellStyleKey.getCellStyle());
|
||||||
|
|
||||||
|
if (cellStyleKey.getAlignment() != null) {
|
||||||
|
computed.setAlignment(cellStyleKey.getAlignment().getPoiAlignment());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cellStyleKey.getFormatString() != null) {
|
||||||
|
computed.setDataFormat(this.parentWorkbook.getCreationHelper().createDataFormat().getFormat(cellStyleKey.getFormatString()));
|
||||||
|
}
|
||||||
|
return computed;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the cell style to use for headers.
|
* Returns the cell style to use for headers.
|
||||||
*
|
*
|
||||||
@ -87,6 +207,15 @@ public class ExcelExport {
|
|||||||
return headerStyle;
|
return headerStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the cell style for default items.
|
||||||
|
*
|
||||||
|
* @return The cell style for default items.
|
||||||
|
*/
|
||||||
|
public CellStyle getDefaultCellStyle() {
|
||||||
|
return defaultStyle;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the parent workbook.
|
* Returns the parent workbook.
|
||||||
*
|
*
|
||||||
@ -125,6 +254,7 @@ public class ExcelExport {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a singleton instance of this class.
|
* Retrieves a singleton instance of this class.
|
||||||
|
*
|
||||||
* @return The instance.
|
* @return The instance.
|
||||||
*/
|
*/
|
||||||
public static ExcelExport getInstance() {
|
public static ExcelExport getInstance() {
|
||||||
@ -141,6 +271,7 @@ public class ExcelExport {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the exports to a workbook.
|
* Writes the exports to a workbook.
|
||||||
|
*
|
||||||
* @param exports The sheets to export.
|
* @param exports The sheets to export.
|
||||||
* @param path The path to the output file.
|
* @param path The path to the output file.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
@ -160,10 +291,15 @@ public class ExcelExport {
|
|||||||
//headerFont.setFontHeightInPoints((short) 14);
|
//headerFont.setFontHeightInPoints((short) 14);
|
||||||
|
|
||||||
// Create a CellStyle with the font
|
// Create a CellStyle with the font
|
||||||
|
HorizontalAlignment alignment = HorizontalAlignment.LEFT;
|
||||||
CellStyle headerCellStyle = workbook.createCellStyle();
|
CellStyle headerCellStyle = workbook.createCellStyle();
|
||||||
headerCellStyle.setFont(headerFont);
|
headerCellStyle.setFont(headerFont);
|
||||||
|
headerCellStyle.setAlignment(alignment);
|
||||||
|
|
||||||
WorksheetEnv env = new WorksheetEnv(headerCellStyle, workbook);
|
CellStyle defaultCellStyle = workbook.createCellStyle();
|
||||||
|
defaultCellStyle.setAlignment(alignment);
|
||||||
|
|
||||||
|
WorksheetEnv env = new WorksheetEnv(headerCellStyle, defaultCellStyle, workbook);
|
||||||
|
|
||||||
if (exports != null) {
|
if (exports != null) {
|
||||||
for (int i = 0; i < exports.size(); i++) {
|
for (int i = 0; i < exports.size(); i++) {
|
||||||
@ -190,4 +326,46 @@ public class ExcelExport {
|
|||||||
// Closing the workbook
|
// Closing the workbook
|
||||||
workbook.close();
|
workbook.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an excel cell given the model.
|
||||||
|
*
|
||||||
|
* @param env The work sheet environment including the workbook.
|
||||||
|
* @param row The row in the excel document.
|
||||||
|
* @param colNum The column number (not zero-indexed).
|
||||||
|
* @param cellModel The model for the cell.
|
||||||
|
* @param cellStyle The style to use.
|
||||||
|
* @return The created cell.
|
||||||
|
*/
|
||||||
|
static Cell createCell(WorksheetEnv env, Row row, int colNum, ExcelCellModel cellModel, Optional<CellStyle> cellStyle) {
|
||||||
|
CellStyle cellStyleToUse = cellStyle.orElse(env.getDefaultCellStyle());
|
||||||
|
|
||||||
|
if (cellModel.getExcelFormatString() != null || cellModel.getHorizontalAlignment() != null) {
|
||||||
|
cellStyleToUse = env.getCellStyle(new CellStyleKey(cellModel.getExcelFormatString(), cellStyleToUse, cellModel.getHorizontalAlignment()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Object cellData = cellModel.getData();
|
||||||
|
Cell cell = row.createCell(colNum);
|
||||||
|
if (cellData instanceof Calendar) {
|
||||||
|
cell.setCellValue((Calendar) cellData);
|
||||||
|
} else if (cellData instanceof Date) {
|
||||||
|
cell.setCellValue((Date) cellData);
|
||||||
|
} else if (cellData instanceof Double) {
|
||||||
|
cell.setCellValue((Double) cellData);
|
||||||
|
} else if (cellData instanceof String) {
|
||||||
|
cell.setCellValue((String) cellData);
|
||||||
|
} else if (cellData instanceof Short) {
|
||||||
|
cell.setCellValue((Short) cellData);
|
||||||
|
} else if (cellData instanceof Integer) {
|
||||||
|
cell.setCellValue((Integer) cellData);
|
||||||
|
} else if (cellData instanceof Long) {
|
||||||
|
cell.setCellValue((Long) cellData);
|
||||||
|
} else if (cellData instanceof Float) {
|
||||||
|
cell.setCellValue((Float) cellData);
|
||||||
|
} else {
|
||||||
|
cell.setCellValue(cellModel.getText());
|
||||||
|
}
|
||||||
|
cell.setCellStyle(cellStyleToUse);
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,265 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2021 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import org.apache.poi.ss.usermodel.Row;
|
||||||
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelExportException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An excel export that has special row-by-row formatting.
|
||||||
|
*/
|
||||||
|
public class ExcelSpecialFormatExport implements ExcelExport.ExcelSheetExport {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The dimensions consumed by an item in an ExcelSpecialFormatExport list of
|
||||||
|
* items to be rendered.
|
||||||
|
*/
|
||||||
|
public static class ItemDimensions {
|
||||||
|
|
||||||
|
private final int rowStart;
|
||||||
|
private final int rowEnd;
|
||||||
|
private final int colStart;
|
||||||
|
private final int colEnd;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param rowStart The starting excel row of the item.
|
||||||
|
* @param colStart The starting excel column of the item.
|
||||||
|
* @param rowEnd The last excel row of the the item.
|
||||||
|
* @param colEnd The last excel column of the item.
|
||||||
|
*/
|
||||||
|
public ItemDimensions(int rowStart, int colStart, int rowEnd, int colEnd) {
|
||||||
|
this.rowStart = rowStart;
|
||||||
|
this.colStart = colStart;
|
||||||
|
this.rowEnd = rowEnd;
|
||||||
|
this.colEnd = colEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The starting excel row of the item.
|
||||||
|
*/
|
||||||
|
public int getRowStart() {
|
||||||
|
return rowStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The last excel row of the the item.
|
||||||
|
*/
|
||||||
|
public int getRowEnd() {
|
||||||
|
return rowEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The starting excel column of the item.
|
||||||
|
*/
|
||||||
|
public int getColStart() {
|
||||||
|
return colStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The last excel column of the item.
|
||||||
|
*/
|
||||||
|
public int getColEnd() {
|
||||||
|
return colEnd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An item to be exported in a specially formatted excel export.
|
||||||
|
*/
|
||||||
|
public interface ExcelItemExportable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the item to the sheet in the special format export sheet.
|
||||||
|
*
|
||||||
|
* @param sheet The sheet.
|
||||||
|
* @param rowStart The starting row to start writing.
|
||||||
|
* @param colStart The starting column to start writing.
|
||||||
|
* @param env The excel export context.
|
||||||
|
* @return The dimensions of what has been written.
|
||||||
|
* @throws ExcelExportException
|
||||||
|
*/
|
||||||
|
ItemDimensions write(Sheet sheet, int rowStart, int colStart, ExcelExport.WorksheetEnv env) throws ExcelExportException;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a string to a single cell in a specially formatted excel export.
|
||||||
|
*/
|
||||||
|
public static class SingleCellExportable implements ExcelItemExportable {
|
||||||
|
|
||||||
|
private final ExcelCellModel item;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param key The text to be written.
|
||||||
|
*/
|
||||||
|
public SingleCellExportable(String key) {
|
||||||
|
this(new DefaultCellModel<>(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param item The cell model to be written.
|
||||||
|
*/
|
||||||
|
public SingleCellExportable(ExcelCellModel item) {
|
||||||
|
this.item = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemDimensions write(Sheet sheet, int rowStart, int colStart, ExcelExport.WorksheetEnv env) throws ExcelExportException {
|
||||||
|
Row row = sheet.createRow(rowStart);
|
||||||
|
ExcelExport.createCell(env, row, colStart, item, Optional.empty());
|
||||||
|
return new ItemDimensions(rowStart, colStart, rowStart, colStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a row consisting of first column as a key and second column as a
|
||||||
|
* value.
|
||||||
|
*/
|
||||||
|
public static class KeyValueItemExportable implements ExcelItemExportable {
|
||||||
|
|
||||||
|
private final ExcelCellModel key;
|
||||||
|
private final ExcelCellModel value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param key The string key to be exported.
|
||||||
|
* @param value The cell model to be exported.
|
||||||
|
*/
|
||||||
|
public KeyValueItemExportable(String key, ExcelCellModel value) {
|
||||||
|
this(new DefaultCellModel<>(key), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param key The cell key to be exported.
|
||||||
|
* @param value The cell model to be exported.
|
||||||
|
*/
|
||||||
|
public KeyValueItemExportable(ExcelCellModel key, ExcelCellModel value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemDimensions write(Sheet sheet, int rowStart, int colStart, ExcelExport.WorksheetEnv env) throws ExcelExportException {
|
||||||
|
Row row = sheet.createRow(rowStart);
|
||||||
|
ExcelExport.createCell(env, row, colStart, key, Optional.of(env.getHeaderStyle()));
|
||||||
|
ExcelExport.createCell(env, row, colStart + 1, value, Optional.empty());
|
||||||
|
return new ItemDimensions(rowStart, colStart, rowStart, colStart + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A special format excel export item that shows a title and a list of items
|
||||||
|
* indented one column.
|
||||||
|
*
|
||||||
|
* i.e.
|
||||||
|
* <pre>
|
||||||
|
* title
|
||||||
|
* item 1
|
||||||
|
* item 2
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public static class TitledExportable implements ExcelItemExportable {
|
||||||
|
|
||||||
|
private static final int DEFAULT_INDENT = 1;
|
||||||
|
|
||||||
|
private final String title;
|
||||||
|
private final List<? extends ExcelItemExportable> children;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param title The title for the export.
|
||||||
|
* @param children The children to be indented and enumerated.
|
||||||
|
*/
|
||||||
|
public TitledExportable(String title, List<? extends ExcelItemExportable> children) {
|
||||||
|
this.title = title;
|
||||||
|
this.children = children;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemDimensions write(Sheet sheet, int rowStart, int colStart, ExcelExport.WorksheetEnv env) throws ExcelExportException {
|
||||||
|
ExcelExport.createCell(env, sheet.createRow(rowStart), colStart, new DefaultCellModel<>(title), Optional.of(env.getHeaderStyle()));
|
||||||
|
int curRow = rowStart + 1;
|
||||||
|
int maxCol = colStart;
|
||||||
|
for (ExcelItemExportable export : children) {
|
||||||
|
if (export == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemDimensions thisItemDim = export.write(sheet, curRow, colStart + DEFAULT_INDENT, env);
|
||||||
|
curRow = thisItemDim.getRowEnd() + 1;
|
||||||
|
maxCol = Math.max(thisItemDim.getColEnd(), maxCol);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ItemDimensions(rowStart, colStart, curRow - 1, maxCol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String sheetName;
|
||||||
|
private final List<ExcelItemExportable> exports;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param sheetName The name of the sheet.
|
||||||
|
* @param exports The row-by-row items to be exported.
|
||||||
|
*/
|
||||||
|
public ExcelSpecialFormatExport(String sheetName, List<ExcelItemExportable> exports) {
|
||||||
|
this.sheetName = sheetName;
|
||||||
|
this.exports = exports == null ? Collections.emptyList() : exports;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSheetName() {
|
||||||
|
return sheetName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderSheet(Sheet sheet, ExcelExport.WorksheetEnv env) throws ExcelExportException {
|
||||||
|
int rowStart = 0;
|
||||||
|
int maxCol = 0;
|
||||||
|
for (ExcelItemExportable export : exports) {
|
||||||
|
if (export == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemDimensions dimensions = export.write(sheet, rowStart, 0, env);
|
||||||
|
rowStart = dimensions.getRowEnd() + 1;
|
||||||
|
maxCol = Math.max(maxCol, dimensions.getColEnd());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize all columns to fit the content size
|
||||||
|
for (int i = 0; i <= maxCol; i++) {
|
||||||
|
sheet.autoSizeColumn(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -18,40 +18,26 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
|
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
|
||||||
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import org.apache.poi.ss.usermodel.Cell;
|
import org.apache.poi.ss.usermodel.Cell;
|
||||||
import org.apache.poi.ss.usermodel.CellStyle;
|
|
||||||
import org.apache.poi.ss.usermodel.Row;
|
import org.apache.poi.ss.usermodel.Row;
|
||||||
import org.apache.poi.ss.usermodel.Sheet;
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
import org.apache.poi.ss.usermodel.Workbook;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelExportException;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelTableExport.ExcelCellModel;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelSheetExport;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.ExcelItemExportable;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.ItemDimensions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An excel sheet export of table data.
|
* An excel sheet export of table data.
|
||||||
*/
|
*/
|
||||||
public class ExcelTableExport<T, C extends ExcelCellModel> implements ExcelExport.ExcelSheetExport {
|
public class ExcelTableExport<T, C extends ExcelCellModel> implements ExcelSheetExport, ExcelItemExportable {
|
||||||
|
|
||||||
/**
|
|
||||||
* Basic interface for a cell model.
|
|
||||||
*/
|
|
||||||
public interface ExcelCellModel extends CellModel {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The format string to be used with Apache POI during excel
|
|
||||||
* export or null if none necessary.
|
|
||||||
*/
|
|
||||||
String getExcelFormatString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private final String sheetName;
|
private final String sheetName;
|
||||||
private final List<ColumnModel<T, C>> columns;
|
private final List<ColumnModel<T, C>> columns;
|
||||||
private final List<T> data;
|
private final List<T> data;
|
||||||
|
private final int columnIndent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main constructor.
|
* Main constructor.
|
||||||
@ -62,9 +48,23 @@ public class ExcelTableExport<T, C extends ExcelCellModel> implements ExcelExpor
|
|||||||
* @param data The data to export.
|
* @param data The data to export.
|
||||||
*/
|
*/
|
||||||
public ExcelTableExport(String sheetName, List<ColumnModel<T, C>> columns, List<T> data) {
|
public ExcelTableExport(String sheetName, List<ColumnModel<T, C>> columns, List<T> data) {
|
||||||
|
this(sheetName, columns, data, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param sheetName The name of the sheet. NOTE: There can be no duplicates
|
||||||
|
* in a workbook.
|
||||||
|
* @param columns The columns of the table.
|
||||||
|
* @param data The data to export.
|
||||||
|
* @param columnIndent The column indent.
|
||||||
|
*/
|
||||||
|
public ExcelTableExport(String sheetName, List<ColumnModel<T, C>> columns, List<T> data, int columnIndent) {
|
||||||
this.sheetName = sheetName;
|
this.sheetName = sheetName;
|
||||||
this.columns = columns;
|
this.columns = columns;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
|
this.columnIndent = columnIndent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -74,11 +74,20 @@ public class ExcelTableExport<T, C extends ExcelCellModel> implements ExcelExpor
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderSheet(Sheet sheet, ExcelExport.WorksheetEnv style) throws ExcelExport.ExcelExportException {
|
public void renderSheet(Sheet sheet, ExcelExport.WorksheetEnv style) throws ExcelExport.ExcelExportException {
|
||||||
renderSheet(sheet, style, columns, data);
|
renderSheet(sheet, style, 0, columnIndent, columns, data);
|
||||||
|
|
||||||
// Resize all columns to fit the content size
|
// Resize all columns to fit the content size
|
||||||
for (int i = 0; i < columns.size(); i++) {
|
for (int i = 0; i < columns.size(); i++) {
|
||||||
sheet.autoSizeColumn(i);
|
sheet.autoSizeColumn(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemDimensions write(Sheet sheet, int rowStart, int colStart, ExcelExport.WorksheetEnv env) throws ExcelExportException {
|
||||||
|
int columnStart = columnIndent + colStart;
|
||||||
|
int rowsWritten = renderSheet(sheet, env, rowStart, columnStart, columns, data);
|
||||||
|
return new ItemDimensions(rowStart, columnStart, rowStart + rowsWritten - 1, this.columns == null ? columnStart : columnStart + this.columns.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,88 +95,44 @@ public class ExcelTableExport<T, C extends ExcelCellModel> implements ExcelExpor
|
|||||||
*
|
*
|
||||||
* @param sheet The sheet.
|
* @param sheet The sheet.
|
||||||
* @param worksheetEnv The worksheet environment and preferences.
|
* @param worksheetEnv The worksheet environment and preferences.
|
||||||
|
* @param rowStart The row to start in.
|
||||||
|
* @param colStart The column to start in.
|
||||||
* @param columns The columns.
|
* @param columns The columns.
|
||||||
* @param data The data.
|
* @param data The data.
|
||||||
* @throws ExcelExportException
|
* @throws ExcelExportException
|
||||||
|
* @return The number of rows (including the header) written.
|
||||||
*/
|
*/
|
||||||
private static <T, C extends ExcelCellModel> void renderSheet(
|
private static <T, C extends ExcelCellModel> int renderSheet(
|
||||||
Sheet sheet, ExcelExport.WorksheetEnv worksheetEnv, List<ColumnModel<T, C>> columns, List<T> data)
|
Sheet sheet,
|
||||||
|
ExcelExport.WorksheetEnv worksheetEnv,
|
||||||
|
int rowStart,
|
||||||
|
int colStart,
|
||||||
|
List<ColumnModel<T, C>> columns, List<T> data)
|
||||||
throws ExcelExport.ExcelExportException {
|
throws ExcelExport.ExcelExportException {
|
||||||
|
|
||||||
List<T> safeData = data == null ? Collections.emptyList() : data;
|
List<T> safeData = data == null ? Collections.emptyList() : data;
|
||||||
// Create a header row
|
// Create a header row
|
||||||
Row headerRow = sheet.createRow(0);
|
Row headerRow = sheet.createRow(rowStart);
|
||||||
// Create header cells
|
// Create header cells
|
||||||
for (int i = 0; i < columns.size(); i++) {
|
for (int i = 0; i < columns.size(); i++) {
|
||||||
Cell cell = headerRow.createCell(i);
|
Cell cell = headerRow.createCell(i + colStart);
|
||||||
cell.setCellValue(columns.get(i).getHeaderTitle());
|
cell.setCellValue(columns.get(i).getHeaderTitle());
|
||||||
cell.setCellStyle(worksheetEnv.getHeaderStyle());
|
cell.setCellStyle(worksheetEnv.getHeaderStyle());
|
||||||
}
|
}
|
||||||
// freeze header row
|
// freeze header row
|
||||||
sheet.createFreezePane(0, 1);
|
sheet.createFreezePane(0, 1);
|
||||||
// Create Cell Style for each column (if one is needed)
|
// Create Cell Style for each column (if one is needed)
|
||||||
Map<String, CellStyle> cellStyles = new HashMap<>();
|
|
||||||
for (int rowNum = 0; rowNum < safeData.size(); rowNum++) {
|
for (int rowNum = 0; rowNum < safeData.size(); rowNum++) {
|
||||||
T rowData = safeData.get(rowNum);
|
T rowData = safeData.get(rowNum);
|
||||||
Row row = sheet.createRow(rowNum + 1);
|
Row row = sheet.createRow(rowNum + rowStart + 1);
|
||||||
for (int colNum = 0; colNum < columns.size(); colNum++) {
|
for (int colNum = 0; colNum < columns.size(); colNum++) {
|
||||||
ColumnModel<T, ? extends ExcelCellModel> colModel = columns.get(colNum);
|
ColumnModel<T, ? extends ExcelCellModel> colModel = columns.get(colNum);
|
||||||
ExcelCellModel cellModel = colModel.getCellRenderer().apply(rowData);
|
ExcelCellModel cellModel = colModel.getCellRenderer().apply(rowData);
|
||||||
String formatString = cellModel.getExcelFormatString();
|
ExcelExport.createCell(worksheetEnv, row, colNum + colStart, cellModel, Optional.empty());
|
||||||
Optional<CellStyle> cellStyle = (formatString == null)
|
|
||||||
? Optional.empty()
|
|
||||||
: Optional.of(cellStyles.computeIfAbsent(formatString, k -> createCellStyle(worksheetEnv.getParentWorkbook(), formatString)));
|
|
||||||
createCell(row, colNum, cellModel, cellStyle);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
return safeData.size() + 1;
|
||||||
* Create a cell style in the workbook with the given format string.
|
|
||||||
*
|
|
||||||
* @param workbook The workbook.
|
|
||||||
* @param formatString The format string.
|
|
||||||
* @return The cell style.
|
|
||||||
*/
|
|
||||||
private static <T> CellStyle createCellStyle(Workbook workbook, String formatString) {
|
|
||||||
CellStyle cellStyle = workbook.createCellStyle();
|
|
||||||
cellStyle.setDataFormat(workbook.getCreationHelper().createDataFormat().getFormat(formatString));
|
|
||||||
return cellStyle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an excel cell given the model.
|
|
||||||
*
|
|
||||||
* @param row The row in the excel document.
|
|
||||||
* @param colNum The column number (not zero-indexed).
|
|
||||||
* @param cellModel The model for the cell.
|
|
||||||
* @param cellStyle The style to use.
|
|
||||||
* @return The created cell.
|
|
||||||
*/
|
|
||||||
private static Cell createCell(Row row, int colNum, ExcelCellModel cellModel, Optional<CellStyle> cellStyle) {
|
|
||||||
Object cellData = cellModel.getData();
|
|
||||||
Cell cell = row.createCell(colNum);
|
|
||||||
if (cellData instanceof Calendar) {
|
|
||||||
cell.setCellValue((Calendar) cellData);
|
|
||||||
} else if (cellData instanceof Date) {
|
|
||||||
cell.setCellValue((Date) cellData);
|
|
||||||
} else if (cellData instanceof Double) {
|
|
||||||
cell.setCellValue((Double) cellData);
|
|
||||||
} else if (cellData instanceof String) {
|
|
||||||
cell.setCellValue((String) cellData);
|
|
||||||
} else if (cellData instanceof Short) {
|
|
||||||
cell.setCellValue((Short) cellData);
|
|
||||||
} else if (cellData instanceof Integer) {
|
|
||||||
cell.setCellValue((Integer) cellData);
|
|
||||||
} else if (cellData instanceof Long) {
|
|
||||||
cell.setCellValue((Long) cellData);
|
|
||||||
} else if (cellData instanceof Float) {
|
|
||||||
cell.setCellValue((Float) cellData);
|
|
||||||
} else {
|
|
||||||
cell.setCellValue(cellModel.getText());
|
|
||||||
}
|
|
||||||
cellStyle.ifPresent(cs -> cell.setCellStyle(cs));
|
|
||||||
return cell;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ ExportCSV.saveNodesToCSV.empty=No data to export
|
|||||||
# {0} - Output file
|
# {0} - Output file
|
||||||
ExportCSV.saveNodesToCSV.fileExists=File {0} already exists
|
ExportCSV.saveNodesToCSV.fileExists=File {0} already exists
|
||||||
ExportCSV.saveNodesToCSV.noCurrentCase=No open case available
|
ExportCSV.saveNodesToCSV.noCurrentCase=No open case available
|
||||||
ExportCSV.title.text=Export selected rows to CSV
|
ExportCSV.title.text=Export Selected Rows to CSV
|
||||||
ExternalViewerAction.actionPerformed.failure.exe.message=The file is an executable and will not be opened.
|
ExternalViewerAction.actionPerformed.failure.exe.message=The file is an executable and will not be opened.
|
||||||
ExternalViewerAction.actionPerformed.failure.IO.message=There is no associated editor for files of this type or the associated application failed to launch.
|
ExternalViewerAction.actionPerformed.failure.IO.message=There is no associated editor for files of this type or the associated application failed to launch.
|
||||||
ExternalViewerAction.actionPerformed.failure.missingFile.message=The file no longer exists.
|
ExternalViewerAction.actionPerformed.failure.missingFile.message=The file no longer exists.
|
||||||
|
@ -85,7 +85,7 @@ public final class ExportCSVAction extends AbstractAction {
|
|||||||
/**
|
/**
|
||||||
* Private constructor for the action.
|
* Private constructor for the action.
|
||||||
*/
|
*/
|
||||||
@NbBundle.Messages({"ExportCSV.title.text=Export selected rows to CSV"})
|
@NbBundle.Messages({"ExportCSV.title.text=Export Selected Rows to CSV"})
|
||||||
private ExportCSVAction() {
|
private ExportCSVAction() {
|
||||||
super(Bundle.ExportCSV_title_text());
|
super(Bundle.ExportCSV_title_text());
|
||||||
}
|
}
|
||||||
|
@ -156,12 +156,11 @@ public class DiscoveryAttributes {
|
|||||||
public void addAttributeToResults(List<Result> results, SleuthkitCase caseDb,
|
public void addAttributeToResults(List<Result> results, SleuthkitCase caseDb,
|
||||||
CentralRepository centralRepoDb) throws DiscoveryException {
|
CentralRepository centralRepoDb) throws DiscoveryException {
|
||||||
try {
|
try {
|
||||||
Map<String, String> domainsToCategories = getDomainsWithWebCategories(caseDb);
|
Map<String, Set<String>> domainsToCategories = getDomainsWithWebCategories(caseDb);
|
||||||
for (Result result : results) {
|
for (Result result : results) {
|
||||||
if (result instanceof ResultDomain) {
|
if (result instanceof ResultDomain) {
|
||||||
ResultDomain domain = (ResultDomain) result;
|
ResultDomain domain = (ResultDomain) result;
|
||||||
String webCategory = domainsToCategories.get(domain.getDomain());
|
domain.addWebCategories(domainsToCategories.get(domain.getDomain()));
|
||||||
domain.setWebCategory(webCategory);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (TskCoreException | InterruptedException ex) {
|
} catch (TskCoreException | InterruptedException ex) {
|
||||||
@ -174,24 +173,23 @@ public class DiscoveryAttributes {
|
|||||||
* the category name attribute. Each ResultDomain is then parsed and
|
* the category name attribute. Each ResultDomain is then parsed and
|
||||||
* matched against this map of values.
|
* matched against this map of values.
|
||||||
*/
|
*/
|
||||||
private Map<String, String> getDomainsWithWebCategories(SleuthkitCase caseDb) throws TskCoreException, InterruptedException {
|
private Map<String, Set<String>> getDomainsWithWebCategories(SleuthkitCase caseDb) throws TskCoreException, InterruptedException {
|
||||||
Map<String, String> domainToCategory = new HashMap<>();
|
Map<String, Set<String>> domainToCategory = new HashMap<>();
|
||||||
|
|
||||||
for (BlackboardArtifact artifact : caseDb.getBlackboardArtifacts(TSK_WEB_CATEGORIZATION)) {
|
for (BlackboardArtifact artifact : caseDb.getBlackboardArtifacts(TSK_WEB_CATEGORIZATION)) {
|
||||||
if (Thread.currentThread().isInterrupted()) {
|
if (Thread.currentThread().isInterrupted()) {
|
||||||
throw new InterruptedException();
|
throw new InterruptedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
BlackboardAttribute webCategory = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME));
|
BlackboardAttribute webCategory = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME));
|
||||||
BlackboardAttribute domain = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN));
|
BlackboardAttribute domain = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN));
|
||||||
|
|
||||||
if (webCategory != null && domain != null) {
|
if (webCategory != null && domain != null) {
|
||||||
String webCatDisplayName = webCategory.getValueString();
|
|
||||||
String domainDisplayName = domain.getValueString().trim().toLowerCase();
|
String domainDisplayName = domain.getValueString().trim().toLowerCase();
|
||||||
domainToCategory.put(domainDisplayName, webCatDisplayName);
|
if (!domainToCategory.containsKey(domainDisplayName)) {
|
||||||
|
domainToCategory.put(domainDisplayName, new HashSet<>());
|
||||||
|
}
|
||||||
|
domainToCategory.get(domainDisplayName).add(webCategory.getValueString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return domainToCategory;
|
return domainToCategory;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,8 @@ import java.time.Instant;
|
|||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.temporal.TemporalAdjusters;
|
import java.time.temporal.TemporalAdjusters;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
@ -802,12 +804,14 @@ public class DiscoveryKeyUtils {
|
|||||||
*/
|
*/
|
||||||
static class DomainCategoryGroupKey extends GroupKey {
|
static class DomainCategoryGroupKey extends GroupKey {
|
||||||
|
|
||||||
private final String webCategory;
|
private final Set<String> webCategories = new HashSet<>();
|
||||||
|
private final String displayName;
|
||||||
|
|
||||||
DomainCategoryGroupKey(Result result) {
|
DomainCategoryGroupKey(Result result) {
|
||||||
if (result instanceof ResultDomain) {
|
if (result instanceof ResultDomain) {
|
||||||
ResultDomain domain = (ResultDomain) result;
|
ResultDomain domain = (ResultDomain) result;
|
||||||
this.webCategory = domain.getWebCategory();
|
this.webCategories.addAll(domain.getWebCategories());
|
||||||
|
displayName = String.join(",", webCategories);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Input result should be of type ResultDomain");
|
throw new IllegalArgumentException("Input result should be of type ResultDomain");
|
||||||
}
|
}
|
||||||
@ -815,7 +819,8 @@ public class DiscoveryKeyUtils {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
String getDisplayName() {
|
String getDisplayName() {
|
||||||
return this.webCategory;
|
|
||||||
|
return this.displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -828,21 +833,27 @@ public class DiscoveryKeyUtils {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(getWebCategory());
|
return Objects.hash(webCategories);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(GroupKey otherGroupKey) {
|
public int compareTo(GroupKey otherGroupKey) {
|
||||||
if (otherGroupKey instanceof DomainCategoryGroupKey) {
|
if (otherGroupKey instanceof DomainCategoryGroupKey) {
|
||||||
DomainCategoryGroupKey webCategoryKey = (DomainCategoryGroupKey) otherGroupKey;
|
if (webCategories.size() != ((DomainCategoryGroupKey) otherGroupKey).getWebCategories().size()) {
|
||||||
return this.webCategory.compareTo(webCategoryKey.getWebCategory());
|
return 1;
|
||||||
|
}
|
||||||
|
if (webCategories.containsAll(((DomainCategoryGroupKey) otherGroupKey).getWebCategories())) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return compareClassNames(otherGroupKey);
|
return compareClassNames(otherGroupKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String getWebCategory() {
|
Set<String> getWebCategories() {
|
||||||
return this.webCategory;
|
return Collections.unmodifiableSet(webCategories);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1198,9 +1209,9 @@ public class DiscoveryKeyUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the next closed Sunday given an epoch time and timezone.
|
* Get the next closed Sunday given an epoch time and timezone. Dates for
|
||||||
* Dates for grouping are managed on a weekly basis. Each Sunday
|
* grouping are managed on a weekly basis. Each Sunday acts as the boundary
|
||||||
* acts as the boundary and representative for the week.
|
* and representative for the week.
|
||||||
*/
|
*/
|
||||||
private static ZonedDateTime getCurrentWeekCutOff(long epochSeconds, ResultDomain domainResult) {
|
private static ZonedDateTime getCurrentWeekCutOff(long epochSeconds, ResultDomain domainResult) {
|
||||||
Instant startActivityAsInsant = Instant.ofEpochSecond(epochSeconds);
|
Instant startActivityAsInsant = Instant.ofEpochSecond(epochSeconds);
|
||||||
@ -1274,9 +1285,8 @@ public class DiscoveryKeyUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Key representing the number of page views.
|
* Key representing the number of page views. Page views are defined as the
|
||||||
* Page views are defined as the number of TSK_WEB_HISTORY artifacts that match
|
* number of TSK_WEB_HISTORY artifacts that match a domain value.
|
||||||
* a domain value.
|
|
||||||
*/
|
*/
|
||||||
static class PageViewsGroupKey extends GroupKey {
|
static class PageViewsGroupKey extends GroupKey {
|
||||||
|
|
||||||
|
@ -95,7 +95,6 @@ public class DomainSearch {
|
|||||||
final Map<GroupKey, List<Result>> searchResults = searchCache.get(
|
final Map<GroupKey, List<Result>> searchResults = searchCache.get(
|
||||||
userName, filters, groupAttributeType, groupSortingType,
|
userName, filters, groupAttributeType, groupSortingType,
|
||||||
domainSortingMethod, caseDb, centralRepoDb);
|
domainSortingMethod, caseDb, centralRepoDb);
|
||||||
|
|
||||||
// Transform the cached results into a map of group key to group size.
|
// Transform the cached results into a map of group key to group size.
|
||||||
final LinkedHashMap<GroupKey, Integer> groupSizes = new LinkedHashMap<>();
|
final LinkedHashMap<GroupKey, Integer> groupSizes = new LinkedHashMap<>();
|
||||||
for (GroupKey groupKey : searchResults.keySet()) {
|
for (GroupKey groupKey : searchResults.keySet()) {
|
||||||
@ -139,7 +138,6 @@ public class DomainSearch {
|
|||||||
userName, filters, groupAttributeType, groupSortingType,
|
userName, filters, groupAttributeType, groupSortingType,
|
||||||
domainSortingMethod, caseDb, centralRepoDb);
|
domainSortingMethod, caseDb, centralRepoDb);
|
||||||
final List<Result> domainsInGroup = searchResults.get(groupKey);
|
final List<Result> domainsInGroup = searchResults.get(groupKey);
|
||||||
|
|
||||||
final List<Result> page = new ArrayList<>();
|
final List<Result> page = new ArrayList<>();
|
||||||
for (int i = startingEntry; (i < startingEntry + numberOfEntries)
|
for (int i = startingEntry; (i < startingEntry + numberOfEntries)
|
||||||
&& (i < domainsInGroup.size()); i++) {
|
&& (i < domainsInGroup.size()); i++) {
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.discovery.search;
|
package org.sleuthkit.autopsy.discovery.search;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.HashSet;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
@ -36,7 +38,7 @@ public class ResultDomain extends Result {
|
|||||||
private final Long filesDownloaded;
|
private final Long filesDownloaded;
|
||||||
private final Long countOfKnownAccountTypes;
|
private final Long countOfKnownAccountTypes;
|
||||||
private final String accountTypes;
|
private final String accountTypes;
|
||||||
private String webCategory;
|
private final Set<String> webCategories = new HashSet<>();
|
||||||
|
|
||||||
private final Content dataSource;
|
private final Content dataSource;
|
||||||
private final long dataSourceId;
|
private final long dataSourceId;
|
||||||
@ -60,6 +62,24 @@ public class ResultDomain extends Result {
|
|||||||
this.accountTypes = accountTypes;
|
this.accountTypes = accountTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a copy of the specified ResultDomain, without a category set.
|
||||||
|
*
|
||||||
|
* @param resultDomain The ResultDomain to copy
|
||||||
|
*/
|
||||||
|
ResultDomain(ResultDomain resultDomain) {
|
||||||
|
this.domain = resultDomain.getDomain();
|
||||||
|
this.dataSource = resultDomain.getDataSource();
|
||||||
|
this.dataSourceId = resultDomain.getDataSourceObjectId();
|
||||||
|
this.activityStart = resultDomain.getActivityStart();
|
||||||
|
this.activityEnd = resultDomain.getActivityEnd();
|
||||||
|
this.totalPageViews = resultDomain.getTotalPageViews();
|
||||||
|
this.pageViewsInLast60 = resultDomain.getPageViewsInLast60Days();
|
||||||
|
this.filesDownloaded = resultDomain.getFilesDownloaded();
|
||||||
|
this.countOfKnownAccountTypes = resultDomain.getCountOfKnownAccountTypes();
|
||||||
|
this.accountTypes = resultDomain.getAccountTypes();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the domain represented as a String.
|
* Get the domain represented as a String.
|
||||||
*
|
*
|
||||||
@ -123,20 +143,24 @@ public class ResultDomain extends Result {
|
|||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
"ResultDomain_getDefaultCategory=Uncategorized"
|
"ResultDomain_getDefaultCategory=Uncategorized"
|
||||||
})
|
})
|
||||||
public String getWebCategory() {
|
public Set<String> getWebCategories() {
|
||||||
if (webCategory == null) {
|
Set<String> returnList = new HashSet<>();
|
||||||
return Bundle.ResultDomain_getDefaultCategory();
|
if (webCategories.isEmpty()) {
|
||||||
|
returnList.add(Bundle.ResultDomain_getDefaultCategory());
|
||||||
} else {
|
} else {
|
||||||
return webCategory;
|
returnList.addAll(webCategories);
|
||||||
}
|
}
|
||||||
|
return returnList;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the web category for this domain (derived from TSK_WEB_CATEGORY)
|
* Add the web categories for this domain (derived from TSK_WEB_CATEGORY)
|
||||||
* artifacts.
|
* artifacts.
|
||||||
*/
|
*/
|
||||||
public void setWebCategory(String webCategory) {
|
public void addWebCategories(Set<String> categories) {
|
||||||
this.webCategory = webCategory;
|
if (categories != null && !categories.isEmpty()) {
|
||||||
|
this.webCategories.addAll(categories);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -144,8 +168,8 @@ public class ResultDomain extends Result {
|
|||||||
* (TSK_WEB_ACCOUNT_TYPE).
|
* (TSK_WEB_ACCOUNT_TYPE).
|
||||||
*/
|
*/
|
||||||
public boolean hasKnownAccountType() {
|
public boolean hasKnownAccountType() {
|
||||||
return countOfKnownAccountTypes != null
|
return getCountOfKnownAccountTypes() != null
|
||||||
&& countOfKnownAccountTypes > 0;
|
&& getCountOfKnownAccountTypes() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -192,4 +216,11 @@ public class ResultDomain extends Result {
|
|||||||
+ this.pageViewsInLast60 + ", downloads=" + this.filesDownloaded + ", frequency="
|
+ this.pageViewsInLast60 + ", downloads=" + this.filesDownloaded + ", frequency="
|
||||||
+ this.getFrequency() + "]";
|
+ this.getFrequency() + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the countOfKnownAccountTypes
|
||||||
|
*/
|
||||||
|
Long getCountOfKnownAccountTypes() {
|
||||||
|
return countOfKnownAccountTypes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -768,7 +768,6 @@ public class SearchFiltering {
|
|||||||
CentralRepository centralRepoDb) throws DiscoveryException {
|
CentralRepository centralRepoDb) throws DiscoveryException {
|
||||||
DiscoveryAttributes.PreviouslyNotableAttribute previouslyNotableAttr = new DiscoveryAttributes.PreviouslyNotableAttribute();
|
DiscoveryAttributes.PreviouslyNotableAttribute previouslyNotableAttr = new DiscoveryAttributes.PreviouslyNotableAttribute();
|
||||||
previouslyNotableAttr.addAttributeToResults(currentResults, caseDb, centralRepoDb);
|
previouslyNotableAttr.addAttributeToResults(currentResults, caseDb, centralRepoDb);
|
||||||
|
|
||||||
List<Result> filteredResults = new ArrayList<>();
|
List<Result> filteredResults = new ArrayList<>();
|
||||||
for (Result file : currentResults) {
|
for (Result file : currentResults) {
|
||||||
if (file.getPreviouslyNotableInCR() == SearchData.PreviouslyNotable.PREVIOUSLY_NOTABLE) {
|
if (file.getPreviouslyNotableInCR() == SearchData.PreviouslyNotable.PREVIOUSLY_NOTABLE) {
|
||||||
|
@ -21,10 +21,13 @@ package org.sleuthkit.autopsy.discovery.search;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey;
|
import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -75,14 +78,45 @@ class SearchResults {
|
|||||||
void add(List<Result> results) {
|
void add(List<Result> results) {
|
||||||
for (Result result : results) {
|
for (Result result : results) {
|
||||||
// Add the file to the appropriate group, creating it if necessary
|
// Add the file to the appropriate group, creating it if necessary
|
||||||
|
if (result.getType() == SearchData.Type.DOMAIN && attrType instanceof DiscoveryAttributes.DomainCategoryAttribute) {
|
||||||
|
/**
|
||||||
|
* This section is to add results to individual groups based on
|
||||||
|
* the individual Web Categories the domain is part of instead
|
||||||
|
* of the combination of categories. So that results will show
|
||||||
|
* up in every group for which they have a category.
|
||||||
|
*/
|
||||||
|
for (String category : ((ResultDomain) result).getWebCategories()) {
|
||||||
|
if (!StringUtils.isBlank(category)) {
|
||||||
|
ResultDomain currentResult = (ResultDomain) result;
|
||||||
|
Set<String> newCategorySet = new HashSet<>();
|
||||||
|
newCategorySet.add(category);
|
||||||
|
ResultDomain copyOfResult = new ResultDomain(currentResult);
|
||||||
|
copyOfResult.addWebCategories(newCategorySet);
|
||||||
|
GroupKey groupKey = attrType.getGroupKey(copyOfResult);
|
||||||
|
//purposefully adding original instead of copy so it will display all categories when looking at domain
|
||||||
|
addResultToGroupMap(groupKey, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
GroupKey groupKey = attrType.getGroupKey(result);
|
GroupKey groupKey = attrType.getGroupKey(result);
|
||||||
|
addResultToGroupMap(groupKey, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private helper method to add a result to the groupMap with a specified
|
||||||
|
* key.
|
||||||
|
*
|
||||||
|
* @param groupKey The key to add the result under.
|
||||||
|
* @param result The result to add.
|
||||||
|
*/
|
||||||
|
private void addResultToGroupMap(GroupKey groupKey, Result result) {
|
||||||
if (!groupMap.containsKey(groupKey)) {
|
if (!groupMap.containsKey(groupKey)) {
|
||||||
groupMap.put(groupKey, new Group(groupSortingType, groupKey));
|
groupMap.put(groupKey, new Group(groupSortingType, groupKey));
|
||||||
}
|
}
|
||||||
groupMap.get(groupKey).addResult(result);
|
groupMap.get(groupKey).addResult(result);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run after all files have been added to sortGroupsAndFiles the groups and
|
* Run after all files have been added to sortGroupsAndFiles the groups and
|
||||||
@ -166,7 +200,6 @@ class SearchResults {
|
|||||||
for (Group group : groupList) {
|
for (Group group : groupList) {
|
||||||
map.put(group.getGroupKey(), group.getResults());
|
map.put(group.getGroupKey(), group.getResults());
|
||||||
}
|
}
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,10 +54,11 @@ DocumentPanel.numberOfImages.noImages=No images
|
|||||||
DocumentPanel.numberOfImages.text=1 of {0} images
|
DocumentPanel.numberOfImages.text=1 of {0} images
|
||||||
DocumentWrapper.previewInitialValue=Preview not generated yet.
|
DocumentWrapper.previewInitialValue=Preview not generated yet.
|
||||||
DomainDetailsPanel.miniTimelineTitle.text=Timeline
|
DomainDetailsPanel.miniTimelineTitle.text=Timeline
|
||||||
|
DomainDetailsPanel.otherOccurrencesTab.title=Other Occurrences
|
||||||
# {0} - startDate
|
# {0} - startDate
|
||||||
# {1} - endDate
|
# {1} - endDate
|
||||||
DomainSummaryPanel.activity.text=Activity: {0} to {1}
|
DomainSummaryPanel.activity.text=Activity: {0} to {1}
|
||||||
DomainSummaryPanel.category.text=Category:
|
DomainSummaryPanel.category.text=Categories:
|
||||||
DomainSummaryPanel.downloads.text=Files downloaded:
|
DomainSummaryPanel.downloads.text=Files downloaded:
|
||||||
DomainSummaryPanel.loadingImages.text=Loading thumbnail...
|
DomainSummaryPanel.loadingImages.text=Loading thumbnail...
|
||||||
DomainSummaryPanel.no.text=No
|
DomainSummaryPanel.no.text=No
|
||||||
|
@ -24,7 +24,9 @@ import java.awt.Point;
|
|||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
import java.util.Set;
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JList;
|
import javax.swing.JList;
|
||||||
@ -171,7 +173,7 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer<
|
|||||||
"DomainSummaryPanel.downloads.text=Files downloaded: ",
|
"DomainSummaryPanel.downloads.text=Files downloaded: ",
|
||||||
"DomainSummaryPanel.notability.text=Previously tagged as notable: ",
|
"DomainSummaryPanel.notability.text=Previously tagged as notable: ",
|
||||||
"DomainSummaryPanel.userRole.text=Account type: ",
|
"DomainSummaryPanel.userRole.text=Account type: ",
|
||||||
"DomainSummaryPanel.category.text=Category: ",
|
"DomainSummaryPanel.category.text=Categories: ",
|
||||||
"DomainSummaryPanel.loadingImages.text=Loading thumbnail...",
|
"DomainSummaryPanel.loadingImages.text=Loading thumbnail...",
|
||||||
"DomainSummaryPanel.no.text=No",
|
"DomainSummaryPanel.no.text=No",
|
||||||
"DomainSummaryPanel.yes.text=Yes"})
|
"DomainSummaryPanel.yes.text=Yes"})
|
||||||
@ -188,7 +190,9 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer<
|
|||||||
notability += Bundle.DomainSummaryPanel_no_text();
|
notability += Bundle.DomainSummaryPanel_no_text();
|
||||||
}
|
}
|
||||||
domainNotabilityLabel.setText(notability);
|
domainNotabilityLabel.setText(notability);
|
||||||
categoryLabel.setText(Bundle.DomainSummaryPanel_category_text() + value.getResultDomain().getWebCategory());
|
Set<String> webCategories = new HashSet<>();
|
||||||
|
webCategories.addAll(value.getResultDomain().getWebCategories());
|
||||||
|
categoryLabel.setText(Bundle.DomainSummaryPanel_category_text() + String.join(",", webCategories));
|
||||||
activityLabel.setText(Bundle.DomainSummaryPanel_activity_text(startDate, endDate));
|
activityLabel.setText(Bundle.DomainSummaryPanel_activity_text(startDate, endDate));
|
||||||
totalVisitsLabel.setText(Bundle.DomainSummaryPanel_totalPages_text() + value.getResultDomain().getTotalPageViews());
|
totalVisitsLabel.setText(Bundle.DomainSummaryPanel_totalPages_text() + value.getResultDomain().getTotalPageViews());
|
||||||
pagesLabel.setText(Bundle.DomainSummaryPanel_pages_text() + value.getResultDomain().getPageViewsInLast60Days());
|
pagesLabel.setText(Bundle.DomainSummaryPanel_pages_text() + value.getResultDomain().getPageViewsInLast60Days());
|
||||||
|
@ -29,6 +29,7 @@ import org.sleuthkit.datamodel.FileSystem;
|
|||||||
import org.sleuthkit.datamodel.LayoutFile;
|
import org.sleuthkit.datamodel.LayoutFile;
|
||||||
import org.sleuthkit.datamodel.LocalFile;
|
import org.sleuthkit.datamodel.LocalFile;
|
||||||
import org.sleuthkit.datamodel.LocalDirectory;
|
import org.sleuthkit.datamodel.LocalDirectory;
|
||||||
|
import org.sleuthkit.datamodel.OsAccount;
|
||||||
import org.sleuthkit.datamodel.SlackFile;
|
import org.sleuthkit.datamodel.SlackFile;
|
||||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||||
|
|
||||||
@ -107,4 +108,9 @@ final class GetRootDirectoryVisitor extends GetFilesContentVisitor {
|
|||||||
public Collection<AbstractFile> visit(BlackboardArtifact art) {
|
public Collection<AbstractFile> visit(BlackboardArtifact art) {
|
||||||
return getAllFromChildren(art);
|
return getAllFromChildren(art);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<AbstractFile> visit(OsAccount art) {
|
||||||
|
return getAllFromChildren(art);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import java.awt.EventQueue;
|
|||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -46,6 +47,7 @@ import javax.annotation.concurrent.GuardedBy;
|
|||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
import org.netbeans.api.progress.ProgressHandle;
|
import org.netbeans.api.progress.ProgressHandle;
|
||||||
import org.openide.util.Cancellable;
|
import org.openide.util.Cancellable;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
@ -289,7 +291,8 @@ public class IngestManager implements IngestProgressSnapshotProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an ingest stream from the given ingest settings for a data source.
|
* Creates an ingest stream from the given ingest settings for a data
|
||||||
|
* source.
|
||||||
*
|
*
|
||||||
* @param dataSource The data source
|
* @param dataSource The data source
|
||||||
* @param settings The ingest job settings.
|
* @param settings The ingest job settings.
|
||||||
@ -313,7 +316,6 @@ public class IngestManager implements IngestProgressSnapshotProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the number of file ingest threads the ingest manager is using to do
|
* Gets the number of file ingest threads the ingest manager is using to do
|
||||||
* ingest jobs.
|
* ingest jobs.
|
||||||
@ -395,6 +397,21 @@ public class IngestManager implements IngestProgressSnapshotProvider {
|
|||||||
"IngestManager.startupErr.dlgErrorList=Errors:"
|
"IngestManager.startupErr.dlgErrorList=Errors:"
|
||||||
})
|
})
|
||||||
IngestJobStartResult startIngestJob(IngestJob job) {
|
IngestJobStartResult startIngestJob(IngestJob job) {
|
||||||
|
|
||||||
|
// initialize IngestMessageInbox, if it hasn't been initialized yet. This can't be done in
|
||||||
|
// the constructor because that ends up freezing the UI on startup (JIRA-7345).
|
||||||
|
if (SwingUtilities.isEventDispatchThread()) {
|
||||||
|
initIngestMessageInbox();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
SwingUtilities.invokeAndWait(() -> initIngestMessageInbox());
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
// ignore interruptions
|
||||||
|
} catch (InvocationTargetException ex) {
|
||||||
|
logger.log(Level.WARNING, "There was an error starting ingest message inbox", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
List<IngestModuleError> errors = null;
|
List<IngestModuleError> errors = null;
|
||||||
Case openCase;
|
Case openCase;
|
||||||
try {
|
try {
|
||||||
@ -521,7 +538,8 @@ public class IngestManager implements IngestProgressSnapshotProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an ingest job event property change listener for the given event types.
|
* Adds an ingest job event property change listener for the given event
|
||||||
|
* types.
|
||||||
*
|
*
|
||||||
* @param eventTypes The event types to listen for
|
* @param eventTypes The event types to listen for
|
||||||
* @param listener The PropertyChangeListener to be added
|
* @param listener The PropertyChangeListener to be added
|
||||||
@ -563,7 +581,8 @@ public class IngestManager implements IngestProgressSnapshotProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an ingest module event property change listener for given event types.
|
* Adds an ingest module event property change listener for given event
|
||||||
|
* types.
|
||||||
*
|
*
|
||||||
* @param eventTypes The event types to listen for
|
* @param eventTypes The event types to listen for
|
||||||
* @param listener The PropertyChangeListener to be removed.
|
* @param listener The PropertyChangeListener to be removed.
|
||||||
@ -699,8 +718,11 @@ public class IngestManager implements IngestProgressSnapshotProvider {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Causes the ingest manager to get the top component used to display ingest
|
* Causes the ingest manager to get the top component used to display ingest
|
||||||
* inbox messages. Called by the custom installer for this package once the
|
* inbox messages. Used to be called by the custom installer for this
|
||||||
* window system is initialized.
|
* package once the window system is initialized, but that results in a lot
|
||||||
|
* of UI components being initialized, which freezes the UI for a long
|
||||||
|
* period of time(JIRA-7345). Instead we are now initializing
|
||||||
|
* IngestMessageInbox immediately prior to running first ingest job.
|
||||||
*/
|
*/
|
||||||
void initIngestMessageInbox() {
|
void initIngestMessageInbox() {
|
||||||
synchronized (this.ingestMessageBoxLock) {
|
synchronized (this.ingestMessageBoxLock) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2014 Basis Technology Corp.
|
* Copyright 2011-2021 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -19,7 +19,6 @@
|
|||||||
package org.sleuthkit.autopsy.ingest;
|
package org.sleuthkit.autopsy.ingest;
|
||||||
|
|
||||||
import org.openide.modules.ModuleInstall;
|
import org.openide.modules.ModuleInstall;
|
||||||
import org.openide.windows.WindowManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes ingest manager when the module is loaded
|
* Initializes ingest manager when the module is loaded
|
||||||
@ -41,15 +40,8 @@ public class Installer extends ModuleInstall {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void restored() {
|
public void restored() {
|
||||||
final IngestManager manager = IngestManager.getInstance();
|
// initialize ingest manager
|
||||||
WindowManager.getDefault().invokeWhenUIReady(new Runnable() {
|
IngestManager.getInstance();
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
//at this point UI top component is present for sure, ensure manager has it
|
|
||||||
manager.initIngestMessageInbox();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -20,10 +20,15 @@ package org.sleuthkit.autopsy.machinesettings;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.prefs.Preferences;
|
import java.util.prefs.Preferences;
|
||||||
|
import java.util.stream.Stream;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.NbPreferences;
|
import org.openide.util.NbPreferences;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||||
import org.sleuthkit.autopsy.coreutils.FileUtil;
|
import org.sleuthkit.autopsy.coreutils.FileUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,26 +38,122 @@ public final class UserMachinePreferences {
|
|||||||
|
|
||||||
private static final Preferences preferences = NbPreferences.forModule(UserMachinePreferences.class);
|
private static final Preferences preferences = NbPreferences.forModule(UserMachinePreferences.class);
|
||||||
|
|
||||||
private static final String TEMP_DIR_KEY = "TempDirectory";
|
/**
|
||||||
|
* The user specified choice for where the temp directory should be located.
|
||||||
|
*/
|
||||||
|
public enum TempDirChoice {
|
||||||
|
/**
|
||||||
|
* A custom location specified with an absolute path by the user.
|
||||||
|
*/
|
||||||
|
CUSTOM,
|
||||||
|
/**
|
||||||
|
* Equivalent to java.io.tmpdir.
|
||||||
|
*/
|
||||||
|
SYSTEM,
|
||||||
|
/**
|
||||||
|
* If a case is open, a sub directory of the case.
|
||||||
|
*/
|
||||||
|
CASE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a default temporary directory that is a subdirectory of
|
* Returns the temp directory choice that matches the string provided
|
||||||
* java.io.tmpdir.
|
* (whitespace and case insensitive).
|
||||||
*
|
*
|
||||||
* @return The absolute path to the temp directory.
|
* @param val The string value.
|
||||||
|
* @return The choice or empty if not found.
|
||||||
*/
|
*/
|
||||||
private static String getDefaultTempDirectory() {
|
static Optional<TempDirChoice> getValue(String val) {
|
||||||
return Paths.get(System.getProperty("java.io.tmpdir")).toAbsolutePath().toString();
|
if (val == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Stream.of(TempDirChoice.values())
|
||||||
|
.filter(tempChoice -> tempChoice.name().equalsIgnoreCase(val.trim()))
|
||||||
|
.findFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String CUSTOM_TEMP_DIR_KEY = "TempDirectory";
|
||||||
|
private static final String TEMP_DIR_CHOICE_KEY = "TempDirChoice";
|
||||||
|
|
||||||
|
private static final String AUTOPSY_SUBDIR = UserPreferences.getAppName();
|
||||||
|
private static final String CASE_SUBDIR = "Temp";
|
||||||
|
|
||||||
|
private static final TempDirChoice DEFAULT_CHOICE = TempDirChoice.SYSTEM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A subdirectory of java.io.tmpdir.
|
||||||
|
*/
|
||||||
|
private static File getSystemTempDirFile() {
|
||||||
|
return Paths.get(System.getProperty("java.io.tmpdir"), AUTOPSY_SUBDIR).toFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the base user-specified temporary directory.
|
* @return A subdirectory of the open case or getSystemTempDirFile if no
|
||||||
|
* open case.
|
||||||
|
*/
|
||||||
|
private static File getCaseTempDirFile() {
|
||||||
|
try {
|
||||||
|
String caseDirStr = Case.getCurrentCaseThrows().getCaseDirectory();
|
||||||
|
return Paths.get(caseDirStr, CASE_SUBDIR).toFile();
|
||||||
|
} catch (NoCurrentCaseException ex) {
|
||||||
|
return getSystemTempDirFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the custom directory subdirectory to be used for temp files
|
||||||
|
* (otherwise java.io.tmpdir subdir).
|
||||||
|
*
|
||||||
|
* @return A subdirectory of the custom user-specified path. If no path is
|
||||||
|
* specified, getSystemTempDirFile() is returned instead.
|
||||||
|
*/
|
||||||
|
private static File getCustomTempDirFile() {
|
||||||
|
String customDirectory = getCustomTempDirectory();
|
||||||
|
return (StringUtils.isBlank(customDirectory))
|
||||||
|
? getSystemTempDirFile() : Paths.get(customDirectory, AUTOPSY_SUBDIR).toFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the temp directory file to use based on user choice.
|
||||||
|
*
|
||||||
|
* @return The directory.
|
||||||
|
*/
|
||||||
|
private static File getTempDirFile() {
|
||||||
|
TempDirChoice choice = getTempDirChoice();
|
||||||
|
switch (choice) {
|
||||||
|
case CASE:
|
||||||
|
return getCaseTempDirFile();
|
||||||
|
case CUSTOM:
|
||||||
|
return getCustomTempDirFile();
|
||||||
|
case SYSTEM:
|
||||||
|
default:
|
||||||
|
return getSystemTempDirFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the temp directory to use based on settings. This method also
|
||||||
|
* ensures the temp directory has been created.
|
||||||
*
|
*
|
||||||
* @return The base user-specified temporary directory.
|
* @return The base user-specified temporary directory.
|
||||||
*/
|
*/
|
||||||
public static String getBaseTempDirectory() {
|
public static String getTempDirectory() {
|
||||||
String tempDir = preferences.get(TEMP_DIR_KEY, null);
|
File dir = getTempDirFile();
|
||||||
return StringUtils.isBlank(tempDir) ? getDefaultTempDirectory() : tempDir;
|
dir = dir == null ? getSystemTempDirFile() : dir;
|
||||||
|
|
||||||
|
if (!dir.exists()) {
|
||||||
|
dir.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
return dir.getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The user-specified custom temp directory path or empty string.
|
||||||
|
*/
|
||||||
|
public static String getCustomTempDirectory() {
|
||||||
|
return preferences.get(CUSTOM_TEMP_DIR_KEY, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,8 +165,7 @@ public final class UserMachinePreferences {
|
|||||||
* @return True if this is a valid location for a temp directory.
|
* @return True if this is a valid location for a temp directory.
|
||||||
*
|
*
|
||||||
* @throws UserMachinePreferencesException If path could not be validated
|
* @throws UserMachinePreferencesException If path could not be validated
|
||||||
* due to mkdirs failure or the
|
* due to mkdirs failure or the directory is not read/write.
|
||||||
* directory is not read/write.
|
|
||||||
*/
|
*/
|
||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
"# {0} - path",
|
"# {0} - path",
|
||||||
@ -98,9 +198,31 @@ public final class UserMachinePreferences {
|
|||||||
* @throws UserMachinePreferencesException If the directory cannot be
|
* @throws UserMachinePreferencesException If the directory cannot be
|
||||||
* accessed or created.
|
* accessed or created.
|
||||||
*/
|
*/
|
||||||
public static void setBaseTempDirectory(String path) throws UserMachinePreferencesException {
|
public static void setCustomTempDirectory(String path) throws UserMachinePreferencesException {
|
||||||
validateTempDirectory(path);
|
validateTempDirectory(path);
|
||||||
preferences.put(TEMP_DIR_KEY, path);
|
preferences.put(CUSTOM_TEMP_DIR_KEY, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The user selection for how the temp directory should be handled
|
||||||
|
* (temp directory in case folder, in java.io.tmpdir, custom path).
|
||||||
|
*/
|
||||||
|
public static TempDirChoice getTempDirChoice() {
|
||||||
|
return TempDirChoice.getValue(preferences.get(TEMP_DIR_CHOICE_KEY, null))
|
||||||
|
.orElse(DEFAULT_CHOICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the temp directory choice (i.e. system, case, custom).
|
||||||
|
* @param tempDirChoice The choice (must be non-null).
|
||||||
|
* @throws UserMachinePreferencesException
|
||||||
|
*/
|
||||||
|
public static void setTempDirChoice(TempDirChoice tempDirChoice) throws UserMachinePreferencesException {
|
||||||
|
if (tempDirChoice == null) {
|
||||||
|
throw new UserMachinePreferencesException("Expected non-null temp dir choice");
|
||||||
|
}
|
||||||
|
|
||||||
|
preferences.put(TEMP_DIR_CHOICE_KEY, tempDirChoice.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
private UserMachinePreferences() {
|
private UserMachinePreferences() {
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
|
|
||||||
<FileName filename="accounts de 0.tsv" description="Accounts_de">
|
<FileName filename="accounts de 0.tsv" description="Accounts_de">
|
||||||
<ArtifactName artifactname="TSK_SERVICE_ACCOUNT" comment="accounts de 0">
|
<ArtifactName artifactname="TSK_SERVICE_ACCOUNT" comment="accounts de 0">
|
||||||
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Last password entry" required="no" />
|
<AttributeName attributename="null" columnName="Last password entry" required="no" />
|
||||||
<AttributeName attributename="TSK_USER_ID" columnName="Name" required="yes" />
|
<AttributeName attributename="TSK_USER_ID" columnName="Name" required="yes" />
|
||||||
<AttributeName attributename="TSK_PROG_NAME" columnName="Type" required="yes" />
|
<AttributeName attributename="TSK_PROG_NAME" columnName="Type" required="yes" />
|
||||||
</ArtifactName>
|
</ArtifactName>
|
||||||
@ -66,13 +66,13 @@
|
|||||||
|
|
||||||
<FileName filename="Browser cookies.tsv" description="Browser Cookies">
|
<FileName filename="Browser cookies.tsv" description="Browser Cookies">
|
||||||
<ArtifactName artifactname="TSK_WEB_COOKIE" comment="Browser Cookies">
|
<ArtifactName artifactname="TSK_WEB_COOKIE" comment="Browser Cookies">
|
||||||
<AttributeName attributename="TSK_DATETIME_START" columnName="Last Access Date" required="yes" />
|
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Last Access Date" required="yes" />
|
||||||
<AttributeName attributename="TSK_DOMAIN" columnName="Host" required="yes" />
|
<AttributeName attributename="TSK_URL" columnName="Host" required="yes" />
|
||||||
<AttributeName attributename="TSK_NAME" columnName="Name" required="yes" />
|
<AttributeName attributename="TSK_NAME" columnName="Name" required="yes" />
|
||||||
<AttributeName attributename="TSK_VALUE" columnName="Value" required="yes" />
|
<AttributeName attributename="TSK_VALUE" columnName="Value" required="yes" />
|
||||||
<AttributeName attributename="TSK_DATETIME_CREATED" columnName="Created Date" required="yes" />
|
<AttributeName attributename="TSK_DATETIME_CREATED" columnName="Created Date" required="yes" />
|
||||||
<AttributeName attributename="TSK_DATETIME_END" columnName="Expiration Date" required="yes" />
|
<AttributeName attributename="TSK_DATETIME_END" columnName="Expiration Date" required="yes" />
|
||||||
<AttributeName attributename="TSK_PATH" columnName="Path" required="yes" />
|
<AttributeName attributename="null" columnName="Path" required="yes" />
|
||||||
</ArtifactName>
|
</ArtifactName>
|
||||||
</FileName>
|
</FileName>
|
||||||
|
|
||||||
@ -90,7 +90,7 @@
|
|||||||
<ArtifactName artifactname="TSK_WEB_SEARCH_QUERY" comment="Browser Keyword Search Terms">
|
<ArtifactName artifactname="TSK_WEB_SEARCH_QUERY" comment="Browser Keyword Search Terms">
|
||||||
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Last Visit Time" required="yes"/>
|
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Last Visit Time" required="yes"/>
|
||||||
<AttributeName attributename="TSK_TEXT" columnName="Term" required="yes"/>
|
<AttributeName attributename="TSK_TEXT" columnName="Term" required="yes"/>
|
||||||
<AttributeName attributename="TSK_URL" columnName="URL" required="yes"/>
|
<AttributeName attributename="TSK_DOMAIN" columnName="URL" required="yes"/>
|
||||||
</ArtifactName>
|
</ArtifactName>
|
||||||
</FileName>
|
</FileName>
|
||||||
|
|
||||||
@ -120,7 +120,7 @@
|
|||||||
<ArtifactName artifactname="TSK_WEB_SEARCH_QUERY" comment="Browser Search Terms">
|
<ArtifactName artifactname="TSK_WEB_SEARCH_QUERY" comment="Browser Search Terms">
|
||||||
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Last Visit Time" required="yes"/>
|
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Last Visit Time" required="yes"/>
|
||||||
<AttributeName attributename="TSK_TEXT" columnName="Search Term" required="yes"/>
|
<AttributeName attributename="TSK_TEXT" columnName="Search Term" required="yes"/>
|
||||||
<AttributeName attributename="TSK_URL" columnName="URL" required="yes"/>
|
<AttributeName attributename="TSK_DOMAIN" columnName="URL" required="yes"/>
|
||||||
<AttributeName attributename="null" columnName="Title" required="no"/>
|
<AttributeName attributename="null" columnName="Title" required="no"/>
|
||||||
<AttributeName attributename="null" columnName="Visit Count" required="no"/>
|
<AttributeName attributename="null" columnName="Visit Count" required="no"/>
|
||||||
</ArtifactName>
|
</ArtifactName>
|
||||||
@ -163,13 +163,13 @@
|
|||||||
|
|
||||||
<FileName filename="Chrome cookies.tsv" description="Chrome Cookies">
|
<FileName filename="Chrome cookies.tsv" description="Chrome Cookies">
|
||||||
<ArtifactName artifactname="TSK_WEB_COOKIE" comment="Chrome Cookies">
|
<ArtifactName artifactname="TSK_WEB_COOKIE" comment="Chrome Cookies">
|
||||||
<AttributeName attributename="TSK_DATETIME_START" columnName="Last Access Date" required="yes" />
|
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Last Access Date" required="yes" />
|
||||||
<AttributeName attributename="TSK_DOMAIN" columnName="Host" required="yes" />
|
<AttributeName attributename="TSK_URL" columnName="Host" required="yes" />
|
||||||
<AttributeName attributename="TSK_NAME" columnName="Name" required="yes" />
|
<AttributeName attributename="TSK_NAME" columnName="Name" required="yes" />
|
||||||
<AttributeName attributename="TSK_VALUE" columnName="Value" required="yes" />
|
<AttributeName attributename="TSK_VALUE" columnName="Value" required="yes" />
|
||||||
<AttributeName attributename="TSK_DATETIME_CREATED" columnName="Created Date" required="yes" />
|
<AttributeName attributename="TSK_DATETIME_CREATED" columnName="Created Date" required="yes" />
|
||||||
<AttributeName attributename="TSK_DATETIME_END" columnName="Expiration Date" required="yes" />
|
<AttributeName attributename="TSK_DATETIME_END" columnName="Expiration Date" required="yes" />
|
||||||
<AttributeName attributename="TSK_PATH" columnName="Path" required="yes" />
|
<AttributeName attributename="null" columnName="Path" required="no" />
|
||||||
</ArtifactName>
|
</ArtifactName>
|
||||||
</FileName>
|
</FileName>
|
||||||
|
|
||||||
@ -209,7 +209,7 @@
|
|||||||
<ArtifactName artifactname="TSK_WEB_SEARCH_QUERY" comment="Chrome Search Terms">
|
<ArtifactName artifactname="TSK_WEB_SEARCH_QUERY" comment="Chrome Search Terms">
|
||||||
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Last Visit Time" required="yes"/>
|
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Last Visit Time" required="yes"/>
|
||||||
<AttributeName attributename="TSK_TEXT" columnName="Search Term" required="yes"/>
|
<AttributeName attributename="TSK_TEXT" columnName="Search Term" required="yes"/>
|
||||||
<AttributeName attributename="TSK_URL" columnName="URL" required="yes"/>
|
<AttributeName attributename="TSK_DOMAIN" columnName="URL" required="yes"/>
|
||||||
<AttributeName attributename="null" columnName="Title" required="no"/>
|
<AttributeName attributename="null" columnName="Title" required="no"/>
|
||||||
<AttributeName attributename="null" columnName="Visit Count" required="no"/>
|
<AttributeName attributename="null" columnName="Visit Count" required="no"/>
|
||||||
</ArtifactName>
|
</ArtifactName>
|
||||||
@ -225,7 +225,7 @@
|
|||||||
</FileName>
|
</FileName>
|
||||||
|
|
||||||
<FileName filename="Edge Bookmarks.tsv" description="Edge Bookmarks">
|
<FileName filename="Edge Bookmarks.tsv" description="Edge Bookmarks">
|
||||||
<ArtifactName artifactname="TSK_WEB_BOOKMARK" comment="Chrome Bookmarks">
|
<ArtifactName artifactname="TSK_WEB_BOOKMARK" comment="Edge Bookmarks">
|
||||||
<AttributeName attributename="TSK_DATETIME_CREATED" columnName="Added Date" required="yes" />
|
<AttributeName attributename="TSK_DATETIME_CREATED" columnName="Added Date" required="yes" />
|
||||||
<AttributeName attributename="TSK_URL" columnName="URL" required="yes" />
|
<AttributeName attributename="TSK_URL" columnName="URL" required="yes" />
|
||||||
<AttributeName attributename="TSK_TITLE" columnName="Name" required="yes" />
|
<AttributeName attributename="TSK_TITLE" columnName="Name" required="yes" />
|
||||||
@ -236,13 +236,13 @@
|
|||||||
|
|
||||||
<FileName filename="Edge cookies.tsv" description="Edge Cookies">
|
<FileName filename="Edge cookies.tsv" description="Edge Cookies">
|
||||||
<ArtifactName artifactname="TSK_WEB_COOKIE" comment="Edge Cookies">
|
<ArtifactName artifactname="TSK_WEB_COOKIE" comment="Edge Cookies">
|
||||||
<AttributeName attributename="TSK_DATETIME_START" columnName="Last Access Date" required="yes" />
|
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Last Access Date" required="yes" />
|
||||||
<AttributeName attributename="TSK_DOMAIN" columnName="Host" required="yes" />
|
<AttributeName attributename="TSK_URL" columnName="Host" required="yes" />
|
||||||
<AttributeName attributename="TSK_NAME" columnName="Name" required="yes" />
|
<AttributeName attributename="TSK_NAME" columnName="Name" required="yes" />
|
||||||
<AttributeName attributename="TSK_VALUE" columnName="Value" required="yes" />
|
<AttributeName attributename="TSK_VALUE" columnName="Value" required="yes" />
|
||||||
<AttributeName attributename="TSK_DATETIME_CREATED" columnName="Created Date" required="yes" />
|
<AttributeName attributename="TSK_DATETIME_CREATED" columnName="Created Date" required="yes" />
|
||||||
<AttributeName attributename="TSK_DATETIME_END" columnName="Expiration Date" required="yes" />
|
<AttributeName attributename="TSK_DATETIME_END" columnName="Expiration Date" required="yes" />
|
||||||
<AttributeName attributename="TSK_PATH" columnName="Path" required="yes" />
|
<AttributeName attributename="null" columnName="Path" required="no" />
|
||||||
</ArtifactName>
|
</ArtifactName>
|
||||||
</FileName>
|
</FileName>
|
||||||
|
|
||||||
@ -282,7 +282,7 @@
|
|||||||
<ArtifactName artifactname="TSK_WEB_SEARCH_QUERY" comment="Chrome Search Terms">
|
<ArtifactName artifactname="TSK_WEB_SEARCH_QUERY" comment="Chrome Search Terms">
|
||||||
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Last Visit Time" required="yes"/>
|
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Last Visit Time" required="yes"/>
|
||||||
<AttributeName attributename="TSK_TEXT" columnName="Search Term" required="yes"/>
|
<AttributeName attributename="TSK_TEXT" columnName="Search Term" required="yes"/>
|
||||||
<AttributeName attributename="TSK_URL" columnName="URL" required="yes"/>
|
<AttributeName attributename="TSK_DOMAIN" columnName="URL" required="yes"/>
|
||||||
<AttributeName attributename="null" columnName="Title" required="no"/>
|
<AttributeName attributename="null" columnName="Title" required="no"/>
|
||||||
<AttributeName attributename="null" columnName="Visit Count" required="no"/>
|
<AttributeName attributename="null" columnName="Visit Count" required="no"/>
|
||||||
</ArtifactName>
|
</ArtifactName>
|
||||||
@ -318,7 +318,7 @@
|
|||||||
<FileName filename="installed apps library.tsv" description="Installed Apps (Library)">
|
<FileName filename="installed apps library.tsv" description="Installed Apps (Library)">
|
||||||
<ArtifactName artifactname="TSK_INSTALLED_PROG" comment="Installed Apps (Library)">
|
<ArtifactName artifactname="TSK_INSTALLED_PROG" comment="Installed Apps (Library)">
|
||||||
<AttributeName attributename="TSK_DATETIME" columnName="Purchase Time" required="yes"/>
|
<AttributeName attributename="TSK_DATETIME" columnName="Purchase Time" required="yes"/>
|
||||||
<AttributeName attributename="TSK_USER_NAME" columnName="Account" required="yes"/>
|
<AttributeName attributename="null" columnName="Account" required="no"/>
|
||||||
<AttributeName attributename="TSK_PROG_NAME" columnName="Doc ID" required="yes"/>
|
<AttributeName attributename="TSK_PROG_NAME" columnName="Doc ID" required="yes"/>
|
||||||
</ArtifactName>
|
</ArtifactName>
|
||||||
</FileName>
|
</FileName>
|
||||||
@ -333,7 +333,7 @@
|
|||||||
<ArtifactName artifactname="TSK_INSTALLED_PROG" comment="Installed Apps (Vending)">
|
<ArtifactName artifactname="TSK_INSTALLED_PROG" comment="Installed Apps (Vending)">
|
||||||
<AttributeName attributename="TSK_DATETIME" columnName="First Download" required="yes" />
|
<AttributeName attributename="TSK_DATETIME" columnName="First Download" required="yes" />
|
||||||
<AttributeName attributename="TSK_PROG_NAME" columnName="Package Name" required="yes" />
|
<AttributeName attributename="TSK_PROG_NAME" columnName="Package Name" required="yes" />
|
||||||
<AttributeName attributename="TSK_TITLE" columnName="Title" required="yes" />
|
<AttributeName attributename="null" columnName="Title" required="no" />
|
||||||
<AttributeName attributename="null" columnName="Install Reason" required="no" />
|
<AttributeName attributename="null" columnName="Install Reason" required="no" />
|
||||||
<AttributeName attributename="null" columnName="Auto Update?" required="no" />
|
<AttributeName attributename="null" columnName="Auto Update?" required="no" />
|
||||||
</ArtifactName>
|
</ArtifactName>
|
||||||
@ -482,8 +482,8 @@
|
|||||||
<AttributeName attributename="TSK_PHONE_NUMBER_TO" columnName="recipients" required="yes"/>
|
<AttributeName attributename="TSK_PHONE_NUMBER_TO" columnName="recipients" required="yes"/>
|
||||||
<AttributeName attributename="TSK_DIRECTION" columnName="direction" required="yes"/>
|
<AttributeName attributename="TSK_DIRECTION" columnName="direction" required="yes"/>
|
||||||
<AttributeName attributename="TSK_TEXT" columnName="content" required="yes"/>
|
<AttributeName attributename="TSK_TEXT" columnName="content" required="yes"/>
|
||||||
<AttributeName attributename="TSK_DATETIME_START" columnName="send_timestamp" required="yes" />
|
<AttributeName attributename="TSK_DATETIME" columnName="send_timestamp" required="yes" />
|
||||||
<AttributeName attributename="TSK_DATETIME_END" columnName="received_timestamp" required="yes"/>
|
<AttributeName attributename="null" columnName="received_timestamp" required="no"/>
|
||||||
<AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="number" required="yes"/>
|
<AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="number" required="yes"/>
|
||||||
<AttributeName attributename="TSK_ATTACHMENTS" columnName="name" required="yes" />
|
<AttributeName attributename="TSK_ATTACHMENTS" columnName="name" required="yes" />
|
||||||
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
|
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
|
||||||
|
@ -72,7 +72,7 @@
|
|||||||
<AttributeName attributename="null" columnName="Name Origin" required="no" />
|
<AttributeName attributename="null" columnName="Name Origin" required="no" />
|
||||||
<AttributeName attributename="null" columnName="Address" required="no" />
|
<AttributeName attributename="null" columnName="Address" required="no" />
|
||||||
<AttributeName attributename="null" columnName="Resolved Address" required="no" />
|
<AttributeName attributename="null" columnName="Resolved Address" required="no" />
|
||||||
<AttributeName attributename="TSK_DATETIME" columnName="Last Seen TIme" required="yes" />
|
<AttributeName attributename="TSK_DATETIME" columnName="Last Seen Time" required="yes" />
|
||||||
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Last Connection Time" required="yes" />
|
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Last Connection Time" required="yes" />
|
||||||
</ArtifactName>
|
</ArtifactName>
|
||||||
</FileName>
|
</FileName>
|
||||||
@ -237,8 +237,8 @@
|
|||||||
|
|
||||||
<FileName filename="KnowledgeC Bluetooth Connections.tsv" description="KnowledgeC Bluetooth Connections">
|
<FileName filename="KnowledgeC Bluetooth Connections.tsv" description="KnowledgeC Bluetooth Connections">
|
||||||
<ArtifactName artifactname="TSK_BLUETOOTH_PAIRING" comment="KnowledgeC Bluetooth Connections">
|
<ArtifactName artifactname="TSK_BLUETOOTH_PAIRING" comment="KnowledgeC Bluetooth Connections">
|
||||||
<AttributeName attributename="TSK_DATETIME_START" columnName="Start" required="yes" />
|
<AttributeName attributename="TSK_DATETIME" columnName="Start" required="yes" />
|
||||||
<AttributeName attributename="TSK_DATETIME_END" columnName="End" required="yes" />
|
<AttributeName attributename="null" columnName="End" required="no" />
|
||||||
<AttributeName attributename="TSK_MAC_ADDRESS" columnName="Bluetooth Address" required="yes" />
|
<AttributeName attributename="TSK_MAC_ADDRESS" columnName="Bluetooth Address" required="yes" />
|
||||||
<AttributeName attributename="TSK_DEVICE_NAME" columnName="Bluetooth Name" required="yes" />
|
<AttributeName attributename="TSK_DEVICE_NAME" columnName="Bluetooth Name" required="yes" />
|
||||||
<AttributeName attributename="null" columnName="Usage in Seconds" required="no" />
|
<AttributeName attributename="null" columnName="Usage in Seconds" required="no" />
|
||||||
@ -252,17 +252,15 @@
|
|||||||
</FileName>
|
</FileName>
|
||||||
|
|
||||||
<FileName filename="KnowledgeC Car Play Connections.tsv" description="KnowledgeC Car Play Connections">
|
<FileName filename="KnowledgeC Car Play Connections.tsv" description="KnowledgeC Car Play Connections">
|
||||||
<ArtifactName artifactname="TSK_DEVICE_INFO" comment="KnowledgeC Car Play Connections">
|
<ArtifactName artifactname="TSK_USER_DEVICE_EVENT" comment="KnowledgeC Car Play Connections">
|
||||||
<AttributeName attributename="TSK_DATETIME" columnName="Start" required="yes" />
|
<AttributeName attributename="TSK_DATETIME_START" columnName="Start" required="yes" />
|
||||||
<AttributeName attributename="null" columnName="End" required="no" />
|
<AttributeName attributename="TSK_DATETIME_END" columnName="End" required="yes" />
|
||||||
<AttributeName attributename="null" columnName="Car Play Connected" required="yes" />
|
<AttributeName attributename="null" columnName="Car Play Connected" required="no" />
|
||||||
<AttributeName attributename="null" columnName="Usage in Seconds" required="no" />
|
<AttributeName attributename="null" columnName="Usage in Seconds" required="no" />
|
||||||
<AttributeName attributename="null" columnName="Usage in Minutes" required="no" />
|
<AttributeName attributename="null" columnName="Usage in Minutes" required="no" />
|
||||||
<AttributeName attributename="null" columnName="Day of Week" required="no" />
|
<AttributeName attributename="null" columnName="Day of Week" required="no" />
|
||||||
<AttributeName attributename="null" columnName="GMT Offset" required="no" />
|
<AttributeName attributename="null" columnName="GMT Offset" required="no" />
|
||||||
<AttributeName attributename="null" columnName="Entry Creation" required="no" />
|
<AttributeName attributename="null" columnName="Entry Creation" required="no" />
|
||||||
<AttributeName attributename="TSK_DEVICE_ID" columnName="UUID" required="yes" />
|
|
||||||
<AttributeName attributename="null" columnName="Zobject Table ID" required="no" />
|
|
||||||
</ArtifactName>
|
</ArtifactName>
|
||||||
</FileName>
|
</FileName>
|
||||||
|
|
||||||
@ -314,9 +312,9 @@
|
|||||||
|
|
||||||
<FileName filename="KnowledgeC Application in Focus.tsv" description="KnowledgeC Application In Focus">
|
<FileName filename="KnowledgeC Application in Focus.tsv" description="KnowledgeC Application In Focus">
|
||||||
<ArtifactName artifactname="TSK_PROG_RUN" comment="KnowledgeC Application In Focus">
|
<ArtifactName artifactname="TSK_PROG_RUN" comment="KnowledgeC Application In Focus">
|
||||||
<AttributeName attributename="TSK_DATETIME_START" columnName="Start" required="no" />
|
<AttributeName attributename="TSK_DATETIME" columnName="Start" required="yes" />
|
||||||
<AttributeName attributename="TSK_DATETIME_END" columnName="End" required="no" />
|
<AttributeName attributename="null" columnName="End" required="no" />
|
||||||
<AttributeName attributename="TSK_PROG_NAME" columnName="Bundle ID" required="no" />
|
<AttributeName attributename="TSK_PROG_NAME" columnName="Bundle ID" required="yes" />
|
||||||
<AttributeName attributename="null" columnName="Usage in Seconds" required="no" />
|
<AttributeName attributename="null" columnName="Usage in Seconds" required="no" />
|
||||||
<AttributeName attributename="null" columnName="Usage in Minutes" required="no" />
|
<AttributeName attributename="null" columnName="Usage in Minutes" required="no" />
|
||||||
<AttributeName attributename="null" columnName="Day of Week" required="no" />
|
<AttributeName attributename="null" columnName="Day of Week" required="no" />
|
||||||
@ -357,7 +355,7 @@
|
|||||||
<ArtifactName artifactname="TSK_RECENT_OBJ" comment="KnowledgeC Media Playing">
|
<ArtifactName artifactname="TSK_RECENT_OBJ" comment="KnowledgeC Media Playing">
|
||||||
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Start" required="yes" />
|
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Start" required="yes" />
|
||||||
<AttributeName attributename="null" columnName="End" required="no" />
|
<AttributeName attributename="null" columnName="End" required="no" />
|
||||||
<AttributeName attributename="TSK_PROG_NAME" columnName="Bundle ID" required="yes" />
|
<AttributeName attributename="TSK_PATH" columnName="Bundle ID" required="yes" />
|
||||||
<AttributeName attributename="null" columnName="Now Playing Album" required="no" />
|
<AttributeName attributename="null" columnName="Now Playing Album" required="no" />
|
||||||
<AttributeName attributename="null" columnName="Now Playing Artists" required="no" />
|
<AttributeName attributename="null" columnName="Now Playing Artists" required="no" />
|
||||||
<AttributeName attributename="null" columnName="Playing Genre" required="no" />
|
<AttributeName attributename="null" columnName="Playing Genre" required="no" />
|
||||||
@ -377,7 +375,7 @@
|
|||||||
<ArtifactName artifactname="TSK_RECENT_OBJ" comment="KnowledgeC Notes - Activity">
|
<ArtifactName artifactname="TSK_RECENT_OBJ" comment="KnowledgeC Notes - Activity">
|
||||||
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Start" required="yes" />
|
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Start" required="yes" />
|
||||||
<AttributeName attributename="null" columnName="End" required="no" />
|
<AttributeName attributename="null" columnName="End" required="no" />
|
||||||
<AttributeName attributename="TSK_PROG_NAME" columnName="Bundle ID" required="yes" />
|
<AttributeName attributename="TSK_PATH" columnName="Bundle ID" required="yes" />
|
||||||
<AttributeName attributename="null" columnName="Activity Type" required="no" />
|
<AttributeName attributename="null" columnName="Activity Type" required="no" />
|
||||||
<AttributeName attributename="null" columnName="User Activity Required String" required="no" />
|
<AttributeName attributename="null" columnName="User Activity Required String" required="no" />
|
||||||
<AttributeName attributename="null" columnName="ID" required="no" />
|
<AttributeName attributename="null" columnName="ID" required="no" />
|
||||||
@ -495,13 +493,6 @@
|
|||||||
</ArtifactName>
|
</ArtifactName>
|
||||||
</FileName>
|
</FileName>
|
||||||
|
|
||||||
<FileName filename="Last Build.tsv" description="iOS Build">
|
|
||||||
<ArtifactName artifactname="TSK_OS_INFO" comment="iOS Build">
|
|
||||||
<AttributeName attributename="TSK_NAME" columnName="Key" required="yes" />
|
|
||||||
<AttributeName attributename="TSK_VALUE" columnName="Values" required="yes" />
|
|
||||||
</ArtifactName>
|
|
||||||
</FileName>
|
|
||||||
|
|
||||||
<FileName filename="LocationD LTE Location.tsv" description="LocationD LTE Location">
|
<FileName filename="LocationD LTE Location.tsv" description="LocationD LTE Location">
|
||||||
<ArtifactName artifactname="TSK_GPS_LAST_KNOWN_LOCATION" comment="LocationD LTE Location">
|
<ArtifactName artifactname="TSK_GPS_LAST_KNOWN_LOCATION" comment="LocationD LTE Location">
|
||||||
<AttributeName attributename="TSK_DATETIME" columnName="Timestamp" required="yes" />
|
<AttributeName attributename="TSK_DATETIME" columnName="Timestamp" required="yes" />
|
||||||
@ -524,7 +515,7 @@
|
|||||||
|
|
||||||
<FileName filename="RoutineD Vehicle Location.tsv" description="RoutineD Vehicle Location">
|
<FileName filename="RoutineD Vehicle Location.tsv" description="RoutineD Vehicle Location">
|
||||||
<ArtifactName artifactname="TSK_GPS_LAST_KNOWN_LOCATION" comment="RoutineD Vehicle Location">
|
<ArtifactName artifactname="TSK_GPS_LAST_KNOWN_LOCATION" comment="RoutineD Vehicle Location">
|
||||||
<AttributeName attributename="TSK_DATETIME" columnName="Date" required="yes" />
|
<AttributeName attributename="TSK_DATETIME" columnName="Timestamp" required="yes" />
|
||||||
<AttributeName attributename="null" columnName="Location Date" required="no" />
|
<AttributeName attributename="null" columnName="Location Date" required="no" />
|
||||||
<AttributeName attributename="null" columnName="Coordinates" required="no" />
|
<AttributeName attributename="null" columnName="Coordinates" required="no" />
|
||||||
<AttributeName attributename="null" columnName="Vehicle Identifier" required="no" />
|
<AttributeName attributename="null" columnName="Vehicle Identifier" required="no" />
|
||||||
@ -543,14 +534,12 @@
|
|||||||
|
|
||||||
<FileName filename="RoutineD Parked Vehicle Historical.tsv" description="RoutineD Parked Vehicle Historical">
|
<FileName filename="RoutineD Parked Vehicle Historical.tsv" description="RoutineD Parked Vehicle Historical">
|
||||||
<ArtifactName artifactname="TSK_GPS_LAST_KNOWN_LOCATION" comment="RoutineD Parked Vehicle Historical">
|
<ArtifactName artifactname="TSK_GPS_LAST_KNOWN_LOCATION" comment="RoutineD Parked Vehicle Historical">
|
||||||
<AttributeName attributename="TSK_DATETIME" columnName="Date" required="yes" />
|
<AttributeName attributename="TSK_DATETIME" columnName="Timestamp" required="yes" />
|
||||||
<AttributeName attributename="null" columnName="Location Date" required="no" />
|
<AttributeName attributename="null" columnName="Location Date" required="no" />
|
||||||
<AttributeName attributename="null" columnName="Coordinates" required="no" />
|
|
||||||
<AttributeName attributename="null" columnName="Location Uncertainty" required="no" />
|
<AttributeName attributename="null" columnName="Location Uncertainty" required="no" />
|
||||||
<AttributeName attributename="null" columnName="Identifier" required="no" />
|
<AttributeName attributename="null" columnName="Identifier" required="no" />
|
||||||
<AttributeName attributename="TSK_GEO_LATITUDE" columnName="Latitude" required="yes" />
|
<AttributeName attributename="TSK_GEO_LATITUDE" columnName="Latitude" required="yes" />
|
||||||
<AttributeName attributename="TSK_GEO_LONGITUDE" columnName="Longitude" required="yes" />
|
<AttributeName attributename="TSK_GEO_LONGITUDE" columnName="Longitude" required="yes" />
|
||||||
<AttributeName attributename="null" columnName="Table ID" required="no" />
|
|
||||||
</ArtifactName>
|
</ArtifactName>
|
||||||
</FileName>
|
</FileName>
|
||||||
|
|
||||||
@ -714,11 +703,12 @@
|
|||||||
</FileName>
|
</FileName>
|
||||||
|
|
||||||
<FileName filename="Powerlog Paired Device Conf.tsv" description="Powerlog Paired Device Configuration">
|
<FileName filename="Powerlog Paired Device Conf.tsv" description="Powerlog Paired Device Configuration">
|
||||||
<ArtifactName artifactname="TSK_DEVICE_INFO" comment="Powerlog Paired Device Configuration">
|
<ArtifactName artifactname="TSK_DEVICE_ATTACHED" comment="Powerlog Paired Device Configuration">
|
||||||
<AttributeName attributename="TSK_DATETIME" columnName="Timestamp" required="yes" />
|
<AttributeName attributename="TSK_DATETIME" columnName="Timestamp" required="yes" />
|
||||||
<AttributeName attributename="TSK_DEVICE_ID" columnName="Build" required="yes" />
|
<AttributeName attributename="TSK_DEVICE_ID" columnName="Build" required="yes" />
|
||||||
<AttributeName attributename="TSK_DEVICE_MAKE" columnName="Device" required="yes" />
|
<AttributeName attributename="TSK_DEVICE_MAKE" columnName="Device" required="yes" />
|
||||||
<AttributeName attributename="TSK_DEVICE_MODEL" columnName="PairedDeviceConfig Table ID" required="yes" />
|
<AttributeName attributename="TSK_DEVICE_MODEL" columnName="HW Model" required="yes" />
|
||||||
|
<AttributeName attributename="null" columnName="Pairing ID" required="no" />
|
||||||
</ArtifactName>
|
</ArtifactName>
|
||||||
</FileName>
|
</FileName>
|
||||||
|
|
||||||
@ -741,13 +731,13 @@
|
|||||||
<ArtifactName artifactname="TSK_WEB_SEARCH_QUERY" comment="null">
|
<ArtifactName artifactname="TSK_WEB_SEARCH_QUERY" comment="null">
|
||||||
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Visit Time" required="yes" />
|
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Visit Time" required="yes" />
|
||||||
<AttributeName attributename="TSK_TEXT" columnName="Search Term" required="yes" />
|
<AttributeName attributename="TSK_TEXT" columnName="Search Term" required="yes" />
|
||||||
<AttributeName attributename="TSK_URL" columnName="URL" required="yes" />
|
<AttributeName attributename="null" columnName="URL" required="yes" />
|
||||||
<AttributeName attributename="null" columnName="Visit Count" required="no" />
|
<AttributeName attributename="null" columnName="Visit Count" required="no" />
|
||||||
<AttributeName attributename="TSK_TITLE" columnName="Title" required="yes" />
|
<AttributeName attributename="null" columnName="Title" required="no" />
|
||||||
<AttributeName attributename="null" columnName="iCloud Sync" required="no" />
|
<AttributeName attributename="null" columnName="iCloud Sync" required="no" />
|
||||||
<AttributeName attributename="null" columnName="Load Successful" required="no" />
|
<AttributeName attributename="null" columnName="Load Successful" required="no" />
|
||||||
<AttributeName attributename="null" columnName="Visit ID" required="no" />
|
<AttributeName attributename="null" columnName="Visit ID" required="no" />
|
||||||
<AttributeName attributename="TSK_REFERRER" columnName="Redirect Source" required="yes" />
|
<AttributeName attributename="null" columnName="Redirect Source" required="no" />
|
||||||
<AttributeName attributename="null" columnName="Redirect Destination" required="no" />
|
<AttributeName attributename="null" columnName="Redirect Destination" required="no" />
|
||||||
<AttributeName attributename="null" columnName="History Item ID" required="no" />
|
<AttributeName attributename="null" columnName="History Item ID" required="no" />
|
||||||
</ArtifactName>
|
</ArtifactName>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
*
|
*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2013-2014 Basis Technology Corp.
|
* Copyright 2013-2021 Basis Technology Corp.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.report;
|
|||||||
import org.sleuthkit.autopsy.report.infrastructure.ReportGenerator;
|
import org.sleuthkit.autopsy.report.infrastructure.ReportGenerator;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
@ -37,7 +39,7 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
|||||||
public final class ReportBranding implements ReportBrandingProviderI {
|
public final class ReportBranding implements ReportBrandingProviderI {
|
||||||
|
|
||||||
//property names
|
//property names
|
||||||
public static final String AGENCY_LOGO_PATH_PROP = "AgencyLogoPath"; //NON-NLS
|
private static final String AGENCY_LOGO_PATH_PROP = "AgencyLogoPath"; //NON-NLS
|
||||||
private static final String REPORT_TITLE_PROP = "ReportTitle"; //NON-NLS
|
private static final String REPORT_TITLE_PROP = "ReportTitle"; //NON-NLS
|
||||||
private static final String REPORT_FOOTER_PROP = "ReportFooter"; //NON-NLS
|
private static final String REPORT_FOOTER_PROP = "ReportFooter"; //NON-NLS
|
||||||
//default settings
|
//default settings
|
||||||
@ -46,8 +48,9 @@ public final class ReportBranding implements ReportBrandingProviderI {
|
|||||||
.getMessage(ReportBranding.class, "ReportBranding.defaultReportTitle.text");
|
.getMessage(ReportBranding.class, "ReportBranding.defaultReportTitle.text");
|
||||||
private static final String DEFAULT_REPORT_FOOTER = NbBundle
|
private static final String DEFAULT_REPORT_FOOTER = NbBundle
|
||||||
.getMessage(ReportBranding.class, "ReportBranding.defaultReportFooter.text");
|
.getMessage(ReportBranding.class, "ReportBranding.defaultReportFooter.text");
|
||||||
private String reportsBrandingDir; //dir with extracted reports branding resources
|
private final String reportsBrandingDir; //dir with extracted reports branding resources
|
||||||
public static final String MODULE_NAME = ReportBranding.class.getSimpleName();
|
private final Path userConfigDir = Paths.get(PlatformUtil.getUserDirectory().getAbsolutePath());
|
||||||
|
private static final String MODULE_NAME = ReportBranding.class.getSimpleName();
|
||||||
private static final Logger logger = Logger.getLogger(ReportBranding.class.getName());
|
private static final Logger logger = Logger.getLogger(ReportBranding.class.getName());
|
||||||
|
|
||||||
// this is static so that it can be set by another object
|
// this is static so that it can be set by another object
|
||||||
@ -109,38 +112,73 @@ public final class ReportBranding implements ReportBrandingProviderI {
|
|||||||
generatorLogoPath = path;
|
generatorLogoPath = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read logo path from preferences file. Reverses the path relativization performed
|
||||||
|
* in setAgencyLogoPath(). If the stored path starts with either “/” or drive letter,
|
||||||
|
* it is a full path, and is returned to the caller. Otherwise, append current user
|
||||||
|
* directory to the saved relative path. See JIRA-7348.
|
||||||
|
*
|
||||||
|
* @return Full path to the logo file.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getAgencyLogoPath() {
|
public String getAgencyLogoPath() {
|
||||||
String curPath = null;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The agency logo code uses these properties to persist changes in the
|
* The agency logo code uses these properties to persist changes in the
|
||||||
* logo (within the same process). This is different from the generator
|
* logo (within the same process). This is different from the generator
|
||||||
* logo that uses a static variable.
|
* logo that uses a static variable.
|
||||||
*/
|
*/
|
||||||
curPath = ModuleSettings.getConfigSetting(MODULE_NAME, AGENCY_LOGO_PATH_PROP);
|
String curPath = ModuleSettings.getConfigSetting(MODULE_NAME, AGENCY_LOGO_PATH_PROP);
|
||||||
|
|
||||||
|
|
||||||
//if has been set, validate it's correct, if not set, return null
|
//if has been set, validate it's correct, if not set, return null
|
||||||
if (curPath != null && new File(curPath).canRead() == false) {
|
if (curPath != null && !curPath.isEmpty()) {
|
||||||
|
|
||||||
|
// check if the path is an absolute path (starts with either drive letter or "/")
|
||||||
|
Path driveLetterOrNetwork = Paths.get(curPath).getRoot();
|
||||||
|
if (driveLetterOrNetwork != null) {
|
||||||
|
// absolute path
|
||||||
|
return curPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Path is a relative path. Reverse path relativization performed in setAgencyLogoPath()
|
||||||
|
Path absolutePath = userConfigDir.resolve(curPath);
|
||||||
|
curPath = absolutePath.toString();
|
||||||
|
if (new File(curPath).canRead() == false) {
|
||||||
//use default
|
//use default
|
||||||
logger.log(Level.INFO, "Custom report branding for agency logo is not valid: " + curPath); //NON-NLS
|
logger.log(Level.INFO, "Custom report branding for agency logo is not valid: {0}", curPath); //NON-NLS
|
||||||
curPath = null;
|
curPath = null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return curPath;
|
return curPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save logo path. If the path is inside user directory (e.g.
|
||||||
|
* "C:\Users\USER_NAME\AppData\Roaming\autopsy"), trim that off and save it
|
||||||
|
* as a relative path (i.e it will not start with a “/” or drive letter). Otherwise,
|
||||||
|
* full path is saved. See JIRA-7348.
|
||||||
|
*
|
||||||
|
* @param fullPath Full path to the logo file.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setAgencyLogoPath(String path) {
|
public void setAgencyLogoPath(String fullPath) {
|
||||||
|
|
||||||
|
Path relativePath = Paths.get(fullPath);
|
||||||
|
// check if the path is within user directory
|
||||||
|
if (Paths.get(fullPath).startsWith(userConfigDir)) {
|
||||||
|
// relativize the path
|
||||||
|
relativePath = userConfigDir.relativize(relativePath);
|
||||||
|
}
|
||||||
// Use properties to persist the logo to use.
|
// Use properties to persist the logo to use.
|
||||||
// Should use static variable instead
|
ModuleSettings.setConfigSetting(MODULE_NAME, AGENCY_LOGO_PATH_PROP, relativePath.toString());
|
||||||
ModuleSettings.setConfigSetting(MODULE_NAME, AGENCY_LOGO_PATH_PROP, path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getReportTitle() {
|
public String getReportTitle() {
|
||||||
String curTitle = null;
|
|
||||||
|
|
||||||
curTitle = ModuleSettings.getConfigSetting(MODULE_NAME, REPORT_TITLE_PROP);
|
String curTitle = ModuleSettings.getConfigSetting(MODULE_NAME, REPORT_TITLE_PROP);
|
||||||
if (curTitle == null || curTitle.isEmpty()) {
|
if (curTitle == null || curTitle.isEmpty()) {
|
||||||
//use default
|
//use default
|
||||||
logger.log(Level.INFO, "Using default report branding for report title"); //NON-NLS
|
logger.log(Level.INFO, "Using default report branding for report title"); //NON-NLS
|
||||||
@ -158,9 +196,8 @@ public final class ReportBranding implements ReportBrandingProviderI {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getReportFooter() {
|
public String getReportFooter() {
|
||||||
String curFooter = null;
|
|
||||||
|
|
||||||
curFooter = ModuleSettings.getConfigSetting(MODULE_NAME, REPORT_FOOTER_PROP);
|
String curFooter = ModuleSettings.getConfigSetting(MODULE_NAME, REPORT_FOOTER_PROP);
|
||||||
if (curFooter == null) {
|
if (curFooter == null) {
|
||||||
//use default
|
//use default
|
||||||
logger.log(Level.INFO, "Using default report branding for report footer"); //NON-NLS
|
logger.log(Level.INFO, "Using default report branding for report footer"); //NON-NLS
|
||||||
|
@ -49,19 +49,19 @@ public class TimeLineModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get instance of the controller for the current case
|
* Get instance of the controller for the current case.
|
||||||
|
* The controller instance is initialized from a case open event.
|
||||||
*
|
*
|
||||||
* @return the controller for the current case.
|
* @return the controller for the current case.
|
||||||
*
|
*
|
||||||
* @throws NoCurrentCaseException If there is no case open.
|
|
||||||
* @throws TskCoreException If there was a problem accessing the case
|
* @throws TskCoreException If there was a problem accessing the case
|
||||||
* database.
|
* database.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public static TimeLineController getController() throws NoCurrentCaseException, TskCoreException {
|
public static TimeLineController getController() throws TskCoreException {
|
||||||
synchronized (controllerLock) {
|
synchronized (controllerLock) {
|
||||||
if (controller == null) {
|
if (controller == null) {
|
||||||
controller = new TimeLineController(Case.getCurrentCaseThrows());
|
throw new TskCoreException("Timeline controller not initialized");
|
||||||
}
|
}
|
||||||
return controller;
|
return controller;
|
||||||
}
|
}
|
||||||
@ -100,13 +100,22 @@ public class TimeLineModule {
|
|||||||
}
|
}
|
||||||
controller = null;
|
controller = null;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Case is opening - create the controller now
|
||||||
|
synchronized (controllerLock) {
|
||||||
|
try {
|
||||||
|
controller = new TimeLineController(Case.getCurrentCaseThrows());
|
||||||
|
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Error creating Timeline controller", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
getController().handleCaseEvent(evt);
|
getController().handleCaseEvent(evt);
|
||||||
} catch (NoCurrentCaseException ignored) {
|
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.SEVERE, "Error handling application event", ex);
|
// The call to getController() will only fail due to case closing, so do
|
||||||
|
// not record the error.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,12 +130,9 @@ public class TimeLineModule {
|
|||||||
public void propertyChange(PropertyChangeEvent evt) {
|
public void propertyChange(PropertyChangeEvent evt) {
|
||||||
try {
|
try {
|
||||||
getController().handleIngestModuleEvent(evt);
|
getController().handleIngestModuleEvent(evt);
|
||||||
} catch (NoCurrentCaseException ex) {
|
|
||||||
// ignore
|
|
||||||
return;
|
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
MessageNotifyUtil.Message.error("Error creating timeline controller.");
|
// The call to getController() will only fail due to case closing, so do
|
||||||
logger.log(Level.SEVERE, "Error creating timeline controller", ex);
|
// not record the error.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,77 +11,28 @@
|
|||||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
|
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,2,-74,0,0,3,-35"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
|
||||||
<Layout>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||||
<DimensionLayout dim="0">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Component id="nodeStatusScrollPane" max="32767" attributes="0"/>
|
|
||||||
<Group type="102" attributes="0">
|
|
||||||
<Component id="nodeStatusTableTitle" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<Component id="refreshButton" linkSize="1" min="-2" pref="100" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace pref="576" max="32767" attributes="0"/>
|
|
||||||
<Component id="healthMonitorButton" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="clusterMetricsButton" linkSize="1" min="-2" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
<DimensionLayout dim="1">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" alignment="1" attributes="0">
|
|
||||||
<EmptySpace min="-2" pref="40" max="-2" attributes="0"/>
|
|
||||||
<Component id="nodeStatusTableTitle" min="-2" pref="23" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
|
||||||
<Component id="nodeStatusScrollPane" min="-2" pref="215" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="-2" pref="382" max="-2" attributes="0"/>
|
|
||||||
<Group type="103" groupAlignment="3" attributes="0">
|
|
||||||
<Component id="refreshButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="clusterMetricsButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="healthMonitorButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
</Layout>
|
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Component class="javax.swing.JButton" name="refreshButton">
|
<Container class="javax.swing.JScrollPane" name="mainScrollPane">
|
||||||
<Properties>
|
<AuxValues>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AinStatusDashboard.refreshButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||||
</Property>
|
</AuxValues>
|
||||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Constraints>
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AinStatusDashboard.refreshButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||||
</Property>
|
<BorderConstraints direction="Center"/>
|
||||||
</Properties>
|
</Constraint>
|
||||||
<Events>
|
</Constraints>
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="refreshButtonActionPerformed"/>
|
|
||||||
</Events>
|
|
||||||
</Component>
|
|
||||||
<Component class="javax.swing.JButton" name="clusterMetricsButton">
|
|
||||||
<Properties>
|
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AinStatusDashboard.clusterMetricsButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
|
||||||
</Property>
|
|
||||||
</Properties>
|
|
||||||
<Events>
|
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="clusterMetricsButtonActionPerformed"/>
|
|
||||||
</Events>
|
|
||||||
</Component>
|
|
||||||
<Container class="javax.swing.JScrollPane" name="nodeStatusScrollPane">
|
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||||
</Container>
|
<SubComponents>
|
||||||
|
<Container class="javax.swing.JPanel" name="mainPanel">
|
||||||
|
|
||||||
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||||
|
<SubComponents>
|
||||||
<Component class="javax.swing.JLabel" name="nodeStatusTableTitle">
|
<Component class="javax.swing.JLabel" name="nodeStatusTableTitle">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
|
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
|
||||||
@ -93,18 +44,62 @@
|
|||||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AinStatusDashboard.nodeStatusTableTitle.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AinStatusDashboard.nodeStatusTableTitle.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="10" insetsLeft="10" insetsBottom="5" insetsRight="10" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
<Container class="javax.swing.JPanel" name="buttonPanel">
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="10" insetsLeft="10" insetsBottom="10" insetsRight="10" anchor="10" weightX="1.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
|
||||||
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||||
|
<SubComponents>
|
||||||
|
<Component class="javax.swing.JButton" name="refreshButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AinStatusDashboard.refreshButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AinStatusDashboard.refreshButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[133, 23]"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="refreshButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JButton" name="clusterMetricsButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AinStatusDashboard.clusterMetricsButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="clusterMetricsButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="3" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JButton" name="healthMonitorButton">
|
<Component class="javax.swing.JButton" name="healthMonitorButton">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AinStatusDashboard.healthMonitorButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AinStatusDashboard.healthMonitorButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
|
||||||
<Dimension value="[133, 23]"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
|
||||||
<Dimension value="[133, 23]"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
<Dimension value="[133, 23]"/>
|
<Dimension value="[133, 23]"/>
|
||||||
</Property>
|
</Property>
|
||||||
@ -112,6 +107,32 @@
|
|||||||
<Events>
|
<Events>
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="healthMonitorButtonActionPerformed"/>
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="healthMonitorButtonActionPerformed"/>
|
||||||
</Events>
|
</Events>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="2" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.Box$Filler" name="filler1">
|
||||||
|
<Properties>
|
||||||
|
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[32767, 0]"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.HorizontalGlue"/>
|
||||||
|
</AuxValues>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
</Component>
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
|
</SubComponents>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2018 Basis Technology Corp.
|
* Copyright 2018-2021 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.experimental.autoingest;
|
|||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
import java.awt.Cursor;
|
import java.awt.Cursor;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
|
import java.awt.GridBagConstraints;
|
||||||
|
import java.awt.Insets;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
@ -34,6 +36,8 @@ import org.sleuthkit.autopsy.healthmonitor.HealthMonitorDashboard;
|
|||||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||||
final class AinStatusDashboard extends javax.swing.JPanel implements Observer {
|
final class AinStatusDashboard extends javax.swing.JPanel implements Observer {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private final AutoIngestMonitor autoIngestMonitor;
|
private final AutoIngestMonitor autoIngestMonitor;
|
||||||
private final AinStatusPanel nodesPanel;
|
private final AinStatusPanel nodesPanel;
|
||||||
private final static String AIN_REFRESH_THREAD_NAME = "AID-refresh-jobs-%d";
|
private final static String AIN_REFRESH_THREAD_NAME = "AID-refresh-jobs-%d";
|
||||||
@ -50,9 +54,17 @@ final class AinStatusDashboard extends javax.swing.JPanel implements Observer {
|
|||||||
scheduledRefreshThreadPoolExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat(AIN_REFRESH_THREAD_NAME).build());
|
scheduledRefreshThreadPoolExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat(AIN_REFRESH_THREAD_NAME).build());
|
||||||
autoIngestMonitor = monitor;
|
autoIngestMonitor = monitor;
|
||||||
nodesPanel = new AinStatusPanel();
|
nodesPanel = new AinStatusPanel();
|
||||||
nodesPanel.setSize(nodesPanel.getSize());
|
GridBagConstraints gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
nodeStatusScrollPane.add(nodesPanel);
|
gridBagConstraints.gridx = 0;
|
||||||
nodeStatusScrollPane.setViewportView(nodesPanel);
|
gridBagConstraints.gridy = 1;
|
||||||
|
gridBagConstraints.fill = GridBagConstraints.BOTH;
|
||||||
|
gridBagConstraints.weightx = 1;
|
||||||
|
gridBagConstraints.weighty = 1;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
|
gridBagConstraints.insets = new Insets(0, 10, 0, 10);
|
||||||
|
mainPanel.add(nodesPanel, gridBagConstraints);
|
||||||
|
|
||||||
|
|
||||||
refreshTables();
|
refreshTables();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,20 +91,45 @@ final class AinStatusDashboard extends javax.swing.JPanel implements Observer {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
|
java.awt.GridBagConstraints gridBagConstraints;
|
||||||
|
|
||||||
|
javax.swing.JScrollPane mainScrollPane = new javax.swing.JScrollPane();
|
||||||
|
mainPanel = new javax.swing.JPanel();
|
||||||
|
nodeStatusTableTitle = new javax.swing.JLabel();
|
||||||
|
buttonPanel = new javax.swing.JPanel();
|
||||||
refreshButton = new javax.swing.JButton();
|
refreshButton = new javax.swing.JButton();
|
||||||
clusterMetricsButton = new javax.swing.JButton();
|
clusterMetricsButton = new javax.swing.JButton();
|
||||||
nodeStatusScrollPane = new javax.swing.JScrollPane();
|
|
||||||
nodeStatusTableTitle = new javax.swing.JLabel();
|
|
||||||
healthMonitorButton = new javax.swing.JButton();
|
healthMonitorButton = new javax.swing.JButton();
|
||||||
|
filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0));
|
||||||
|
|
||||||
|
setLayout(new java.awt.BorderLayout());
|
||||||
|
|
||||||
|
mainPanel.setLayout(new java.awt.GridBagLayout());
|
||||||
|
|
||||||
|
nodeStatusTableTitle.setFont(nodeStatusTableTitle.getFont().deriveFont(nodeStatusTableTitle.getFont().getSize()+3f));
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(nodeStatusTableTitle, org.openide.util.NbBundle.getMessage(AinStatusDashboard.class, "AinStatusDashboard.nodeStatusTableTitle.text")); // NOI18N
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(10, 10, 5, 10);
|
||||||
|
mainPanel.add(nodeStatusTableTitle, gridBagConstraints);
|
||||||
|
|
||||||
|
buttonPanel.setLayout(new java.awt.GridBagLayout());
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(refreshButton, org.openide.util.NbBundle.getMessage(AinStatusDashboard.class, "AinStatusDashboard.refreshButton.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(refreshButton, org.openide.util.NbBundle.getMessage(AinStatusDashboard.class, "AinStatusDashboard.refreshButton.text")); // NOI18N
|
||||||
refreshButton.setToolTipText(org.openide.util.NbBundle.getMessage(AinStatusDashboard.class, "AinStatusDashboard.refreshButton.toolTipText")); // NOI18N
|
refreshButton.setToolTipText(org.openide.util.NbBundle.getMessage(AinStatusDashboard.class, "AinStatusDashboard.refreshButton.toolTipText")); // NOI18N
|
||||||
|
refreshButton.setPreferredSize(new java.awt.Dimension(133, 23));
|
||||||
refreshButton.addActionListener(new java.awt.event.ActionListener() {
|
refreshButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
refreshButtonActionPerformed(evt);
|
refreshButtonActionPerformed(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
|
buttonPanel.add(refreshButton, gridBagConstraints);
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(clusterMetricsButton, org.openide.util.NbBundle.getMessage(AinStatusDashboard.class, "AinStatusDashboard.clusterMetricsButton.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(clusterMetricsButton, org.openide.util.NbBundle.getMessage(AinStatusDashboard.class, "AinStatusDashboard.clusterMetricsButton.text")); // NOI18N
|
||||||
clusterMetricsButton.addActionListener(new java.awt.event.ActionListener() {
|
clusterMetricsButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
@ -100,56 +137,42 @@ final class AinStatusDashboard extends javax.swing.JPanel implements Observer {
|
|||||||
clusterMetricsButtonActionPerformed(evt);
|
clusterMetricsButtonActionPerformed(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
nodeStatusTableTitle.setFont(nodeStatusTableTitle.getFont().deriveFont(nodeStatusTableTitle.getFont().getSize()+3f));
|
gridBagConstraints.gridx = 3;
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(nodeStatusTableTitle, org.openide.util.NbBundle.getMessage(AinStatusDashboard.class, "AinStatusDashboard.nodeStatusTableTitle.text")); // NOI18N
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
|
buttonPanel.add(clusterMetricsButton, gridBagConstraints);
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(healthMonitorButton, org.openide.util.NbBundle.getMessage(AinStatusDashboard.class, "AinStatusDashboard.healthMonitorButton.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(healthMonitorButton, org.openide.util.NbBundle.getMessage(AinStatusDashboard.class, "AinStatusDashboard.healthMonitorButton.text")); // NOI18N
|
||||||
healthMonitorButton.setMaximumSize(new java.awt.Dimension(133, 23));
|
|
||||||
healthMonitorButton.setMinimumSize(new java.awt.Dimension(133, 23));
|
|
||||||
healthMonitorButton.setPreferredSize(new java.awt.Dimension(133, 23));
|
healthMonitorButton.setPreferredSize(new java.awt.Dimension(133, 23));
|
||||||
healthMonitorButton.addActionListener(new java.awt.event.ActionListener() {
|
healthMonitorButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
healthMonitorButtonActionPerformed(evt);
|
healthMonitorButtonActionPerformed(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 2;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
|
buttonPanel.add(healthMonitorButton, gridBagConstraints);
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 1;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||||
|
gridBagConstraints.weightx = 1.0;
|
||||||
|
buttonPanel.add(filler1, gridBagConstraints);
|
||||||
|
|
||||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
this.setLayout(layout);
|
gridBagConstraints.gridx = 0;
|
||||||
layout.setHorizontalGroup(
|
gridBagConstraints.gridy = 2;
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||||
.addGroup(layout.createSequentialGroup()
|
gridBagConstraints.weightx = 1.0;
|
||||||
.addContainerGap()
|
gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
mainPanel.add(buttonPanel, gridBagConstraints);
|
||||||
.addComponent(nodeStatusScrollPane)
|
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addComponent(nodeStatusTableTitle)
|
|
||||||
.addGap(0, 0, Short.MAX_VALUE))
|
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addComponent(refreshButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 576, Short.MAX_VALUE)
|
|
||||||
.addComponent(healthMonitorButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(clusterMetricsButton)))
|
|
||||||
.addContainerGap())
|
|
||||||
);
|
|
||||||
|
|
||||||
layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {clusterMetricsButton, refreshButton});
|
mainScrollPane.setViewportView(mainPanel);
|
||||||
|
|
||||||
layout.setVerticalGroup(
|
add(mainScrollPane, java.awt.BorderLayout.CENTER);
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
|
||||||
.addGap(40, 40, 40)
|
|
||||||
.addComponent(nodeStatusTableTitle, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addGap(0, 0, 0)
|
|
||||||
.addComponent(nodeStatusScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addGap(382, 382, 382)
|
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
|
||||||
.addComponent(refreshButton)
|
|
||||||
.addComponent(clusterMetricsButton)
|
|
||||||
.addComponent(healthMonitorButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
|
||||||
.addContainerGap())
|
|
||||||
);
|
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
private void refreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshButtonActionPerformed
|
private void refreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshButtonActionPerformed
|
||||||
@ -172,9 +195,11 @@ final class AinStatusDashboard extends javax.swing.JPanel implements Observer {
|
|||||||
|
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
|
private javax.swing.JPanel buttonPanel;
|
||||||
private javax.swing.JButton clusterMetricsButton;
|
private javax.swing.JButton clusterMetricsButton;
|
||||||
|
private javax.swing.Box.Filler filler1;
|
||||||
private javax.swing.JButton healthMonitorButton;
|
private javax.swing.JButton healthMonitorButton;
|
||||||
private javax.swing.JScrollPane nodeStatusScrollPane;
|
private javax.swing.JPanel mainPanel;
|
||||||
private javax.swing.JLabel nodeStatusTableTitle;
|
private javax.swing.JLabel nodeStatusTableTitle;
|
||||||
private javax.swing.JButton refreshButton;
|
private javax.swing.JButton refreshButton;
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2018 Basis Technology Corp.
|
* Copyright 2018-2021 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.experimental.autoingest;
|
package org.sleuthkit.autopsy.experimental.autoingest;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
@ -73,7 +74,8 @@ final class AinStatusDashboardTopComponent extends TopComponent {
|
|||||||
AinStatusDashboard nodeTab = new AinStatusDashboard(monitor);
|
AinStatusDashboard nodeTab = new AinStatusDashboard(monitor);
|
||||||
nodeTab.startUp();
|
nodeTab.startUp();
|
||||||
nodeTab.setSize(nodeTab.getPreferredSize());
|
nodeTab.setSize(nodeTab.getPreferredSize());
|
||||||
tc.add(nodeTab);
|
tc.setLayout(new BorderLayout());
|
||||||
|
tc.add(nodeTab, BorderLayout.CENTER);
|
||||||
tc.open();
|
tc.open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,61 +22,20 @@
|
|||||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
|
||||||
<Layout>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||||
<DimensionLayout dim="0">
|
<SubComponents>
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Container class="javax.swing.JScrollPane" name="mainScrollPane">
|
||||||
<Group type="102" alignment="1" attributes="0">
|
<Constraints>
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||||
<Group type="103" groupAlignment="1" attributes="0">
|
<BorderConstraints direction="Center"/>
|
||||||
<Component id="pendingScrollPane" max="32767" attributes="0"/>
|
</Constraint>
|
||||||
<Component id="runningScrollPane" alignment="0" max="32767" attributes="0"/>
|
</Constraints>
|
||||||
<Component id="completedScrollPane" alignment="0" max="32767" attributes="0"/>
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||||
<Component id="lbServicesStatus" min="-2" max="-2" attributes="0"/>
|
<SubComponents>
|
||||||
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
|
<Container class="javax.swing.JPanel" name="mainPanel">
|
||||||
<Component id="tbServicesStatusMessage" pref="861" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<Group type="103" groupAlignment="1" attributes="0">
|
|
||||||
<Component id="lbPending" alignment="0" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="lbCompleted" alignment="0" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="lbRunning" alignment="0" min="-2" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
<Component id="refreshButton" alignment="0" min="-2" pref="100" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
<DimensionLayout dim="1">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" alignment="1" attributes="0">
|
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
|
||||||
<Group type="103" groupAlignment="3" attributes="0">
|
|
||||||
<Component id="lbServicesStatus" alignment="3" min="-2" pref="23" max="-2" attributes="0"/>
|
|
||||||
<Component id="tbServicesStatusMessage" alignment="3" min="-2" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="lbPending" min="-2" pref="23" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="-2" pref="1" max="-2" attributes="0"/>
|
|
||||||
<Component id="pendingScrollPane" max="32767" attributes="0"/>
|
|
||||||
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="lbRunning" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="-2" pref="1" max="-2" attributes="0"/>
|
|
||||||
<Component id="runningScrollPane" pref="133" max="32767" attributes="0"/>
|
|
||||||
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="lbCompleted" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="completedScrollPane" pref="179" max="32767" attributes="0"/>
|
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="refreshButton" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
</Layout>
|
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Container class="javax.swing.JScrollPane" name="pendingScrollPane">
|
<Container class="javax.swing.JScrollPane" name="pendingScrollPane">
|
||||||
<Properties>
|
<Properties>
|
||||||
@ -84,26 +43,51 @@
|
|||||||
<Property name="verticalScrollBarPolicy" type="int" value="21"/>
|
<Property name="verticalScrollBarPolicy" type="int" value="21"/>
|
||||||
<Property name="opaque" type="boolean" value="false"/>
|
<Property name="opaque" type="boolean" value="false"/>
|
||||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
<Dimension value="[2, 215]"/>
|
<Dimension value="[2, 150]"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<AuxValues>
|
<AuxValues>
|
||||||
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
|
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="3" gridWidth="2" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="10" insetsBottom="10" insetsRight="10" anchor="18" weightX="1.0" weightY="1.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||||
</Container>
|
</Container>
|
||||||
<Container class="javax.swing.JScrollPane" name="runningScrollPane">
|
<Container class="javax.swing.JScrollPane" name="runningScrollPane">
|
||||||
|
<Properties>
|
||||||
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[2, 150]"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
<AuxValues>
|
<AuxValues>
|
||||||
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
|
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="5" gridWidth="2" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="10" insetsBottom="10" insetsRight="10" anchor="18" weightX="1.0" weightY="1.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||||
</Container>
|
</Container>
|
||||||
<Container class="javax.swing.JScrollPane" name="completedScrollPane">
|
<Container class="javax.swing.JScrollPane" name="completedScrollPane">
|
||||||
|
<Properties>
|
||||||
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[2, 150]"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
<AuxValues>
|
<AuxValues>
|
||||||
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
|
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="7" gridWidth="5" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="10" insetsBottom="10" insetsRight="10" anchor="18" weightX="1.0" weightY="1.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||||
</Container>
|
</Container>
|
||||||
@ -118,6 +102,11 @@
|
|||||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.lbPending.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.lbPending.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="2" gridWidth="2" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="10" insetsLeft="10" insetsBottom="5" insetsRight="10" anchor="18" weightX="0.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JLabel" name="lbRunning">
|
<Component class="javax.swing.JLabel" name="lbRunning">
|
||||||
<Properties>
|
<Properties>
|
||||||
@ -130,6 +119,11 @@
|
|||||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.lbRunning.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.lbRunning.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="4" gridWidth="2" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="10" insetsBottom="5" insetsRight="10" anchor="18" weightX="0.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JLabel" name="lbCompleted">
|
<Component class="javax.swing.JLabel" name="lbCompleted">
|
||||||
<Properties>
|
<Properties>
|
||||||
@ -142,6 +136,11 @@
|
|||||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.lbCompleted.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.lbCompleted.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="6" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="10" insetsBottom="5" insetsRight="10" anchor="18" weightX="0.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JButton" name="refreshButton">
|
<Component class="javax.swing.JButton" name="refreshButton">
|
||||||
<Properties>
|
<Properties>
|
||||||
@ -155,6 +154,11 @@
|
|||||||
<Events>
|
<Events>
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="refreshButtonActionPerformed"/>
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="refreshButtonActionPerformed"/>
|
||||||
</Events>
|
</Events>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="8" gridWidth="2" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="10" insetsBottom="10" insetsRight="10" anchor="18" weightX="0.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JLabel" name="lbServicesStatus">
|
<Component class="javax.swing.JLabel" name="lbServicesStatus">
|
||||||
<Properties>
|
<Properties>
|
||||||
@ -167,6 +171,11 @@
|
|||||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.lbServicesStatus.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.lbServicesStatus.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="10" insetsLeft="10" insetsBottom="0" insetsRight="10" anchor="18" weightX="0.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JTextField" name="tbServicesStatusMessage">
|
<Component class="javax.swing.JTextField" name="tbServicesStatusMessage">
|
||||||
<Properties>
|
<Properties>
|
||||||
@ -183,6 +192,15 @@
|
|||||||
<Border info="null"/>
|
<Border info="null"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="10" insetsLeft="0" insetsBottom="0" insetsRight="10" anchor="18" weightX="1.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
</Component>
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
|
</SubComponents>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -348,8 +348,11 @@ final class AutoIngestDashboard extends JPanel implements Observer {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
|
java.awt.GridBagConstraints gridBagConstraints;
|
||||||
|
|
||||||
jButton1 = new javax.swing.JButton();
|
jButton1 = new javax.swing.JButton();
|
||||||
|
mainScrollPane = new javax.swing.JScrollPane();
|
||||||
|
mainPanel = new javax.swing.JPanel();
|
||||||
pendingScrollPane = new javax.swing.JScrollPane();
|
pendingScrollPane = new javax.swing.JScrollPane();
|
||||||
runningScrollPane = new javax.swing.JScrollPane();
|
runningScrollPane = new javax.swing.JScrollPane();
|
||||||
completedScrollPane = new javax.swing.JScrollPane();
|
completedScrollPane = new javax.swing.JScrollPane();
|
||||||
@ -362,19 +365,77 @@ final class AutoIngestDashboard extends JPanel implements Observer {
|
|||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.jButton1.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.jButton1.text")); // NOI18N
|
||||||
|
|
||||||
|
setLayout(new java.awt.BorderLayout());
|
||||||
|
|
||||||
|
mainPanel.setLayout(new java.awt.GridBagLayout());
|
||||||
|
|
||||||
pendingScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
pendingScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||||
pendingScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
|
pendingScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
|
||||||
pendingScrollPane.setOpaque(false);
|
pendingScrollPane.setOpaque(false);
|
||||||
pendingScrollPane.setPreferredSize(new java.awt.Dimension(2, 215));
|
pendingScrollPane.setPreferredSize(new java.awt.Dimension(2, 150));
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 3;
|
||||||
|
gridBagConstraints.gridwidth = 2;
|
||||||
|
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
|
gridBagConstraints.weightx = 1.0;
|
||||||
|
gridBagConstraints.weighty = 1.0;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(0, 10, 10, 10);
|
||||||
|
mainPanel.add(pendingScrollPane, gridBagConstraints);
|
||||||
|
|
||||||
|
runningScrollPane.setPreferredSize(new java.awt.Dimension(2, 150));
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 5;
|
||||||
|
gridBagConstraints.gridwidth = 2;
|
||||||
|
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
|
gridBagConstraints.weightx = 1.0;
|
||||||
|
gridBagConstraints.weighty = 1.0;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(0, 10, 10, 10);
|
||||||
|
mainPanel.add(runningScrollPane, gridBagConstraints);
|
||||||
|
|
||||||
|
completedScrollPane.setPreferredSize(new java.awt.Dimension(2, 150));
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 7;
|
||||||
|
gridBagConstraints.gridwidth = 5;
|
||||||
|
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
|
gridBagConstraints.weightx = 1.0;
|
||||||
|
gridBagConstraints.weighty = 1.0;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(0, 10, 10, 10);
|
||||||
|
mainPanel.add(completedScrollPane, gridBagConstraints);
|
||||||
|
|
||||||
lbPending.setFont(lbPending.getFont().deriveFont(lbPending.getFont().getSize()+3f));
|
lbPending.setFont(lbPending.getFont().deriveFont(lbPending.getFont().getSize()+3f));
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(lbPending, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.lbPending.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(lbPending, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.lbPending.text")); // NOI18N
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 2;
|
||||||
|
gridBagConstraints.gridwidth = 2;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(10, 10, 5, 10);
|
||||||
|
mainPanel.add(lbPending, gridBagConstraints);
|
||||||
|
|
||||||
lbRunning.setFont(lbRunning.getFont().deriveFont(lbRunning.getFont().getSize()+3f));
|
lbRunning.setFont(lbRunning.getFont().deriveFont(lbRunning.getFont().getSize()+3f));
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(lbRunning, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.lbRunning.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(lbRunning, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.lbRunning.text")); // NOI18N
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 4;
|
||||||
|
gridBagConstraints.gridwidth = 2;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(0, 10, 5, 10);
|
||||||
|
mainPanel.add(lbRunning, gridBagConstraints);
|
||||||
|
|
||||||
lbCompleted.setFont(lbCompleted.getFont().deriveFont(lbCompleted.getFont().getSize()+3f));
|
lbCompleted.setFont(lbCompleted.getFont().deriveFont(lbCompleted.getFont().getSize()+3f));
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(lbCompleted, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.lbCompleted.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(lbCompleted, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.lbCompleted.text")); // NOI18N
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 6;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(0, 10, 5, 10);
|
||||||
|
mainPanel.add(lbCompleted, gridBagConstraints);
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(refreshButton, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.refreshButton.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(refreshButton, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.refreshButton.text")); // NOI18N
|
||||||
refreshButton.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.refreshButton.toolTipText")); // NOI18N
|
refreshButton.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.refreshButton.toolTipText")); // NOI18N
|
||||||
@ -383,61 +444,39 @@ final class AutoIngestDashboard extends JPanel implements Observer {
|
|||||||
refreshButtonActionPerformed(evt);
|
refreshButtonActionPerformed(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 8;
|
||||||
|
gridBagConstraints.gridwidth = 2;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(6, 10, 10, 10);
|
||||||
|
mainPanel.add(refreshButton, gridBagConstraints);
|
||||||
|
|
||||||
lbServicesStatus.setFont(lbServicesStatus.getFont().deriveFont(lbServicesStatus.getFont().getSize()+3f));
|
lbServicesStatus.setFont(lbServicesStatus.getFont().deriveFont(lbServicesStatus.getFont().getSize()+3f));
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(lbServicesStatus, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.lbServicesStatus.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(lbServicesStatus, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.lbServicesStatus.text")); // NOI18N
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(10, 10, 0, 10);
|
||||||
|
mainPanel.add(lbServicesStatus, gridBagConstraints);
|
||||||
|
|
||||||
tbServicesStatusMessage.setEditable(false);
|
tbServicesStatusMessage.setEditable(false);
|
||||||
tbServicesStatusMessage.setFont(tbServicesStatusMessage.getFont().deriveFont(tbServicesStatusMessage.getFont().getStyle() | java.awt.Font.BOLD, tbServicesStatusMessage.getFont().getSize()+1));
|
tbServicesStatusMessage.setFont(tbServicesStatusMessage.getFont().deriveFont(tbServicesStatusMessage.getFont().getStyle() | java.awt.Font.BOLD, tbServicesStatusMessage.getFont().getSize()+1));
|
||||||
tbServicesStatusMessage.setText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.text")); // NOI18N
|
tbServicesStatusMessage.setText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.text")); // NOI18N
|
||||||
tbServicesStatusMessage.setBorder(null);
|
tbServicesStatusMessage.setBorder(null);
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 1;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
|
gridBagConstraints.weightx = 1.0;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(10, 0, 0, 10);
|
||||||
|
mainPanel.add(tbServicesStatusMessage, gridBagConstraints);
|
||||||
|
|
||||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
mainScrollPane.setViewportView(mainPanel);
|
||||||
this.setLayout(layout);
|
|
||||||
layout.setHorizontalGroup(
|
add(mainScrollPane, java.awt.BorderLayout.CENTER);
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
|
||||||
.addContainerGap()
|
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
|
||||||
.addComponent(pendingScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
|
||||||
.addComponent(runningScrollPane, javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addComponent(completedScrollPane, javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
|
|
||||||
.addComponent(lbServicesStatus)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
|
||||||
.addComponent(tbServicesStatusMessage, javax.swing.GroupLayout.DEFAULT_SIZE, 861, Short.MAX_VALUE))
|
|
||||||
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
|
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
|
||||||
.addComponent(lbPending, javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addComponent(lbCompleted, javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addComponent(lbRunning, javax.swing.GroupLayout.Alignment.LEADING))
|
|
||||||
.addGap(0, 0, Short.MAX_VALUE))
|
|
||||||
.addComponent(refreshButton, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE))
|
|
||||||
.addContainerGap())
|
|
||||||
);
|
|
||||||
layout.setVerticalGroup(
|
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
|
||||||
.addContainerGap()
|
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
|
||||||
.addComponent(lbServicesStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addComponent(tbServicesStatusMessage, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(lbPending, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addGap(1, 1, 1)
|
|
||||||
.addComponent(pendingScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
|
||||||
.addComponent(lbRunning)
|
|
||||||
.addGap(1, 1, 1)
|
|
||||||
.addComponent(runningScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 133, Short.MAX_VALUE)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
|
||||||
.addComponent(lbCompleted)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(completedScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 179, Short.MAX_VALUE)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(refreshButton)
|
|
||||||
.addContainerGap())
|
|
||||||
);
|
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -460,6 +499,8 @@ final class AutoIngestDashboard extends JPanel implements Observer {
|
|||||||
private javax.swing.JLabel lbPending;
|
private javax.swing.JLabel lbPending;
|
||||||
private javax.swing.JLabel lbRunning;
|
private javax.swing.JLabel lbRunning;
|
||||||
private javax.swing.JLabel lbServicesStatus;
|
private javax.swing.JLabel lbServicesStatus;
|
||||||
|
private javax.swing.JPanel mainPanel;
|
||||||
|
private javax.swing.JScrollPane mainScrollPane;
|
||||||
private javax.swing.JScrollPane pendingScrollPane;
|
private javax.swing.JScrollPane pendingScrollPane;
|
||||||
private javax.swing.JButton refreshButton;
|
private javax.swing.JButton refreshButton;
|
||||||
private javax.swing.JScrollPane runningScrollPane;
|
private javax.swing.JScrollPane runningScrollPane;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
* Copyright 2011-2021 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.experimental.autoingest;
|
package org.sleuthkit.autopsy.experimental.autoingest;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -69,13 +70,14 @@ public final class AutoIngestDashboardTopComponent extends TopComponent {
|
|||||||
* dashboard instance so we don't accumulate them.
|
* dashboard instance so we don't accumulate them.
|
||||||
*/
|
*/
|
||||||
tc.removeAll();
|
tc.removeAll();
|
||||||
|
tc.setLayout(new BorderLayout());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a new dashboard instance to ensure we're using the
|
* Create a new dashboard instance to ensure we're using the
|
||||||
* most recent configuration.
|
* most recent configuration.
|
||||||
*/
|
*/
|
||||||
AutoIngestDashboard dashboard = AutoIngestDashboard.createDashboard();
|
AutoIngestDashboard dashboard = AutoIngestDashboard.createDashboard();
|
||||||
tc.add(dashboard);
|
tc.add(dashboard, BorderLayout.CENTER);
|
||||||
dashboard.setSize(dashboard.getPreferredSize());
|
dashboard.setSize(dashboard.getPreferredSize());
|
||||||
//if the user has administrator access enabled open the Node Status and cases top components as well
|
//if the user has administrator access enabled open the Node Status and cases top components as well
|
||||||
if (AutoIngestDashboard.isAdminAutoIngestDashboard()) {
|
if (AutoIngestDashboard.isAdminAutoIngestDashboard()) {
|
||||||
|
@ -205,7 +205,9 @@ DeleteCaseTask.progress.parsingManifest=Parsing manifest file {0}...
|
|||||||
DeleteCaseTask.progress.releasingManifestLock=Releasing lock on the manifest file {0}...
|
DeleteCaseTask.progress.releasingManifestLock=Releasing lock on the manifest file {0}...
|
||||||
DeleteCaseTask.progress.startMessage=Starting deletion...
|
DeleteCaseTask.progress.startMessage=Starting deletion...
|
||||||
DeleteOrphanCaseNodesAction.progressDisplayName=Cleanup Case Znodes
|
DeleteOrphanCaseNodesAction.progressDisplayName=Cleanup Case Znodes
|
||||||
|
# {0} - item count
|
||||||
DeleteOrphanCaseNodesDialog.additionalInit.lblNodeCount.text=Znodes found: {0}
|
DeleteOrphanCaseNodesDialog.additionalInit.lblNodeCount.text=Znodes found: {0}
|
||||||
|
# {0} - item count
|
||||||
DeleteOrphanCaseNodesDialog.additionalInit.znodesTextArea.countMessage=ZNODES FOUND: {0}
|
DeleteOrphanCaseNodesDialog.additionalInit.znodesTextArea.countMessage=ZNODES FOUND: {0}
|
||||||
DeleteOrphanCaseNodesTask.progress.connectingToCoordSvc=Connecting to the coordination service
|
DeleteOrphanCaseNodesTask.progress.connectingToCoordSvc=Connecting to the coordination service
|
||||||
# {0} - node path
|
# {0} - node path
|
||||||
|
@ -13,43 +13,40 @@
|
|||||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
|
||||||
<Layout>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||||
<DimensionLayout dim="0">
|
<SubComponents>
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Container class="javax.swing.JScrollPane" name="caseBrowserScrollPane">
|
||||||
<Group type="102" attributes="0">
|
<Constraints>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<BorderConstraints direction="Center"/>
|
||||||
<Group type="102" attributes="0">
|
</Constraint>
|
||||||
<Component id="refreshButton" linkSize="3" min="-2" max="-2" attributes="0"/>
|
</Constraints>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="deleteOrphanCaseNodesButton" linkSize="3" min="-2" max="-2" attributes="0"/>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<SubComponents>
|
||||||
<Component id="deleteOrphanManifestNodesButton" linkSize="3" min="-2" max="-2" attributes="0"/>
|
<Container class="javax.swing.JPanel" name="mainPanel">
|
||||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||||
<Group type="102" alignment="1" attributes="0">
|
<SubComponents>
|
||||||
<Component id="caseBrowserScrollPane" max="32767" attributes="0"/>
|
<Container class="javax.swing.JPanel" name="bottomPanel">
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<Constraints>
|
||||||
</Group>
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||||
</Group>
|
<BorderConstraints direction="South"/>
|
||||||
</Group>
|
</Constraint>
|
||||||
</Group>
|
</Constraints>
|
||||||
</DimensionLayout>
|
|
||||||
<DimensionLayout dim="1">
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<SubComponents>
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<Container class="javax.swing.JPanel" name="buttonPanel">
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<Constraints>
|
||||||
<Component id="caseBrowserScrollPane" pref="246" max="32767" attributes="0"/>
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="10" insetsLeft="10" insetsBottom="10" insetsRight="10" anchor="18" weightX="1.0" weightY="0.0"/>
|
||||||
<Group type="103" groupAlignment="3" attributes="0">
|
</Constraint>
|
||||||
<Component id="refreshButton" linkSize="2" alignment="3" min="-2" max="-2" attributes="0"/>
|
</Constraints>
|
||||||
<Component id="deleteOrphanCaseNodesButton" linkSize="2" alignment="3" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="deleteOrphanManifestNodesButton" linkSize="2" alignment="3" min="-2" max="-2" attributes="0"/>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
|
||||||
</Group>
|
<Property name="columns" type="int" value="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<Property name="rows" type="int" value="1"/>
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
</Layout>
|
</Layout>
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Component class="javax.swing.JButton" name="refreshButton">
|
<Component class="javax.swing.JButton" name="refreshButton">
|
||||||
@ -62,10 +59,6 @@
|
|||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="refreshButtonActionPerformed"/>
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="refreshButtonActionPerformed"/>
|
||||||
</Events>
|
</Events>
|
||||||
</Component>
|
</Component>
|
||||||
<Container class="javax.swing.JScrollPane" name="caseBrowserScrollPane">
|
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
|
||||||
</Container>
|
|
||||||
<Component class="javax.swing.JButton" name="deleteOrphanCaseNodesButton">
|
<Component class="javax.swing.JButton" name="deleteOrphanCaseNodesButton">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
@ -87,4 +80,12 @@
|
|||||||
</Events>
|
</Events>
|
||||||
</Component>
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
|
</SubComponents>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2019-2019 Basis Technology Corp.
|
* Copyright 2019-2021 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.experimental.autoingest;
|
package org.sleuthkit.autopsy.experimental.autoingest;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.openide.explorer.ExplorerManager;
|
import org.openide.explorer.ExplorerManager;
|
||||||
import org.openide.explorer.ExplorerUtils;
|
import org.openide.explorer.ExplorerUtils;
|
||||||
@ -95,8 +96,7 @@ public final class CasesDashboardTopComponent extends TopComponent implements Ex
|
|||||||
explorerManager = new ExplorerManager();
|
explorerManager = new ExplorerManager();
|
||||||
associateLookup(ExplorerUtils.createLookup(explorerManager, getActionMap()));
|
associateLookup(ExplorerUtils.createLookup(explorerManager, getActionMap()));
|
||||||
caseBrowserPanel = new MultiUserCasesBrowserPanel(explorerManager, new CasesDashboardCustomizer());
|
caseBrowserPanel = new MultiUserCasesBrowserPanel(explorerManager, new CasesDashboardCustomizer());
|
||||||
caseBrowserScrollPane.add(caseBrowserPanel);
|
mainPanel.add(caseBrowserPanel, BorderLayout.CENTER);
|
||||||
caseBrowserScrollPane.setViewportView(caseBrowserPanel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -116,18 +116,31 @@ public final class CasesDashboardTopComponent extends TopComponent implements Ex
|
|||||||
*/
|
*/
|
||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
|
java.awt.GridBagConstraints gridBagConstraints;
|
||||||
|
|
||||||
refreshButton = new javax.swing.JButton();
|
|
||||||
caseBrowserScrollPane = new javax.swing.JScrollPane();
|
caseBrowserScrollPane = new javax.swing.JScrollPane();
|
||||||
|
mainPanel = new javax.swing.JPanel();
|
||||||
|
bottomPanel = new javax.swing.JPanel();
|
||||||
|
buttonPanel = new javax.swing.JPanel();
|
||||||
|
refreshButton = new javax.swing.JButton();
|
||||||
deleteOrphanCaseNodesButton = new javax.swing.JButton();
|
deleteOrphanCaseNodesButton = new javax.swing.JButton();
|
||||||
deleteOrphanManifestNodesButton = new javax.swing.JButton();
|
deleteOrphanManifestNodesButton = new javax.swing.JButton();
|
||||||
|
|
||||||
|
setLayout(new java.awt.BorderLayout());
|
||||||
|
|
||||||
|
mainPanel.setLayout(new java.awt.BorderLayout());
|
||||||
|
|
||||||
|
bottomPanel.setLayout(new java.awt.GridBagLayout());
|
||||||
|
|
||||||
|
buttonPanel.setLayout(new java.awt.GridLayout());
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(refreshButton, org.openide.util.NbBundle.getMessage(CasesDashboardTopComponent.class, "CasesDashboardTopComponent.refreshButton.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(refreshButton, org.openide.util.NbBundle.getMessage(CasesDashboardTopComponent.class, "CasesDashboardTopComponent.refreshButton.text")); // NOI18N
|
||||||
refreshButton.addActionListener(new java.awt.event.ActionListener() {
|
refreshButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
refreshButtonActionPerformed(evt);
|
refreshButtonActionPerformed(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
buttonPanel.add(refreshButton);
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(deleteOrphanCaseNodesButton, org.openide.util.NbBundle.getMessage(CasesDashboardTopComponent.class, "CasesDashboardTopComponent.deleteOrphanCaseNodesButton.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(deleteOrphanCaseNodesButton, org.openide.util.NbBundle.getMessage(CasesDashboardTopComponent.class, "CasesDashboardTopComponent.deleteOrphanCaseNodesButton.text")); // NOI18N
|
||||||
deleteOrphanCaseNodesButton.addActionListener(new java.awt.event.ActionListener() {
|
deleteOrphanCaseNodesButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
@ -135,6 +148,7 @@ public final class CasesDashboardTopComponent extends TopComponent implements Ex
|
|||||||
deleteOrphanCaseNodesButtonActionPerformed(evt);
|
deleteOrphanCaseNodesButtonActionPerformed(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
buttonPanel.add(deleteOrphanCaseNodesButton);
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(deleteOrphanManifestNodesButton, org.openide.util.NbBundle.getMessage(CasesDashboardTopComponent.class, "CasesDashboardTopComponent.deleteOrphanManifestNodesButton.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(deleteOrphanManifestNodesButton, org.openide.util.NbBundle.getMessage(CasesDashboardTopComponent.class, "CasesDashboardTopComponent.deleteOrphanManifestNodesButton.text")); // NOI18N
|
||||||
deleteOrphanManifestNodesButton.addActionListener(new java.awt.event.ActionListener() {
|
deleteOrphanManifestNodesButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
@ -142,43 +156,21 @@ public final class CasesDashboardTopComponent extends TopComponent implements Ex
|
|||||||
deleteOrphanManifestNodesButtonActionPerformed(evt);
|
deleteOrphanManifestNodesButtonActionPerformed(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
buttonPanel.add(deleteOrphanManifestNodesButton);
|
||||||
|
|
||||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
this.setLayout(layout);
|
gridBagConstraints.gridx = 0;
|
||||||
layout.setHorizontalGroup(
|
gridBagConstraints.gridy = 0;
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
.addGroup(layout.createSequentialGroup()
|
gridBagConstraints.weightx = 1.0;
|
||||||
.addContainerGap()
|
gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
bottomPanel.add(buttonPanel, gridBagConstraints);
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addComponent(refreshButton)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(deleteOrphanCaseNodesButton)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(deleteOrphanManifestNodesButton)
|
|
||||||
.addGap(0, 0, Short.MAX_VALUE))
|
|
||||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
|
||||||
.addComponent(caseBrowserScrollPane)
|
|
||||||
.addContainerGap())))
|
|
||||||
);
|
|
||||||
|
|
||||||
layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {deleteOrphanCaseNodesButton, deleteOrphanManifestNodesButton, refreshButton});
|
mainPanel.add(bottomPanel, java.awt.BorderLayout.SOUTH);
|
||||||
|
|
||||||
layout.setVerticalGroup(
|
caseBrowserScrollPane.setViewportView(mainPanel);
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addContainerGap()
|
|
||||||
.addComponent(caseBrowserScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 246, Short.MAX_VALUE)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
|
||||||
.addComponent(refreshButton)
|
|
||||||
.addComponent(deleteOrphanCaseNodesButton)
|
|
||||||
.addComponent(deleteOrphanManifestNodesButton))
|
|
||||||
.addContainerGap())
|
|
||||||
);
|
|
||||||
|
|
||||||
layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {deleteOrphanCaseNodesButton, deleteOrphanManifestNodesButton, refreshButton});
|
|
||||||
|
|
||||||
|
add(caseBrowserScrollPane, java.awt.BorderLayout.CENTER);
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
private void refreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshButtonActionPerformed
|
private void refreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshButtonActionPerformed
|
||||||
@ -194,9 +186,12 @@ public final class CasesDashboardTopComponent extends TopComponent implements Ex
|
|||||||
}//GEN-LAST:event_deleteOrphanManifestNodesButtonActionPerformed
|
}//GEN-LAST:event_deleteOrphanManifestNodesButtonActionPerformed
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
|
private javax.swing.JPanel bottomPanel;
|
||||||
|
private javax.swing.JPanel buttonPanel;
|
||||||
private javax.swing.JScrollPane caseBrowserScrollPane;
|
private javax.swing.JScrollPane caseBrowserScrollPane;
|
||||||
private javax.swing.JButton deleteOrphanCaseNodesButton;
|
private javax.swing.JButton deleteOrphanCaseNodesButton;
|
||||||
private javax.swing.JButton deleteOrphanManifestNodesButton;
|
private javax.swing.JButton deleteOrphanManifestNodesButton;
|
||||||
|
private javax.swing.JPanel mainPanel;
|
||||||
private javax.swing.JButton refreshButton;
|
private javax.swing.JButton refreshButton;
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
|
@ -10,3 +10,5 @@ MemoryDSInputPanel.errorLabel.text=Error Label
|
|||||||
MemoryDSInputPanel.browseButton.text=Browse
|
MemoryDSInputPanel.browseButton.text=Browse
|
||||||
MemoryDSInputPanel.timeZoneLabel.text=Timezone:
|
MemoryDSInputPanel.timeZoneLabel.text=Timezone:
|
||||||
MemoryDSInputPanel.profileLabel.text=Profile:
|
MemoryDSInputPanel.profileLabel.text=Profile:
|
||||||
|
MemoryDSInputPanel.selectAllButton.text=Select All
|
||||||
|
MemoryDSInputPanel.deselectAllButton.text=Deselect All
|
||||||
|
@ -17,6 +17,8 @@ MemoryDSInputPanel.errorLabel.text=Error Label
|
|||||||
MemoryDSInputPanel.browseButton.text=Browse
|
MemoryDSInputPanel.browseButton.text=Browse
|
||||||
MemoryDSInputPanel.timeZoneLabel.text=Timezone:
|
MemoryDSInputPanel.timeZoneLabel.text=Timezone:
|
||||||
MemoryDSInputPanel.profileLabel.text=Profile:
|
MemoryDSInputPanel.profileLabel.text=Profile:
|
||||||
|
MemoryDSInputPanel.selectAllButton.text=Select All
|
||||||
|
MemoryDSInputPanel.deselectAllButton.text=Deselect All
|
||||||
MemoryDSInputPanel_errorMsg_dataSourcePathOnCdrive=Path to multi-user data source is on "C:" drive
|
MemoryDSInputPanel_errorMsg_dataSourcePathOnCdrive=Path to multi-user data source is on "C:" drive
|
||||||
MemoryDSInputPanel_errorMsg_noOpenCase=No open case
|
MemoryDSInputPanel_errorMsg_noOpenCase=No open case
|
||||||
MemoryDSProcessor.dataSourceType=Memory Image File (Volatility)
|
MemoryDSProcessor.dataSourceType=Memory Image File (Volatility)
|
||||||
|
@ -37,6 +37,11 @@
|
|||||||
<Component id="profileComboBox" alignment="0" pref="243" max="32767" attributes="0"/>
|
<Component id="profileComboBox" alignment="0" pref="243" max="32767" attributes="0"/>
|
||||||
<Component id="timeZoneComboBox" alignment="0" max="32767" attributes="0"/>
|
<Component id="timeZoneComboBox" alignment="0" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<Component id="selectAllButton" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="deselectAllButton" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
@ -78,7 +83,12 @@
|
|||||||
<Component id="PluginsToRunLabel" min="-2" max="-2" attributes="0"/>
|
<Component id="PluginsToRunLabel" min="-2" max="-2" attributes="0"/>
|
||||||
<Component id="listsScrollPane" min="-2" pref="122" max="-2" attributes="0"/>
|
<Component id="listsScrollPane" min="-2" pref="122" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
<EmptySpace pref="73" max="32767" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Group type="103" groupAlignment="3" attributes="0">
|
||||||
|
<Component id="selectAllButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="deselectAllButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
<EmptySpace pref="44" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
@ -188,5 +198,25 @@
|
|||||||
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
|
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
</Component>
|
</Component>
|
||||||
|
<Component class="javax.swing.JButton" name="selectAllButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/experimental/volatilityDSP/Bundle.properties" key="MemoryDSInputPanel.selectAllButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="selectAllButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JButton" name="deselectAllButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/experimental/volatilityDSP/Bundle.properties" key="MemoryDSInputPanel.deselectAllButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="deselectAllButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -191,6 +191,8 @@ final class MemoryDSInputPanel extends JPanel implements DocumentListener {
|
|||||||
pluginTable = new javax.swing.JTable();
|
pluginTable = new javax.swing.JTable();
|
||||||
profileLabel = new javax.swing.JLabel();
|
profileLabel = new javax.swing.JLabel();
|
||||||
profileComboBox = new javax.swing.JComboBox<>();
|
profileComboBox = new javax.swing.JComboBox<>();
|
||||||
|
selectAllButton = new javax.swing.JButton();
|
||||||
|
deselectAllButton = new javax.swing.JButton();
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(pathLabel, org.openide.util.NbBundle.getMessage(MemoryDSInputPanel.class, "MemoryDSInputPanel.pathLabel.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(pathLabel, org.openide.util.NbBundle.getMessage(MemoryDSInputPanel.class, "MemoryDSInputPanel.pathLabel.text")); // NOI18N
|
||||||
|
|
||||||
@ -238,6 +240,20 @@ final class MemoryDSInputPanel extends JPanel implements DocumentListener {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(selectAllButton, org.openide.util.NbBundle.getMessage(MemoryDSInputPanel.class, "MemoryDSInputPanel.selectAllButton.text")); // NOI18N
|
||||||
|
selectAllButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
selectAllButtonActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(deselectAllButton, org.openide.util.NbBundle.getMessage(MemoryDSInputPanel.class, "MemoryDSInputPanel.deselectAllButton.text")); // NOI18N
|
||||||
|
deselectAllButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
deselectAllButtonActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||||
this.setLayout(layout);
|
this.setLayout(layout);
|
||||||
layout.setHorizontalGroup(
|
layout.setHorizontalGroup(
|
||||||
@ -256,7 +272,11 @@ final class MemoryDSInputPanel extends JPanel implements DocumentListener {
|
|||||||
.addComponent(listsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 248, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(listsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 248, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
|
||||||
.addComponent(profileComboBox, javax.swing.GroupLayout.Alignment.LEADING, 0, 243, Short.MAX_VALUE)
|
.addComponent(profileComboBox, javax.swing.GroupLayout.Alignment.LEADING, 0, 243, Short.MAX_VALUE)
|
||||||
.addComponent(timeZoneComboBox, javax.swing.GroupLayout.Alignment.LEADING, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))))
|
.addComponent(timeZoneComboBox, javax.swing.GroupLayout.Alignment.LEADING, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||||
|
.addGroup(layout.createSequentialGroup()
|
||||||
|
.addComponent(selectAllButton)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(deselectAllButton)))))
|
||||||
.addGap(0, 163, Short.MAX_VALUE))
|
.addGap(0, 163, Short.MAX_VALUE))
|
||||||
.addGroup(layout.createSequentialGroup()
|
.addGroup(layout.createSequentialGroup()
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
@ -287,7 +307,11 @@ final class MemoryDSInputPanel extends JPanel implements DocumentListener {
|
|||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addComponent(PluginsToRunLabel)
|
.addComponent(PluginsToRunLabel)
|
||||||
.addComponent(listsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 122, javax.swing.GroupLayout.PREFERRED_SIZE))
|
.addComponent(listsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 122, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||||
.addContainerGap(73, Short.MAX_VALUE))
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
|
.addComponent(selectAllButton)
|
||||||
|
.addComponent(deselectAllButton))
|
||||||
|
.addContainerGap(44, Short.MAX_VALUE))
|
||||||
);
|
);
|
||||||
|
|
||||||
pathLabel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(MemoryDSInputPanel.class, "MemoryDSInputPanel.pathLabel.AccessibleContext.accessibleName")); // NOI18N
|
pathLabel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(MemoryDSInputPanel.class, "MemoryDSInputPanel.pathLabel.AccessibleContext.accessibleName")); // NOI18N
|
||||||
@ -316,9 +340,24 @@ final class MemoryDSInputPanel extends JPanel implements DocumentListener {
|
|||||||
// TODO add your handling code here:
|
// TODO add your handling code here:
|
||||||
}//GEN-LAST:event_pathTextFieldActionPerformed
|
}//GEN-LAST:event_pathTextFieldActionPerformed
|
||||||
|
|
||||||
|
private void selectAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectAllButtonActionPerformed
|
||||||
|
for(String name : pluginListStates.keySet()) {
|
||||||
|
pluginListStates.put(name, Boolean.TRUE);
|
||||||
|
}
|
||||||
|
tableModel.fireTableDataChanged();
|
||||||
|
}//GEN-LAST:event_selectAllButtonActionPerformed
|
||||||
|
|
||||||
|
private void deselectAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deselectAllButtonActionPerformed
|
||||||
|
for(String name : pluginListStates.keySet()) {
|
||||||
|
pluginListStates.put(name, Boolean.FALSE);
|
||||||
|
}
|
||||||
|
tableModel.fireTableDataChanged();
|
||||||
|
}//GEN-LAST:event_deselectAllButtonActionPerformed
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
private javax.swing.JLabel PluginsToRunLabel;
|
private javax.swing.JLabel PluginsToRunLabel;
|
||||||
private javax.swing.JButton browseButton;
|
private javax.swing.JButton browseButton;
|
||||||
|
private javax.swing.JButton deselectAllButton;
|
||||||
private javax.swing.JLabel errorLabel;
|
private javax.swing.JLabel errorLabel;
|
||||||
private javax.swing.ButtonGroup infileTypeButtonGroup;
|
private javax.swing.ButtonGroup infileTypeButtonGroup;
|
||||||
private javax.swing.JScrollPane listsScrollPane;
|
private javax.swing.JScrollPane listsScrollPane;
|
||||||
@ -327,6 +366,7 @@ final class MemoryDSInputPanel extends JPanel implements DocumentListener {
|
|||||||
private javax.swing.JTable pluginTable;
|
private javax.swing.JTable pluginTable;
|
||||||
private javax.swing.JComboBox<String> profileComboBox;
|
private javax.swing.JComboBox<String> profileComboBox;
|
||||||
private javax.swing.JLabel profileLabel;
|
private javax.swing.JLabel profileLabel;
|
||||||
|
private javax.swing.JButton selectAllButton;
|
||||||
private javax.swing.JComboBox<String> timeZoneComboBox;
|
private javax.swing.JComboBox<String> timeZoneComboBox;
|
||||||
private javax.swing.JLabel timeZoneLabel;
|
private javax.swing.JLabel timeZoneLabel;
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
@ -192,12 +192,15 @@ public final class ImageGalleryController {
|
|||||||
* @param theCase The case.
|
* @param theCase The case.
|
||||||
*/
|
*/
|
||||||
static void shutDownController(Case theCase) {
|
static void shutDownController(Case theCase) {
|
||||||
|
ImageGalleryController controller = null;
|
||||||
synchronized (controllersByCaseLock) {
|
synchronized (controllersByCaseLock) {
|
||||||
if (controllersByCase.containsKey(theCase.getName())) {
|
if (controllersByCase.containsKey(theCase.getName())) {
|
||||||
ImageGalleryController controller = controllersByCase.remove(theCase.getName());
|
controller = controllersByCase.remove(theCase.getName());
|
||||||
controller.shutDown();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (controller != null) {
|
||||||
|
controller.shutDown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -100,13 +100,9 @@ public abstract class DrawableFile {
|
|||||||
|
|
||||||
private String model;
|
private String model;
|
||||||
|
|
||||||
private final CategoryManager categoryManager;
|
|
||||||
|
|
||||||
protected DrawableFile(AbstractFile file, Boolean analyzed) {
|
protected DrawableFile(AbstractFile file, Boolean analyzed) {
|
||||||
this.analyzed = new SimpleBooleanProperty(analyzed);
|
this.analyzed = new SimpleBooleanProperty(analyzed);
|
||||||
this.file = file;
|
this.file = file;
|
||||||
|
|
||||||
categoryManager = ImageGalleryController.getController(Case.getCurrentCase()).getCategoryManager();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract boolean isVideo();
|
public abstract boolean isVideo();
|
||||||
@ -247,11 +243,17 @@ public abstract class DrawableFile {
|
|||||||
*/
|
*/
|
||||||
private void updateCategory() {
|
private void updateCategory() {
|
||||||
try {
|
try {
|
||||||
|
ImageGalleryController controllerForCase = ImageGalleryController.getController(Case.getCurrentCaseThrows());
|
||||||
|
if (controllerForCase == null) {
|
||||||
|
// This can only happen during case closing, so return without generating an error.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
List<ContentTag> contentTags = getContentTags();
|
List<ContentTag> contentTags = getContentTags();
|
||||||
TagName tag = null;
|
TagName tag = null;
|
||||||
for (ContentTag ct : contentTags) {
|
for (ContentTag ct : contentTags) {
|
||||||
TagName tagName = ct.getName();
|
TagName tagName = ct.getName();
|
||||||
if (categoryManager.isCategoryTagName(tagName)) {
|
if (controllerForCase.getCategoryManager().isCategoryTagName(tagName)) {
|
||||||
tag = tagName;
|
tag = tagName;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -259,7 +261,7 @@ public abstract class DrawableFile {
|
|||||||
categoryTagName.set(tag);
|
categoryTagName.set(tag);
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
LOGGER.log(Level.WARNING, "problem looking up category for " + this.getContentPathSafe(), ex); //NON-NLS
|
LOGGER.log(Level.WARNING, "problem looking up category for " + this.getContentPathSafe(), ex); //NON-NLS
|
||||||
} catch (IllegalStateException ex) {
|
} catch (IllegalStateException | NoCurrentCaseException ex) {
|
||||||
// We get here many times if the case is closed during ingest, so don't print out a ton of warnings.
|
// We get here many times if the case is closed during ingest, so don't print out a ton of warnings.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,7 +173,7 @@
|
|||||||
<!-- Update configuration file to include jre -->
|
<!-- Update configuration file to include jre -->
|
||||||
<property name="inst.property.file" value="${inst-path}/etc/${app.name}.conf" />
|
<property name="inst.property.file" value="${inst-path}/etc/${app.name}.conf" />
|
||||||
<!-- Sets max heap size to be ${jvm.max.mem} which is set in the run-ai-(32/64) target -->
|
<!-- Sets max heap size to be ${jvm.max.mem} which is set in the run-ai-(32/64) target -->
|
||||||
<var name="jvm.args" value=""--branding ${app.name} -J-Xms24m -J-Xmx${jvm.max.mem} -J-XX:MaxPermSize=128M -J-Xverify:none -J-XX:+UseG1GC -J-XX:+UseStringDeduplication "" />
|
<var name="jvm.args" value=""--branding ${app.name} -J-Xms24m -J-Xmx4G -J-Xverify:none -J-XX:+UseG1GC -J-XX:+UseStringDeduplication -J-Dprism.order=sw "" />
|
||||||
<propertyfile file="${inst.property.file}">
|
<propertyfile file="${inst.property.file}">
|
||||||
<!-- Note: can be higher on 64 bit systems, should be in sync with project.properties -->
|
<!-- Note: can be higher on 64 bit systems, should be in sync with project.properties -->
|
||||||
<entry key="default_options" value="@JVM_OPTIONS" />
|
<entry key="default_options" value="@JVM_OPTIONS" />
|
||||||
|
BIN
docs/doxygen-user/images/solr/solr_config_monitoring.png
Normal file
BIN
docs/doxygen-user/images/solr/solr_config_monitoring.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 130 KiB |
Binary file not shown.
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 97 KiB |
@ -53,9 +53,8 @@ Follow these steps to configure Solr:
|
|||||||
Required Solr Configuration Parameters:
|
Required Solr Configuration Parameters:
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>JAVA_HOME</b> – path to 64-bit JRE installation. For example \c "JAVA_HOME=C:\Program Files\Java\jre1.8.0_151" or \c "JAVA_HOME=C:\Program Files\ojdkbuild\java-1.8.0-openjdk-1.8.0.222-1"
|
<li><b>JAVA_HOME</b> – path to 64-bit JRE installation. For example \c "JAVA_HOME=C:\Program Files\Java\jre1.8.0_151" or \c "JAVA_HOME=C:\Program Files\ojdkbuild\java-1.8.0-openjdk-1.8.0.222-1"
|
||||||
<li><b>DEFAULT_CONFDIR</b> – path to Autopsy configuration directory. If the Solr archive was extracted into \c "C:\solr-8.6.3" directory, then this path will be \c "C:\ solr-8.6.3\server\solr\configsets\AutopsyConfig\conf".
|
<li><b>DEFAULT_CONFDIR</b> – path to Autopsy configuration directory. If the Solr archive was extracted into \c "C:\solr-8.6.3" directory, then this path will be \c "C:\ solr-8.6.3\server\solr\configsets\AutopsyConfig\conf". Do not include quotes around the path.
|
||||||
<li><b>Dbootstrap_confdir</b> – same path as <b>DEFAULT_CONFDIR</b>
|
<li><b>SOLR_JAVA_MEM</b> - Solr JVM heap size should be as large as the Solr machine’s resources allow, at least half of the total RAM available on the machine. A rule of thumb would be use "set SOLR_JAVA_MEM=-Xms2G -Xmx40G" for a machine with 64GB of RAM, "set SOLR_JAVA_MEM=-Xms2G -Xmx20G" for a machine with 32GB of RAM, and "set SOLR_JAVA_MEM=-Xms2G -Xmx8G" for a machine with 16GB of RAM. Please see the \ref install_solr_heap_usage "troubleshooting section" for more info regarding Solr heap usage and troubleshooting information.
|
||||||
<li><b>SOLR_JAVA_MEM</b> - Solr JVM heap size should be somewhere between one third and one half of the total RAM available on the machine. A rule of thumb would be use \c "set SOLR_JAVA_MEM=-Xms2G -Xmx14G" for a machine with 32GB of RAM or more, and \c "set SOLR_JAVA_MEM=-Xms2G -Xmx8G" for a machine with 16GB of RAM.
|
|
||||||
<li><b>SOLR_DATA_HOME</b> – location where Solr indexes will be stored. If this is not configured, the indexes will be stored in the \c "C:\solr-8.6.3\server\solr" directory. NOTE: for Autopsy cases consisting of large number of data sources, Solr indexes can get very large (hundreds of GBs, or TBs) so they should probably be stored on a larger network share.
|
<li><b>SOLR_DATA_HOME</b> – location where Solr indexes will be stored. If this is not configured, the indexes will be stored in the \c "C:\solr-8.6.3\server\solr" directory. NOTE: for Autopsy cases consisting of large number of data sources, Solr indexes can get very large (hundreds of GBs, or TBs) so they should probably be stored on a larger network share.
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@ -208,8 +207,57 @@ Solr creates two types of data that need to be backed up:
|
|||||||
<ol><li>In a default installation that data is stored in \c "C:\solr-8.6.3\server\solr zoo_data" (assuming that the Solr package ZIP was extracted into \c "C:\solr-8.6.3" directory).</ol>
|
<ol><li>In a default installation that data is stored in \c "C:\solr-8.6.3\server\solr zoo_data" (assuming that the Solr package ZIP was extracted into \c "C:\solr-8.6.3" directory).</ol>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
\section install_solr_delayed_start Delayed Start Problems With Large Number Of Solr Collections
|
\section Troubleshooting
|
||||||
|
|
||||||
|
\subsection install_solr_delayed_start Delayed Start Problems With Large Number Of Solr Collections
|
||||||
|
|
||||||
In our testing, we have encountered an issue when a very large number (thousands) of Autopsy multi-user cases was created. Each new Autopsy multi-user case creates a Solr "collection" that contains the Solr text index. With 2,000 existing collections, when Solr service is restarted, Solr appears to internally be "loading" roughly 250 collections per minute (in chronological order, starting with oldest collections). After 4 minutes roughly half of the 2,000 collections were loaded. Users are able to search the collections that have been loaded, but they are unable to open or search the collections that have not yet been internally loaded by Solr. After 7-8 minutes all collections were loaded. These numbers will vary depending on the specific cluster configuration, text index file location (network or local storage), network throughput, number of Solr servers, etc.
|
In our testing, we have encountered an issue when a very large number (thousands) of Autopsy multi-user cases was created. Each new Autopsy multi-user case creates a Solr "collection" that contains the Solr text index. With 2,000 existing collections, when Solr service is restarted, Solr appears to internally be "loading" roughly 250 collections per minute (in chronological order, starting with oldest collections). After 4 minutes roughly half of the 2,000 collections were loaded. Users are able to search the collections that have been loaded, but they are unable to open or search the collections that have not yet been internally loaded by Solr. After 7-8 minutes all collections were loaded. These numbers will vary depending on the specific cluster configuration, text index file location (network or local storage), network throughput, number of Solr servers, etc.
|
||||||
|
|
||||||
|
\subsection install_solr_heap_usage Solr Heap Usage and Recommendations
|
||||||
|
|
||||||
|
Solr JVM heap plays especially important role if you are going to create a large number of Autopsy cases (i.e. Solr collections). Here are some “rule of thumb” Solr heap usage stats that we identified during our internal testing:
|
||||||
|
<ul>
|
||||||
|
<li>For very small cases/collections, our tests show that Solr uses an absolute minimum of 7-10 MB of heap per collection.
|
||||||
|
<li>For larger cases/collections (50-100GB input E01 size) Solr uses at least 65 MB per collection
|
||||||
|
<li>For large cases/collections (1.5TB input E01 size) Solr uses at least 850 MB per collection
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
\subsubsection install_solr_heap_troublshooting Troubleshooting Solr Heap Issues
|
||||||
|
|
||||||
|
Once the Solr JVM uses all of its available heap and is unable to free up any memory via garbage collection, the Solr service will not be able to create new collections or may become completely unresponsive, resulting in Autopsy being unable to create new text indexes. Below is a list of some of the errors that you might see as a result of this in the Solr (not Autopsy) service logs and/or the Solr admin console:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>org.apache.solr.common.SolrException: Could not register as the leader because creating the ephemeral registration node in ZooKeeper failed
|
||||||
|
<li>RequestHandlerBase org.apache.solr.common.SolrException: Failed to get config from zookeeper
|
||||||
|
<li>RecoveryStrategy Error while trying to recover. org.apache.solr.common.SolrException: Cloud state still says we are leader.
|
||||||
|
<li>RequestHandlerBase org.apache.solr.common.SolrException: Could not load collection from ZK
|
||||||
|
<li>org.apache.solr.common.SolrException: Error CREATEing SolrCore: Unable to create core. Caused by: There are no more files
|
||||||
|
<li>org.apache.solr.common.SolrException: java.io.IOException: There are no more files
|
||||||
|
<li>org.apache.solr.common.SolrException: Cannot unload non-existent core
|
||||||
|
<li>ZkIndexSchemaReader Error creating ZooKeeper watch for the managed schema
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
You may also see the following ZooKeeper errors:
|
||||||
|
<ul>
|
||||||
|
<li>org.apache.zookeeper.KeeperException$NodeExistsException: KeeperErrorCode = NodeExists
|
||||||
|
<li>org.apache.zookeeper.KeeperException$BadVersionException: KeeperErrorCode = BadVersion for (collection_name)/state.json
|
||||||
|
<li>org.apache.zookeeper.KeeperException$SessionExpiredException: KeeperErrorCode = Session expired for /roles.json
|
||||||
|
<li>org.apache.zookeeper.KeeperException$SessionExpiredException: KeeperErrorCode = Session expired for /configs/AutopsyConfig/managed-schema
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
The common theme among most of these errors is the breakdown in communication between Solr and ZooKeeper, especially when using an embedded ZooKeeper server. It is important to note that these errors may potentially occur for other reasons and are not unique to Solr heap issues.
|
||||||
|
|
||||||
|
\subsubsection install_solr_monitoring Monitoring Solr Heap Usage
|
||||||
|
|
||||||
|
The simplest way to see current Solr heap usage is to check the Solr Admin Console web page. To access the Solr admin console, on the Solr machine navigate to http://localhost:8983/solr/#/ . There you will be able to see the Solr memory usage:
|
||||||
|
|
||||||
|
\image html solr_config_monitoring.png
|
||||||
|
|
||||||
|
However, the dashboard does not show enough detail to know when Solr is out of heap, so it should only be used to identify that you are NOT having heap issues. Even if the dashboard shows that the Solr heap is fully used, it may or may not be an issue. It is best to use profiling tools like Java VisualVM. In order for VisualVM to connect to Solr, you will need to enable the JMX interface for Solr’s Java process. The details are described here:
|
||||||
|
<ul><li>https://solr.apache.org/guide/8_3/using-jmx-with-solr.html#using-jmx-with-solr</ul>
|
||||||
|
|
||||||
|
Solr heap and other performance tuning is described in the following article:
|
||||||
|
<ul><li>https://cwiki.apache.org/confluence/display/SOLR/SolrPerformanceProblems</ul>
|
||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
@ -444,6 +444,7 @@ def normalize_db_entry(line, files_table, vs_parts_table, vs_info_table, fs_info
|
|||||||
ig_groups_seen_index = line.find('INSERT INTO "image_gallery_groups_seen"') > -1 or line.find('INSERT INTO image_gallery_groups_seen ') > -1
|
ig_groups_seen_index = line.find('INSERT INTO "image_gallery_groups_seen"') > -1 or line.find('INSERT INTO image_gallery_groups_seen ') > -1
|
||||||
os_account_index = line.find('INSERT INTO "tsk_os_accounts"') > -1 or line.find('INSERT INTO tsk_os_accounts') > -1
|
os_account_index = line.find('INSERT INTO "tsk_os_accounts"') > -1 or line.find('INSERT INTO tsk_os_accounts') > -1
|
||||||
os_account_attr_index = line.find('INSERT INTO "tsk_os_account_attributes"') > -1 or line.find('INSERT INTO tsk_os_account_attributes') > -1
|
os_account_attr_index = line.find('INSERT INTO "tsk_os_account_attributes"') > -1 or line.find('INSERT INTO tsk_os_account_attributes') > -1
|
||||||
|
os_account_instances_index = line.find('INSERT INTO "tsk_os_account_instances"') > -1 or line.find('INSERT INTO tsk_os_account_instances') > -1
|
||||||
|
|
||||||
parens = line[line.find('(') + 1 : line.rfind(')')]
|
parens = line[line.find('(') + 1 : line.rfind(')')]
|
||||||
no_space_parens = parens.replace(" ", "")
|
no_space_parens = parens.replace(" ", "")
|
||||||
@ -664,6 +665,11 @@ def normalize_db_entry(line, files_table, vs_parts_table, vs_info_table, fs_info
|
|||||||
fields_list[3] = "NULL"
|
fields_list[3] = "NULL"
|
||||||
newLine = ('INSERT INTO "tsk_os_account_attributes" VALUES(' + ','.join(fields_list[1:]) + ');') # remove id
|
newLine = ('INSERT INTO "tsk_os_account_attributes" VALUES(' + ','.join(fields_list[1:]) + ');') # remove id
|
||||||
return newLine
|
return newLine
|
||||||
|
elif os_account_instances_index:
|
||||||
|
os_account_id = int(fields_list[1])
|
||||||
|
fields_list[1] = accounts_table[os_account_id]
|
||||||
|
newLine = ('INSERT INTO "tsk_os_account_instances" VALUES(' + ','.join(fields_list[1:]) + ');') # remove id
|
||||||
|
return newLine
|
||||||
else:
|
else:
|
||||||
return line
|
return line
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user