Merge pull request #4229 from millmanorama/timeline-event-mgr

1093 Timeline event mgr
This commit is contained in:
Brian Carrier 2018-10-31 09:36:49 -04:00 committed by GitHub
commit 02ce6ee62c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
291 changed files with 12248 additions and 9519 deletions

View File

@ -26,7 +26,6 @@
<dependency conf="core->default" org="org.apache.commons" name="commons-dbcp2" rev="2.1.1"/>
<dependency conf="core->default" org="org.apache.commons" name="commons-pool2" rev="2.4.2"/>
<dependency org="com.monitorjbl" name="xlsx-streamer" rev="1.2.1"/>
<dependency conf="core->default" org="org.jsoup" name="jsoup" rev="1.10.3"/>
<dependency conf="core->default" org="com.googlecode.plist" name="dd-plist" rev="1.20"/>

View File

@ -2,7 +2,7 @@ Manifest-Version: 1.0
OpenIDE-Module: org.sleuthkit.autopsy.core/10
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties
OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml
OpenIDE-Module-Implementation-Version: 24
OpenIDE-Module-Implementation-Version: 25
OpenIDE-Module-Requires: org.openide.windows.WindowManager
AutoUpdate-Show-In-Client: true
AutoUpdate-Essential-Module: true

View File

@ -29,13 +29,12 @@ file.reference.cxf-rt-transports-http-3.0.16.jar=release/modules/ext/cxf-rt-tran
file.reference.fontbox-2.0.8.jar=release/modules/ext/fontbox-2.0.8.jar
file.reference.pdfbox-2.0.8.jar=release/modules/ext/pdfbox-2.0.8.jar
file.reference.pdfbox-tools-2.0.8.jar=release/modules/ext/pdfbox-tools-2.0.8.jar
file.reference.sleuthkit-postgresql-4.6.2.jar=release/modules/ext/sleuthkit-postgresql-4.6.2.jar
file.reference.sleuthkit-postgresql-4.6.3.jar=release/modules/ext/sleuthkit-postgresql-4.6.3.jar
file.reference.tika-core-1.17.jar=release/modules/ext/tika-core-1.17.jar
file.reference.tika-parsers-1.17.jar=release/modules/ext/tika-parsers-1.17.jar
file.reference.curator-client-2.8.0.jar=release/modules/ext/curator-client-2.8.0.jar
file.reference.curator-framework-2.8.0.jar=release/modules/ext/curator-framework-2.8.0.jar
file.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0.jar
file.reference.xlsx-streamer-1.2.1.jar=release/modules/ext/xlsx-streamer-1.2.1.jar
file.reference.xmpcore-5.1.3.jar=release/modules/ext/xmpcore-5.1.3.jar
file.reference.xz-1.6.jar=release/modules/ext/xz-1.6.jar
file.reference.zookeeper-3.4.6.jar=release/modules/ext/zookeeper-3.4.6.jar
@ -48,5 +47,5 @@ nbm.homepage=http://www.sleuthkit.org/
nbm.module.author=Brian Carrier
nbm.needs.restart=true
source.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0-sources.jar
spec.version.base=10.12
spec.version.base=10.13

View File

@ -394,8 +394,8 @@
<binary-origin>release/modules/ext/sevenzipjbinding.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sleuthkit-postgresql-4.6.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sleuthkit-postgresql-4.6.2.jar</binary-origin>
<runtime-relative-path>ext/sleuthkit-postgresql-4.6.3.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sleuthkit-postgresql-4.6.3.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/mchange-commons-java-0.2.9.jar</runtime-relative-path>
@ -497,10 +497,6 @@
<runtime-relative-path>ext/SparseBitSet-1.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/SparseBitSet-1.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/xlsx-streamer-1.2.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/xlsx-streamer-1.2.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/pdfbox-2.0.8.jar</runtime-relative-path>
<binary-origin>release/modules/ext/pdfbox-2.0.8.jar</binary-origin>

View File

@ -0,0 +1,147 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 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.casemodule;
import java.beans.PropertyChangeEvent;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.EnumSet;
import java.util.Properties;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
/**
* Read and update case preference file values.
*/
public final class CasePreferences {
private static final String SETTINGS_FILE = "CasePreferences.properties"; //NON-NLS
private static final String KEY_GROUP_BY_DATA_SOURCE = "groupByDataSource"; //NON-NLS
private static final String VALUE_TRUE = "true"; //NON-NLS
private static final String VALUE_FALSE = "false"; //NON-NLS
private static final Logger logger = Logger.getLogger(CasePreferences.class.getName());
private static Boolean groupItemsInTreeByDataSource = null;
/**
* Prevent instantiation.
*/
private CasePreferences() {
}
static {
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> {
if (evt.getNewValue() != null) {
loadFromStorage((Case) evt.getNewValue());
} else {
saveToStorage((Case) evt.getOldValue());
clear();
}
});
try {
loadFromStorage(Case.getCurrentCaseThrows());
} catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "No current case open.", ex);
}
}
/**
* Get the 'groupItemsInTreeByDataSource' value. This can be true, false, or
* null.
*
* @return The value.
*/
public static Boolean getGroupItemsInTreeByDataSource() {
return groupItemsInTreeByDataSource;
}
/**
* Set the 'groupItemsInTreeByDataSource' value to true or false.
*
* @param value The value to use for the value change.
*/
public static void setGroupItemsInTreeByDataSource(boolean value) {
groupItemsInTreeByDataSource = value;
DirectoryTreeTopComponent.getDefault().refreshContentTreeSafe();
}
/**
* Load case preferences from the settings file.
*/
private static void loadFromStorage(Case currentCase) {
Path settingsFile = Paths.get(currentCase.getConfigDirectory(), SETTINGS_FILE); //NON-NLS
if (settingsFile.toFile().exists()) {
// Read the settings
try (InputStream inputStream = Files.newInputStream(settingsFile)) {
Properties props = new Properties();
props.load(inputStream);
String groupByDataSourceValue = props.getProperty(KEY_GROUP_BY_DATA_SOURCE);
if (groupByDataSourceValue != null) {
switch (groupByDataSourceValue) {
case VALUE_TRUE:
groupItemsInTreeByDataSource = true;
break;
case VALUE_FALSE:
groupItemsInTreeByDataSource = false;
break;
default:
logger.log(Level.WARNING, String.format("Unexpected value '%s' for key '%s'. Using 'null' instead.",
groupByDataSourceValue, KEY_GROUP_BY_DATA_SOURCE));
groupItemsInTreeByDataSource = null;
break;
}
} else {
groupItemsInTreeByDataSource = null;
}
} catch (IOException ex) {
logger.log(Level.SEVERE, "Error reading settings file", ex);
}
}
}
/**
* Reset all values to their default states.
*/
private static void clear() {
groupItemsInTreeByDataSource = null;
}
/**
* Store case preferences in the settings file.
*/
private static void saveToStorage(Case currentCase) {
Path settingsFile = Paths.get(currentCase.getConfigDirectory(), SETTINGS_FILE); //NON-NLS
Properties props = new Properties();
if (groupItemsInTreeByDataSource != null) {
props.setProperty(KEY_GROUP_BY_DATA_SOURCE, (groupItemsInTreeByDataSource ? VALUE_TRUE : VALUE_FALSE));
}
try (OutputStream fos = Files.newOutputStream(settingsFile)) {
props.store(fos, ""); //NON-NLS
} catch (IOException ex) {
logger.log(Level.SEVERE, "Error writing settings file", ex);
}
}
}

View File

@ -850,7 +850,7 @@ public class SingleUserCaseConverter {
// content_tags
biggestPK = 0;
inputStatement = sqliteConnection.createStatement();
inputResultSet = inputStatement.executeQuery("SELECT * FROM content_tags"); //NON-NLS
inputResultSet = inputStatement.executeQuery("SELECT * FROM content_tags LEFT OUTER JOIN tsk_examiners ON content_tags.examiner_id = tsk_examiners.examiner_id"); //NON-NLS
while (inputResultSet.next()) {
outputStatement = postgreSQLConnection.createStatement();
@ -859,14 +859,14 @@ public class SingleUserCaseConverter {
if (value > biggestPK) {
biggestPK = value;
}
outputStatement.executeUpdate("INSERT INTO content_tags (tag_id, obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset, user_name) VALUES (" //NON-NLS
outputStatement.executeUpdate("INSERT INTO content_tags (tag_id, obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset, examiner_id) VALUES (" //NON-NLS
+ value + ","
+ inputResultSet.getLong(2) + ","
+ inputResultSet.getLong(3) + ",'"
+ inputResultSet.getString(4) + "',"
+ inputResultSet.getLong(5) + ","
+ inputResultSet.getLong(6) + ",'"
+ inputResultSet.getString(7)+ "')"); //NON-NLS
+ inputResultSet.getLong(6) + ","
+ inputResultSet.getInt(7) + ")"); //NON-NLS
} catch (SQLException ex) {
if (ex.getErrorCode() != 0) { // 0 if the entry already exists

View File

@ -31,7 +31,7 @@ import org.openide.util.Lookup;
iconBase = "org/sleuthkit/autopsy/casemodule/services/tag-options-panel-icon.png",
keywords = "#OptionsCategory_TagNames",
keywordsCategory = "CustomTagNames",
position = 11
position = 12
)
public final class TagsOptionsPanelController extends OptionsPanelController {

View File

@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.centralrepository;
import java.awt.event.ActionEvent;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.Action;
import org.apache.commons.lang.StringUtils;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.util.NbBundle.Messages;
@ -37,9 +39,9 @@ import org.sleuthkit.datamodel.AbstractFile;
* An AbstractAction to manage adding and modifying a Central Repository file
* instance comment.
*/
@Messages({"AddEditCentralRepoCommentAction.menuItemText.addEditCentralRepoComment=Add/Edit Central Repository Comment"})
@Messages({"AddEditCentralRepoCommentAction.menuItemText.addEditCentralRepoCommentEmptyFile=Add/Edit Central Repository Comment (Empty File)",
"AddEditCentralRepoCommentAction.menuItemText.addEditCentralRepoCommentNoMD5=Add/Edit Central Repository Comment (No MD5 Hash)",
"AddEditCentralRepoCommentAction.menuItemText.addEditCentralRepoComment=Add/Edit Central Repository Comment"})
public final class AddEditCentralRepoCommentAction extends AbstractAction {
private static final Logger logger = Logger.getLogger(AddEditCentralRepoCommentAction.class.getName());
@ -58,14 +60,19 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction {
*
*/
public AddEditCentralRepoCommentAction(AbstractFile file) {
super(Bundle.AddEditCentralRepoCommentAction_menuItemText_addEditCentralRepoComment());
fileId = file.getId();
correlationAttributeInstance = EamArtifactUtil.getInstanceFromContent(file);
if (correlationAttributeInstance == null) {
addToDatabase = true;
correlationAttributeInstance = EamArtifactUtil.makeInstanceFromContent(file);
}
if (file.getSize() == 0) {
putValue(Action.NAME, Bundle.AddEditCentralRepoCommentAction_menuItemText_addEditCentralRepoCommentEmptyFile());
} else if (StringUtils.isBlank(file.getMd5Hash())) {
putValue(Action.NAME, Bundle.AddEditCentralRepoCommentAction_menuItemText_addEditCentralRepoCommentNoMD5());
} else {
putValue(Action.NAME, Bundle.AddEditCentralRepoCommentAction_menuItemText_addEditCentralRepoComment());
}
}
/**

View File

@ -35,6 +35,7 @@
<EmptySpace min="0" pref="451" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="remainingCharactersLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="okButton" min="-2" pref="75" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
@ -53,10 +54,13 @@
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="jScrollPane1" max="32767" attributes="0"/>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="3" attributes="0">
<Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="okButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="remainingCharactersLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
</Group>
@ -108,5 +112,6 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="remainingCharactersLabel"></Component>
</SubComponents>
</Form>

View File

@ -18,8 +18,12 @@
*/
package org.sleuthkit.autopsy.centralrepository;
import javax.swing.text.AbstractDocument;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.WindowManager;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
/**
@ -37,7 +41,8 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog {
/**
* Create an instance.
*
* @param correlationAttributeInstance The correlation attribute to be modified.
* @param correlationAttributeInstance The correlation attribute to be
* modified.
*/
CentralRepoCommentDialog(CorrelationAttributeInstance correlationAttributeInstance) {
super(WindowManager.getDefault().getMainWindow(), Bundle.CentralRepoCommentDialog_title_addEditCentralRepoComment());
@ -51,6 +56,9 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog {
currentComment = instance.getComment();
}
//Truncate legacy comments to be MAX_CHARACTERS characters, pressing 'okay'
//once the editted comment is loaded in will truncate it in the database as
//well.
commentTextArea.setText(instance.getComment());
this.correlationAttributeInstance = correlationAttributeInstance;
@ -78,9 +86,8 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog {
}
/**
* Get the current comment.
* If the user hit OK, this will be the new comment.
* If the user canceled, this will be the original comment.
* Get the current comment. If the user hit OK, this will be the new
* comment. If the user canceled, this will be the original comment.
*
* @return the comment
*/
@ -88,6 +95,107 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog {
return currentComment;
}
/**
* Limits the number of characters that can go into the Comment JTextArea of
* this Dialog box.
*/
private class CentralRepoCommentLengthFilter extends DocumentFilter {
private final Integer MAX_CHARACTERS = 500;
private Integer remainingCharacters = MAX_CHARACTERS;
public CentralRepoCommentLengthFilter() {
updateLabel();
}
/**
* Truncates the insert string if its addition in the Comment dialog box
* will cause it to go past MAX_CHARACTERS in length.
*
* @param filter FilterBypass that can be used to mutate Document
* @param offset the offset into the document to insert the content >=
* 0. All positions that track change at or after the
* given location will move.
* @param input the string to insert
* @param attrSet the attributes to associate with the inserted content.
* This may be null if there are no attributes.
*
* @throws BadLocationException the given insert position is not a valid
* position within the document
*/
public void insertString(FilterBypass filter, int offset, String input,
AttributeSet attrSet) throws BadLocationException {
//Truncate the insert if its too long
this.replace(filter, offset, 0, input, attrSet);
}
/**
* Remove the number of characters from the Comment Text box and add
* back to our remaining count.
*
* @param filter FilterBypass that can be used to mutate Document
* @param offset the offset from the beginning >= 0
* @param length the number of characters to remove >= 0
*
* @throws BadLocationException some portion of the removal range was
* not a valid part of the document. The
* location in the exception is the first
* bad position encountered.
*/
public void remove(FilterBypass filter, int offset, int length)
throws BadLocationException {
super.remove(filter, offset, length);
remainingCharacters += length;
updateLabel();
}
/**
* Replace the current text at the offset position with the inputted
* text. If the offset is the end of the text box, then this functions
* like an append. Truncate this input if its addition will cause the
* Comment text box to be > MAX_CHARACTERS in length.
*
* @param filter FilterBypass that can be used to mutate Document
* @param offset Location in Document
* @param length Length of text to delete
* @param input Text to insert, null indicates no text to insert
* @param attrSet AttributeSet indicating attributes of inserted text,
* null is legal.
*
* @throws BadLocationException the given insert position is not a valid
* position within the document
*/
public void replace(FilterBypass filter, int offset, int length, String input,
AttributeSet attrSet) throws BadLocationException {
//Truncate the replace if its too long
String truncatedText = input;
if ((filter.getDocument().getLength() + input.length() - length) > MAX_CHARACTERS) {
truncatedText = input.substring(0, MAX_CHARACTERS -
filter.getDocument().getLength() - length);
}
super.replace(filter, offset, length, truncatedText, attrSet);
remainingCharacters -= truncatedText.length() - length;
updateLabel();
}
/**
* Updates the remainingCharactersLabel to reflect the current state.
* If there are no more characters left, a red 0 is displayed in the
* UI.
*/
private void updateLabel() {
if (remainingCharacters == 0) {
remainingCharactersLabel.setText(String.format(
"<html><font color=\"red\">%d</font> %s</html>",
remainingCharacters, "characters remaining"));
} else {
remainingCharactersLabel.setText(String.format(
"<html><font color=\"black\">%d</font> %s</html>",
remainingCharacters, "characters remaining"));
}
}
}
/**
* 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
@ -102,6 +210,7 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog {
okButton = new javax.swing.JButton();
cancelButton = new javax.swing.JButton();
commentLabel = new javax.swing.JLabel();
remainingCharactersLabel = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setSize(getPreferredSize());
@ -111,6 +220,8 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog {
commentTextArea.setRows(5);
commentTextArea.setTabSize(4);
commentTextArea.setWrapStyleWord(true);
((AbstractDocument)commentTextArea.getDocument())
.setDocumentFilter(new CentralRepoCommentLengthFilter());
jScrollPane1.setViewportView(commentTextArea);
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(CentralRepoCommentDialog.class, "CentralRepoCommentDialog.okButton.text")); // NOI18N
@ -141,7 +252,8 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog {
.addComponent(commentLabel)
.addGap(0, 451, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(remainingCharactersLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(okButton, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE)))
@ -155,9 +267,11 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog {
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(cancelButton)
.addComponent(okButton))
.addComponent(remainingCharactersLabel))
.addContainerGap())
);
@ -180,6 +294,7 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog {
private javax.swing.JButton cancelButton;
private javax.swing.JLabel commentLabel;
private javax.swing.JTextArea commentTextArea;
private javax.swing.JLabel remainingCharactersLabel;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JButton okButton;
// End of variables declaration//GEN-END:variables

View File

@ -18,6 +18,9 @@
*/
package org.sleuthkit.autopsy.centralrepository.datamodel;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
@ -34,6 +37,8 @@ import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.Case;
import static org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil.updateSchemaVersion;
@ -57,7 +62,21 @@ abstract class AbstractSqlEamDb implements EamDb {
private int bulkArtifactsCount;
protected int bulkArtifactsThreshold;
private final Map<String, Collection<CorrelationAttributeInstance>> bulkArtifacts;
private static final int CASE_CACHE_TIMEOUT = 5;
private static final int DATA_SOURCE_CACHE_TIMEOUT = 5;
private static final Cache<Integer, CorrelationAttributeInstance.Type> typeCache = CacheBuilder.newBuilder().build();
private static final Cache<String, CorrelationCase> caseCacheByUUID = CacheBuilder.newBuilder()
.expireAfterWrite(CASE_CACHE_TIMEOUT, TimeUnit.MINUTES).
build();
private static final Cache<Integer, CorrelationCase> caseCacheById = CacheBuilder.newBuilder()
.expireAfterWrite(CASE_CACHE_TIMEOUT, TimeUnit.MINUTES).
build();
private static final Cache<String, CorrelationDataSource> dataSourceCacheByDeviceId = CacheBuilder.newBuilder()
.expireAfterWrite(DATA_SOURCE_CACHE_TIMEOUT, TimeUnit.MINUTES).
build();
private static final Cache<String, CorrelationDataSource> dataSourceCacheById = CacheBuilder.newBuilder()
.expireAfterWrite(DATA_SOURCE_CACHE_TIMEOUT, TimeUnit.MINUTES).
build();
// Maximum length for the value column in the instance tables
static final int MAX_VALUE_LENGTH = 256;
@ -149,6 +168,17 @@ abstract class AbstractSqlEamDb implements EamDb {
return value;
}
/**
* Reset the contents of the caches associated with EamDb results.
*/
protected final void clearCaches() {
typeCache.invalidateAll();
caseCacheByUUID.invalidateAll();
caseCacheById.invalidateAll();
dataSourceCacheByDeviceId.invalidateAll();
dataSourceCacheById.invalidateAll();
}
/**
* Update the value for a name in the name/value db_info table.
*
@ -201,9 +231,9 @@ abstract class AbstractSqlEamDb implements EamDb {
+ "examiner_name, examiner_email, examiner_phone, notes) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) "
+ getConflictClause();
ResultSet resultSet = null;
try {
preparedStatement = conn.prepareStatement(sql);
preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
preparedStatement.setString(1, eamCase.getCaseUUID());
if (null == eamCase.getOrg()) {
@ -240,9 +270,21 @@ abstract class AbstractSqlEamDb implements EamDb {
}
preparedStatement.executeUpdate();
//update the case in the caches
resultSet = preparedStatement.getGeneratedKeys();
if (!resultSet.next()) {
throw new EamDbException(String.format("Failed to INSERT case %s in central repo", eamCase.getCaseUUID()));
}
int caseID = resultSet.getInt(1); //last_insert_rowid()
CorrelationCase correlationCase = new CorrelationCase(caseID, eamCase.getCaseUUID(), eamCase.getOrg(),
eamCase.getDisplayName(), eamCase.getCreationDate(), eamCase.getCaseNumber(), eamCase.getExaminerName(),
eamCase.getExaminerEmail(), eamCase.getExaminerPhone(), eamCase.getNotes());
caseCacheByUUID.put(eamCase.getCaseUUID(), correlationCase);
caseCacheById.put(caseID, correlationCase);
} catch (SQLException ex) {
throw new EamDbException("Error inserting new case.", ex); // NON-NLS
} finally {
EamDbUtil.closeResultSet(resultSet);
EamDbUtil.closeStatement(preparedStatement);
EamDbUtil.closeConnection(conn);
}
@ -339,6 +381,9 @@ abstract class AbstractSqlEamDb implements EamDb {
preparedStatement.setString(9, eamCase.getCaseUUID());
preparedStatement.executeUpdate();
//update the case in the cache
caseCacheById.put(eamCase.getID(), eamCase);
caseCacheByUUID.put(eamCase.getCaseUUID(), eamCase);
} catch (SQLException ex) {
throw new EamDbException("Error updating case.", ex); // NON-NLS
} finally {
@ -347,6 +392,25 @@ abstract class AbstractSqlEamDb implements EamDb {
}
}
/**
* Retrieves Case details based on Case UUID from the central repo
*
* @param caseUUID unique identifier for a case
*
* @return The retrieved case
*/
@Override
public CorrelationCase getCaseByUUID(String caseUUID) throws EamDbException {
try {
return caseCacheByUUID.get(caseUUID, () -> getCaseByUUIDFromCr(caseUUID));
} catch (CacheLoader.InvalidCacheLoadException ignored) {
//lambda valueloader returned a null value and cache can not store null values this is normal if the case does not exist in the central repo yet
return null;
} catch (ExecutionException ex) {
throw new EamDbException("Error getting autopsy case from Central repo", ex);
}
}
/**
* Retrieves Case details based on Case UUID
*
@ -354,10 +418,7 @@ abstract class AbstractSqlEamDb implements EamDb {
*
* @return The retrieved case
*/
@Override
public CorrelationCase getCaseByUUID(String caseUUID) throws EamDbException {
// @@@ We should have a cache here...
private CorrelationCase getCaseByUUIDFromCr(String caseUUID) throws EamDbException {
Connection conn = connect();
CorrelationCase eamCaseResult = null;
@ -377,6 +438,10 @@ abstract class AbstractSqlEamDb implements EamDb {
if (resultSet.next()) {
eamCaseResult = getEamCaseFromResultSet(resultSet);
}
if (eamCaseResult != null) {
//Update the version in the other cache
caseCacheById.put(eamCaseResult.getID(), eamCaseResult);
}
} catch (SQLException ex) {
throw new EamDbException("Error getting case details.", ex); // NON-NLS
} finally {
@ -397,8 +462,24 @@ abstract class AbstractSqlEamDb implements EamDb {
*/
@Override
public CorrelationCase getCaseById(int caseId) throws EamDbException {
// @@@ We should have a cache here...
try {
return caseCacheById.get(caseId, () -> getCaseByIdFromCr(caseId));
} catch (CacheLoader.InvalidCacheLoadException ignored) {
//lambda valueloader returned a null value and cache can not store null values this is normal if the case does not exist in the central repo yet
return null;
} catch (ExecutionException ex) {
throw new EamDbException("Error getting autopsy case from Central repo", ex);
}
}
/**
* Retrieves Case details based on Case ID
*
* @param caseID unique identifier for a case
*
* @return The retrieved case
*/
private CorrelationCase getCaseByIdFromCr(int caseId) throws EamDbException {
Connection conn = connect();
CorrelationCase eamCaseResult = null;
@ -410,7 +491,6 @@ abstract class AbstractSqlEamDb implements EamDb {
+ "FROM cases "
+ "LEFT JOIN organizations ON cases.org_id=organizations.id "
+ "WHERE cases.id=?";
try {
preparedStatement = conn.prepareStatement(sql);
preparedStatement.setInt(1, caseId);
@ -418,6 +498,10 @@ abstract class AbstractSqlEamDb implements EamDb {
if (resultSet.next()) {
eamCaseResult = getEamCaseFromResultSet(resultSet);
}
if (eamCaseResult != null) {
//Update the version in the other cache
caseCacheByUUID.put(eamCaseResult.getCaseUUID(), eamCaseResult);
}
} catch (SQLException ex) {
throw new EamDbException("Error getting case details.", ex); // NON-NLS
} finally {
@ -466,6 +550,32 @@ abstract class AbstractSqlEamDb implements EamDb {
return cases;
}
/**
* Create a key to the DataSourceCacheByDeviceId
*
* @param caseId - the id of the CorrelationCase in the Central
* Repository
* @param dataSourceDeviceId - the device Id of the data source
*
* @return a String to be used as a key for the dataSourceCacheByDeviceId
*/
private static String getDataSourceByDeviceIdCacheKey(int caseId, String dataSourceDeviceId) {
return "Case" + caseId + "DeviceId" + dataSourceDeviceId; //NON-NLS
}
/**
* Create a key to the DataSourceCacheById
*
* @param caseId - the id of the CorrelationCase in the Central
* Repository
* @param dataSourceId - the id of the datasource in the central repository
*
* @return a String to be used as a key for the dataSourceCacheById
*/
private static String getDataSourceByIdCacheKey(int caseId, int dataSourceId) {
return "Case" + caseId + "Id" + dataSourceId; //NON-NLS
}
/**
* Creates new Data Source in the database
*
@ -485,18 +595,27 @@ abstract class AbstractSqlEamDb implements EamDb {
String sql = "INSERT INTO data_sources(device_id, case_id, name) VALUES (?, ?, ?) "
+ getConflictClause();
ResultSet resultSet = null;
try {
preparedStatement = conn.prepareStatement(sql);
preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
preparedStatement.setString(1, eamDataSource.getDeviceID());
preparedStatement.setInt(2, eamDataSource.getCaseID());
preparedStatement.setString(3, eamDataSource.getName());
preparedStatement.executeUpdate();
resultSet = preparedStatement.getGeneratedKeys();
if (!resultSet.next()) {
throw new EamDbException(String.format("Failed to INSERT data source %s in central repo", eamDataSource.getName()));
}
int dataSourceId = resultSet.getInt(1); //last_insert_rowid()
CorrelationDataSource dataSource = new CorrelationDataSource(eamDataSource.getCaseID(), dataSourceId, eamDataSource.getDeviceID(), eamDataSource.getName());
dataSourceCacheByDeviceId.put(getDataSourceByDeviceIdCacheKey(dataSource.getCaseID(), dataSource.getDeviceID()), dataSource);
dataSourceCacheById.put(getDataSourceByIdCacheKey(dataSource.getCaseID(), dataSource.getID()), dataSource);
} catch (SQLException ex) {
throw new EamDbException("Error inserting new data source.", ex); // NON-NLS
} finally {
EamDbUtil.closeResultSet(resultSet);
EamDbUtil.closeStatement(preparedStatement);
EamDbUtil.closeConnection(conn);
}
@ -510,13 +629,38 @@ abstract class AbstractSqlEamDb implements EamDb {
* @param dataSourceDeviceId the data source device ID number
*
* @return The data source
*
* @throws EamDbException
*/
@Override
public CorrelationDataSource getDataSource(CorrelationCase correlationCase, String dataSourceDeviceId) throws EamDbException {
if (correlationCase == null) {
throw new EamDbException("Correlation case is null");
}
try {
return dataSourceCacheByDeviceId.get(getDataSourceByDeviceIdCacheKey(correlationCase.getID(), dataSourceDeviceId), () -> getDataSourceFromCr(correlationCase, dataSourceDeviceId));
} catch (CacheLoader.InvalidCacheLoadException ignored) {
//lambda valueloader returned a null value and cache can not store null values this is normal if the dataSource does not exist in the central repo yet
return null;
} catch (ExecutionException ex) {
throw new EamDbException("Error getting data source from central repository", ex);
}
}
/**
* Gets the Data Source details based on data source device ID from the
* central repository.
*
* @param correlationCase the current CorrelationCase used for ensuring
* uniqueness of DataSource
* @param dataSourceDeviceId the data source device ID number
*
* @return The data source
*
* @throws EamDbException
*/
private CorrelationDataSource getDataSourceFromCr(CorrelationCase correlationCase, String dataSourceDeviceId) throws EamDbException {
Connection conn = connect();
CorrelationDataSource eamDataSourceResult = null;
@ -533,6 +677,9 @@ abstract class AbstractSqlEamDb implements EamDb {
if (resultSet.next()) {
eamDataSourceResult = getEamDataSourceFromResultSet(resultSet);
}
if (eamDataSourceResult != null) {
dataSourceCacheById.put(getDataSourceByIdCacheKey(correlationCase.getID(), eamDataSourceResult.getID()), eamDataSourceResult);
}
} catch (SQLException ex) {
throw new EamDbException("Error getting data source.", ex); // NON-NLS
} finally {
@ -558,7 +705,26 @@ abstract class AbstractSqlEamDb implements EamDb {
if (correlationCase == null) {
throw new EamDbException("Correlation case is null");
}
try {
return dataSourceCacheById.get(getDataSourceByIdCacheKey(correlationCase.getID(), dataSourceId), () -> getDataSourceByIdFromCr(correlationCase, dataSourceId));
} catch (CacheLoader.InvalidCacheLoadException ignored) {
//lambda valueloader returned a null value and cache can not store null values this is normal if the dataSource does not exist in the central repo yet
return null;
} catch (ExecutionException ex) {
throw new EamDbException("Error getting data source from central repository", ex);
}
}
/**
* Retrieves Data Source details based on data source ID
*
* @param correlationCase the current CorrelationCase used for ensuring
* uniqueness of DataSource
* @param dataSourceId the data source ID number
*
* @return The data source
*/
private CorrelationDataSource getDataSourceByIdFromCr(CorrelationCase correlationCase, int dataSourceId) throws EamDbException {
Connection conn = connect();
CorrelationDataSource eamDataSourceResult = null;
@ -575,6 +741,9 @@ abstract class AbstractSqlEamDb implements EamDb {
if (resultSet.next()) {
eamDataSourceResult = getEamDataSourceFromResultSet(resultSet);
}
if (eamDataSourceResult != null) {
dataSourceCacheByDeviceId.put(getDataSourceByDeviceIdCacheKey(correlationCase.getID(), eamDataSourceResult.getDeviceID()), eamDataSourceResult);
}
} catch (SQLException ex) {
throw new EamDbException("Error getting data source.", ex); // NON-NLS
} finally {
@ -1895,6 +2064,7 @@ abstract class AbstractSqlEamDb implements EamDb {
* @param type EamArtifact.Type to search for
* @param instanceTableCallback callback to process the instance
* @param whereClause query string to execute
*
* @throws EamDbException
*/
@Override
@ -2279,7 +2449,8 @@ abstract class AbstractSqlEamDb implements EamDb {
* Add a new reference instance
*
* @param eamGlobalFileInstance The reference instance to add
* @param correlationType Correlation Type that this Reference Instance is
* @param correlationType Correlation Type that this Reference
* Instance is
*
* @throws EamDbException
*/
@ -2694,7 +2865,7 @@ abstract class AbstractSqlEamDb implements EamDb {
preparedStatement.setInt(4, aType.isEnabled() ? 1 : 0);
preparedStatement.setInt(5, aType.getId());
preparedStatement.executeUpdate();
typeCache.put(aType.getId(), aType);
} catch (SQLException ex) {
throw new EamDbException("Error updating correlation type.", ex); // NON-NLS
} finally {
@ -2715,6 +2886,26 @@ abstract class AbstractSqlEamDb implements EamDb {
*/
@Override
public CorrelationAttributeInstance.Type getCorrelationTypeById(int typeId) throws EamDbException {
try {
return typeCache.get(typeId, () -> getCorrelationTypeByIdFromCr(typeId));
} catch (CacheLoader.InvalidCacheLoadException ignored) {
//lambda valueloader returned a null value and cache can not store null values this is normal if the correlation type does not exist in the central repo yet
return null;
} catch (ExecutionException ex) {
throw new EamDbException("Error getting correlation type", ex);
}
}
/**
* Get the EamArtifact.Type that has the given Type.Id from the central repo
*
* @param typeId Type.Id of Correlation Type to get
*
* @return EamArtifact.Type or null if it doesn't exist.
*
* @throws EamDbException
*/
private CorrelationAttributeInstance.Type getCorrelationTypeByIdFromCr(int typeId) throws EamDbException {
Connection conn = connect();
CorrelationAttributeInstance.Type aType;

View File

@ -283,7 +283,7 @@ public class CorrelationAttributeInstance implements Serializable {
/**
*
* @param id Unique ID for this Correlation Type
* @param typeId Unique ID for this Correlation Type
* @param displayName Name of this type displayed in the UI.
* @param dbTableName Central repository db table where data of this
* type is stored. Must start with a lowercase letter and only contain
@ -387,7 +387,7 @@ public class CorrelationAttributeInstance implements Serializable {
}
/**
* @param id the typeId to set
* @param typeId the typeId to set
*/
public void setId(int typeId) {
this.typeId = typeId;

View File

@ -55,8 +55,6 @@ public class EamArtifactUtil {
* null.
*
* @param bbArtifact BlackboardArtifact to examine
* @param addInstanceDetails If true, add instance details from bbArtifact
* into the returned structure
* @param checkEnabled If true, only create a CorrelationAttribute if it is
* enabled
*
@ -129,7 +127,10 @@ public class EamArtifactUtil {
|| BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID() == artifactTypeID)) {
// Lower-case this to normalize domains
value = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN)).getValueString();
BlackboardAttribute attribute = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN));
if (attribute != null) {
value = attribute.getValueString();
}
} else if (correlationType.getId() == CorrelationAttributeInstance.PHONE_TYPE_ID
&& (BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID() == artifactTypeID
|| BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() == artifactTypeID
@ -173,7 +174,7 @@ public class EamArtifactUtil {
return null;
}
if (null != value) {
if ((null != value) && (value.isEmpty() == false)) {
return makeCorrelationAttributeInstanceUsingTypeValue(bbArtifact, correlationType, value);
} else {
return null;

View File

@ -178,7 +178,7 @@ public interface EamDb {
/**
* Retrieves Case details based on Case ID
*
* @param caseID unique identifier for a case
* @param caseId unique identifier for a case
*
* @return The retrieved case
*/

View File

@ -1,7 +1,7 @@
/*
* Central Repository
*
* Copyright 2015-2017 Basis Technology Corp.
* Copyright 2015-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -78,6 +78,7 @@ final class PostgresEamDb extends AbstractSqlEamDb {
connectionPool.close();
connectionPool = null; // force it to be re-created on next connect()
}
clearCaches();
}
} catch (SQLException ex) {
throw new EamDbException("Failed to close existing database connections.", ex); // NON-NLS

View File

@ -1,7 +1,7 @@
/*
* Central Repository
*
* Copyright 2015-2017 Basis Technology Corp.
* Copyright 2015-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -85,6 +85,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
connectionPool.close();
connectionPool = null; // force it to be re-created on next connect()
}
clearCaches();
}
} catch (SQLException ex) {
throw new EamDbException("Failed to close existing database connections.", ex); // NON-NLS

View File

@ -42,7 +42,7 @@ public class IngestModuleFactory extends IngestModuleFactoryAdapter {
*
* @return The module name.
*/
static String getModuleName() {
public static String getModuleName() {
return Bundle.IngestModuleFactory_ingestmodule_name();
}

View File

@ -75,3 +75,4 @@ ShowCasesDialog.title=Case Details
GlobalSettingsPanel.Case\ Details.AccessibleContext.accessibleName=Cases Details
ShowCasesDialog.caseDetailsTable.AccessibleContext.accessibleDescription=Click column name to sort.
GlobalSettingsPanel.casesTextArea.text=Display table that lists central repository case details.
GlobalSettingsPanel.ingestRunningWarningLabel.text=Cannot make changes to central repository settings when ingest is running!

View File

@ -35,7 +35,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
*/
@OptionsPanelController.TopLevelRegistration(categoryName = "#OptionsCategory_Name_Central_Repository_Options",
iconBase = "org/sleuthkit/autopsy/centralrepository/images/options-icon.png",
position = 14,
position = 15,
keywords = "#OptionsCategory_Keywords_Central_Repository_Options",
keywordsCategory = "CentralRepository")
public final class EamOptionsPanelController extends OptionsPanelController {

View File

@ -27,7 +27,7 @@
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane1" alignment="0" pref="517" max="32767" attributes="0"/>
<Component id="jScrollPane1" alignment="0" pref="512" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
@ -61,21 +61,20 @@
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="pnDatabaseConfiguration" alignment="0" max="32767" attributes="0"/>
<Component id="pnCorrelationProperties" alignment="0" pref="1016" max="32767" attributes="0"/>
<Component id="pnCorrelationProperties" alignment="0" pref="1012" max="32767" attributes="0"/>
<Component id="organizationPanel" alignment="1" max="32767" attributes="0"/>
<Component id="casesPanel" alignment="0" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="cbUseCentralRepo" min="-2" max="-2" attributes="0"/>
<Component id="cbUseCentralRepo" min="-2" pref="162" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="ingestRunningWarningLabel" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="tbOops" min="-2" pref="974" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -84,7 +83,10 @@
<Group type="102" alignment="0" attributes="0">
<Component id="lbCentralRepository" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cbUseCentralRepo" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="cbUseCentralRepo" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="ingestRunningWarningLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="pnDatabaseConfiguration" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
@ -512,6 +514,21 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="ingestRunningWarningLabel">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true">
<Font bold="false" component="ingestRunningWarningLabel" property="font" relativeSize="false" size="11"/>
</FontInfo>
</Property>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/modules/filetypeid/warning16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.ingestRunningWarningLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>

View File

@ -129,6 +129,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
casesScrollPane = new javax.swing.JScrollPane();
casesTextArea = new javax.swing.JTextArea();
tbOops = new javax.swing.JTextField();
ingestRunningWarningLabel = new javax.swing.JLabel();
setName(""); // NOI18N
setPreferredSize(new java.awt.Dimension(1022, 488));
@ -347,6 +348,10 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
tbOops.setText(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.tbOops.text")); // NOI18N
tbOops.setBorder(null);
ingestRunningWarningLabel.setFont(ingestRunningWarningLabel.getFont().deriveFont(ingestRunningWarningLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
ingestRunningWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/modules/filetypeid/warning16.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(ingestRunningWarningLabel, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.ingestRunningWarningLabel.text")); // NOI18N
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
@ -355,24 +360,26 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
.addGroup(jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(pnCorrelationProperties, javax.swing.GroupLayout.DEFAULT_SIZE, 1016, Short.MAX_VALUE)
.addComponent(pnCorrelationProperties, javax.swing.GroupLayout.DEFAULT_SIZE, 1012, Short.MAX_VALUE)
.addComponent(organizationPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(casesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
.addComponent(casesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(cbUseCentralRepo)
.addComponent(cbUseCentralRepo, javax.swing.GroupLayout.PREFERRED_SIZE, 162, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(ingestRunningWarningLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, 974, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGap(0, 0, Short.MAX_VALUE))
.addContainerGap())
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(lbCentralRepository)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(cbUseCentralRepo)
.addComponent(ingestRunningWarningLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@ -398,7 +405,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 517, Short.MAX_VALUE)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 512, Short.MAX_VALUE)
);
}// </editor-fold>//GEN-END:initComponents
@ -555,6 +562,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
if (IngestManager.getInstance().isIngestRunning()) {
tbOops.setText(Bundle.GlobalSettingsPanel_validationErrMsg_ingestRunning());
tbOops.setVisible(true);
cbUseCentralRepo.setEnabled(false);
enableAllSubComponents(false);
} else if (!cbUseCentralRepo.isEnabled()) {
@ -586,6 +594,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
*/
private void enableDatabaseConfigureButton(Boolean enable) {
boolean ingestRunning = IngestManager.getInstance().isIngestRunning();
ingestRunningWarningLabel.setVisible(ingestRunning);
pnDatabaseConfiguration.setEnabled(enable && !ingestRunning);
bnDbConfigure.setEnabled(enable && !ingestRunning);
lbDbLocationLabel.setEnabled(enable && !ingestRunning);
@ -628,6 +637,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
private javax.swing.JCheckBox cbUseCentralRepo;
private javax.swing.JScrollPane correlationPropertiesScrollPane;
private javax.swing.JTextArea correlationPropertiesTextArea;
private javax.swing.JLabel ingestRunningWarningLabel;
private javax.swing.JPanel jPanel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JLabel lbCentralRepository;

View File

@ -33,36 +33,31 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Prototype for an object which finds files with common attributes.
* Subclass this and implement findMatches in order
* Prototype for an object which finds files with common attributes. Subclass
* this and implement findMatches in order
*/
public abstract class AbstractCommonAttributeSearcher {
private final Map<Long, String> dataSourceIdToNameMap;
private boolean filterByMedia;
private boolean filterByDoc;
final int frequencyPercentageThreshold;
AbstractCommonAttributeSearcher(Map<Long, String> dataSourceIdMap, boolean filterByMedia, boolean filterByDoc, int percentageThreshold){
AbstractCommonAttributeSearcher(boolean filterByMedia, boolean filterByDoc, int percentageThreshold) {
this.filterByDoc = filterByDoc;
this.filterByMedia = filterByMedia;
this.dataSourceIdToNameMap = dataSourceIdMap;
this.frequencyPercentageThreshold = percentageThreshold;
}
Map<Long, String> getDataSourceIdToNameMap(){
return Collections.unmodifiableMap(this.dataSourceIdToNameMap);
}
/**
* Implement this to search for files with common attributes. Creates an
* object (CommonAttributeSearchResults) which contains all of the information
* required to display a tree view in the UI. The view will contain 3 layers:
* a top level node, indicating the number matches each of it's children possess,
* a mid level node indicating the matched attribute,
* object (CommonAttributeSearchResults) which contains all of the
* information required to display a tree view in the UI. The view will
* contain 3 layers: a top level node, indicating the number matches each of
* it's children possess, a mid level node indicating the matched attribute,
*
* @return
*
* @throws TskCoreException
* @throws NoCurrentCaseException
* @throws SQLException
@ -71,17 +66,12 @@ public abstract class AbstractCommonAttributeSearcher {
public abstract CommonAttributeSearchResults findMatches() throws TskCoreException, NoCurrentCaseException, SQLException, EamDbException;
/**
* Implement this to create a descriptive string for the tab which will display
* this data.
* Implement this to create a descriptive string for the tab which will
* display this data.
*
* @return an informative string
*/
@NbBundle.Messages({
"AbstractCommonFilesMetadataBuilder.buildTabTitle.titleIntraAll=Common Attributes (All Data Sources, %s)",
"AbstractCommonFilesMetadataBuilder.buildTabTitle.titleIntraSingle=Common Attributes (Data Source: %s, %s)",
"AbstractCommonFilesMetadataBuilder.buildTabTitle.titleInterAll=Common Attributes (All Central Repository Cases, %s)",
"AbstractCommonFilesMetadataBuilder.buildTabTitle.titleInterSingle=Common Attributes (Central Repository Case: %s, %s)",
})
abstract String buildTabTitle();
abstract String getTabTitle();
@NbBundle.Messages({
"AbstractCommonFilesMetadataBuilder.buildCategorySelectionString.doc=Documents",
@ -104,6 +94,24 @@ public abstract class AbstractCommonAttributeSearcher {
}
}
/**
* Get the portion of the title that will display the frequency percentage
* threshold. Items that existed in over this percent of data sources were
* ommited from the results.
*
* @return A string providing the frequency percentage threshold, or an empty string if no threshold was set
*/
@NbBundle.Messages({
"# {0} - threshold percent",
"AbstractCommonFilesMetadataBuilder.getPercentFilter.thresholdPercent=, Threshold {0}%"})
String getPercentThresholdString() {
if (frequencyPercentageThreshold == 0) {
return "";
} else {
return Bundle.AbstractCommonFilesMetadataBuilder_getPercentFilter_thresholdPercent(frequencyPercentageThreshold);
}
}
static Map<Integer, CommonAttributeValueList> collateMatchesByNumberOfInstances(Map<String, CommonAttributeValue> commonFiles) {
//collate matches by number of matching instances - doing this in sql doesnt seem efficient
Map<Integer, CommonAttributeValueList> instanceCollatedCommonFiles = new TreeMap<>();
@ -124,10 +132,10 @@ public abstract class AbstractCommonAttributeSearcher {
/*
* The set of the MIME types that will be checked for extension mismatches
* when checkType is ONLY_MEDIA.
* ".jpg", ".jpeg", ".png", ".psd", ".nef", ".tiff", ".bmp", ".tec"
* ".aaf", ".3gp", ".asf", ".avi", ".m1v", ".m2v", //NON-NLS
* ".m4v", ".mp4", ".mov", ".mpeg", ".mpg", ".mpe", ".mp4", ".rm", ".wmv", ".mpv", ".flv", ".swf"
* when checkType is ONLY_MEDIA. ".jpg", ".jpeg", ".png", ".psd", ".nef",
* ".tiff", ".bmp", ".tec" ".aaf", ".3gp", ".asf", ".avi", ".m1v", ".m2v",
* //NON-NLS ".m4v", ".mp4", ".mov", ".mpeg", ".mpg", ".mpe", ".mp4", ".rm",
* ".wmv", ".mpv", ".flv", ".swf"
*/
static final Set<String> MEDIA_PICS_VIDEO_MIME_TYPES = Stream.of(
"image/bmp", //NON-NLS
@ -157,11 +165,9 @@ public abstract class AbstractCommonAttributeSearcher {
/*
* The set of the MIME types that will be checked for extension mismatches
* when checkType is ONLY_TEXT_FILES.
* ".doc", ".docx", ".odt", ".xls", ".xlsx", ".ppt", ".pptx"
* ".txt", ".rtf", ".log", ".text", ".xml"
* ".html", ".htm", ".css", ".js", ".php", ".aspx"
* ".pdf"
* when checkType is ONLY_TEXT_FILES. ".doc", ".docx", ".odt", ".xls",
* ".xlsx", ".ppt", ".pptx" ".txt", ".rtf", ".log", ".text", ".xml" ".html",
* ".htm", ".css", ".js", ".php", ".aspx" ".pdf"
*/
static final Set<String> TEXT_FILES_MIME_TYPES = Stream.of(
"text/plain", //NON-NLS

View File

@ -20,12 +20,16 @@
package org.sleuthkit.autopsy.commonfilesearch;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance.Type;
import static org.sleuthkit.autopsy.commonfilesearch.AbstractCommonAttributeSearcher.MEDIA_PICS_VIDEO_MIME_TYPES;
/**
* Algorithm which finds files anywhere in the Central Repo which also occur in
@ -39,22 +43,41 @@ public class AllInterCaseCommonAttributeSearcher extends InterCaseCommonAttribut
* broadly categorized as media types
* @param filterByDocMimeType match only on files whose mime types can be
* broadly categorized as document types
* @param corAttrType attribute type
* @param percentageThreshold omit any matches with frequency above this
* threshold
*
* @throws EamDbException
*/
public AllInterCaseCommonAttributeSearcher(Map<Long, String> dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType, Type corAttrType, int percentageThreshold) throws EamDbException {
super(dataSourceIdMap, filterByMediaMimeType, filterByDocMimeType, corAttrType, percentageThreshold);
public AllInterCaseCommonAttributeSearcher(boolean filterByMediaMimeType, boolean filterByDocMimeType, Type corAttrType, int percentageThreshold) throws EamDbException {
super(filterByMediaMimeType, filterByDocMimeType, corAttrType, percentageThreshold);
}
@Override
public CommonAttributeSearchResults findMatches() throws TskCoreException, NoCurrentCaseException, SQLException, EamDbException {
InterCaseSearchResultsProcessor eamDbAttrInst = new InterCaseSearchResultsProcessor(this.getDataSourceIdToNameMap(), corAttrType);
InterCaseSearchResultsProcessor eamDbAttrInst = new InterCaseSearchResultsProcessor(corAttrType);
Map<Integer, CommonAttributeValueList> interCaseCommonFiles = eamDbAttrInst.findInterCaseCommonAttributeValues(Case.getCurrentCase());
return new CommonAttributeSearchResults(interCaseCommonFiles, this.frequencyPercentageThreshold, this.corAttrType);
Set<String> mimeTypesToFilterOn = new HashSet<>();
if (isFilterByMedia()) {
mimeTypesToFilterOn.addAll(MEDIA_PICS_VIDEO_MIME_TYPES);
}
if (isFilterByDoc()) {
mimeTypesToFilterOn.addAll(TEXT_FILES_MIME_TYPES);
}
return new CommonAttributeSearchResults(interCaseCommonFiles, this.frequencyPercentageThreshold, this.corAttrType, mimeTypesToFilterOn);
}
@NbBundle.Messages({
"# {0} - attr type",
"# {1} - threshold string",
"AllInterCaseCommonAttributeSearcher.buildTabTitle.titleInterAll=Common Properties (All Central Repository Cases, {0}{1})"})
@Override
String buildTabTitle() {
final String titleTemplate = Bundle.AbstractCommonFilesMetadataBuilder_buildTabTitle_titleInterAll();
return String.format(titleTemplate, new Object[]{this.corAttrType.getDisplayName()});
String getTabTitle() {
String typeString = this.corAttrType.getDisplayName();
if (typeString.equals("Files")) {
typeString = this.buildCategorySelectionString();
}
return Bundle.AllInterCaseCommonAttributeSearcher_buildTabTitle_titleInterAll(typeString, this.getPercentThresholdString());
}
}

View File

@ -20,6 +20,7 @@
package org.sleuthkit.autopsy.commonfilesearch;
import java.util.Map;
import org.openide.util.NbBundle;
import org.sleuthkit.datamodel.TskData.FileKnown;
/**
@ -34,8 +35,11 @@ final public class AllIntraCaseCommonAttributeSearcher extends IntraCaseCommonAt
* sources.
*
* @param dataSourceIdMap a map of obj_id to datasource name
* @param filterByMediaMimeType match only on files whose mime types can be broadly categorized as media types
* @param filterByDocMimeType match only on files whose mime types can be broadly categorized as document types
* @param filterByMediaMimeType match only on files whose mime types can be
* broadly categorized as media types
* @param filterByDocMimeType match only on files whose mime types can be
* broadly categorized as document types
* @param percentageThreshold omit any matches with frequency above this threshold
*/
public AllIntraCaseCommonAttributeSearcher(Map<Long, String> dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType, int percentageThreshold) {
super(dataSourceIdMap, filterByMediaMimeType, filterByDocMimeType, percentageThreshold);
@ -48,10 +52,13 @@ final public class AllIntraCaseCommonAttributeSearcher extends IntraCaseCommonAt
return String.format(WHERE_CLAUSE, args);
}
@NbBundle.Messages({
"# {0} - build category",
"# {1} - threshold string",
"AllIntraCaseCommonAttributeSearcher.buildTabTitle.titleIntraAll=Common Properties (All Data Sources, {0}{1})"
})
@Override
String buildTabTitle() {
final String buildCategorySelectionString = this.buildCategorySelectionString();
final String titleTemplate = Bundle.AbstractCommonFilesMetadataBuilder_buildTabTitle_titleIntraAll();
return String.format(titleTemplate, new Object[]{buildCategorySelectionString});
String getTabTitle() {
return Bundle.AllIntraCaseCommonAttributeSearcher_buildTabTitle_titleIntraAll(this.buildCategorySelectionString(), this.getPercentThresholdString());
}
}

View File

@ -1,37 +1,42 @@
CommonFilesPanel.commonFilesSearchLabel.text=<html>Find files in multiple data sources in the current case.</html>
CommonFilesPanel.text=Indicate which data sources to consider while searching for duplicates:
CommonFilesPanel.jRadioButton1.text=jRadioButton1
CommonFilesPanel.jRadioButton2.text=With previous cases in the Central Repository
CommonFilesPanel.jRadioButton2.text=Between current case and cases in Central Repository
CommonFilesPanel.intraCaseRadio.label=Correlate within current case only
CommonFilesPanel.interCaseRadio.label=Correlate amongst all known cases (uses Central Repo)
IntraCasePanel.allDataSourcesRadioButton.text=Matches may be from any data source
IntraCasePanel.withinDataSourceRadioButton.text=At least one match must appear in the data source selected below:
IntraCasePanel.selectDataSourceComboBox.actionCommand=
InterCasePanel.specificCentralRepoCaseRadio.text=Matches must be from the following Central Repo case:
InterCasePanel.anyCentralRepoCaseRadio.text=Matches may be from any Central Repo case
CommonAttributePanel.jCheckBox1.text=Hide files found in over
CommonAttributePanel.jLabel1.text=% of data sources in central repository.
CommonAttributePanel.percentageThresholdTextTwo.text_1=% of data sources in central repository.
CommonAttributePanel.percentageThresholdTextOne.text=20
CommonAttributePanel.percentageThresholdCheck.text_1=Hide files found in over
CommonAttributePanel.intraCaseRadio.text=Within current case
CommonAttributePanel.commonFilesSearchLabel1.text=<html>Find common files to correlate data soures or cases.</html>
CommonAttributePanel.errorText.text=<html>In order to search, you must select a file category.</html>
CommonAttributePanel.categoriesLabel.text=File Types To Include:
CommonAttributePanel.documentsCheckbox.text=Documents
CommonAttributePanel.pictureVideoCheckbox.text=Pictures and Videos
CommonAttributePanel.selectedFileCategoriesButton.toolTipText=Select from the options below...
CommonAttributePanel.selectedFileCategoriesButton.text=Only the selected file types:
CommonAttributePanel.allFileCategoriesRadioButton.toolTipText=No filtering applied to results...
CommonAttributePanel.allFileCategoriesRadioButton.text=All file types
CommonAttributePanel.cancelButton.actionCommand=Cancel
CommonAttributePanel.cancelButton.text=Cancel
CommonAttributePanel.searchButton.text=Search
CommonAttributePanel.jCheckBox1.text=Hide files found in over
CommonAttributePanel.jLabel1.text=% of data sources in central repository.
CommonAttributePanel.percentageThreshold.text=20
CommonAttributePanel.jLabel1.text_1=% of data sources in central repository.
CommonAttributePanel.percentageThresholdCheck.text_1=Hide files found in over
InterCasePanel.comboBoxLabel.text=Select correlation type to search:
InterCasePanel.correlationTypeComboBox.toolTipText=Selected Correlation Type
CommonAttributePanel.commonFilesSearchLabel2.text=Scope of Search
IntraCasePanel.selectedFileCategoriesButton.text=Only the selected file types:
IntraCasePanel.categoriesLabel.text=File Types to Show:
IntraCasePanel.allFileCategoriesRadioButton.toolTipText=No filtering applied to results...
IntraCasePanel.allFileCategoriesRadioButton.text=All file types
IntraCasePanel.documentsCheckbox.text=Documents
IntraCasePanel.pictureVideoCheckbox.text=Pictures and Videos
IntraCasePanel.selectedFileCategoriesButton.toolTipText=Select from the options below...
CommonAttributePanel.percentageThresholdTextTwo.text_1=% of data sources in Central Repository.
CommonAttributePanel.percentageThresholdCheck.text_1_1=Hide items found in over
CommonAttributePanel.intraCaseRadio.text=Between data sources in current case
CommonAttributePanel.errorText.text=<html>In order to search, you must select a file category.</html>
CommonAttributePanel.searchButton.text=Search
InterCasePanel.categoriesLabel.text=File Types To Show:
InterCasePanel.documentsCheckbox.text=Documents
InterCasePanel.pictureVideoCheckbox.text=Pictures and Videos
InterCasePanel.selectedFileCategoriesButton.toolTipText=Select from the options below...
InterCasePanel.selectedFileCategoriesButton.text=Only the selected file types:
InterCasePanel.allFileCategoriesRadioButton.toolTipText=No filtering applied to results...
InterCasePanel.allFileCategoriesRadioButton.text=All file types
InterCasePanel.specificCentralRepoCaseCheckbox.text=Common items need to exist in a specific case:
IntraCasePanel.onlySpecificDataSourceCheckbox.text=Common items need to exist in a specific data source:
CommonAttributePanel.interCasePanel.border.title=Central Repository Options
CommonAttributePanel.intraCasePanel.border.title=Current Case Options
CommonAttributePanel.commonItemSearchDescription.text=<html>Find items that exist in multiple data sources or cases</html>
CommonAttributePanel.scopeLabel.text=Scope of Search:
InterCasePanel.correlationComboBoxLabel.text=Property Type to Match:
CommonAttributePanel.percentageThresholdInputBox.text=20

View File

@ -22,6 +22,8 @@ import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.openide.nodes.Sheet;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
@ -47,7 +49,7 @@ public class CaseDBCommonAttributeInstanceNode extends FileNode {
*
*/
public CaseDBCommonAttributeInstanceNode(AbstractFile fsContent, String caseName, String dataSource) {
super(fsContent);
super(fsContent, false);
this.caseName = caseName;
this.dataSource = dataSource;
}
@ -84,16 +86,21 @@ public class CaseDBCommonAttributeInstanceNode extends FileNode {
final String NO_DESCR = Bundle.CommonFilesSearchResultsViewerTable_noDescText();
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), NO_DESCR, this.getContent().getName()));
CorrelationAttributeInstance correlationAttribute = getCorrelationAttributeInstance();
this.addScoreProperty(sheetSet, tags);
this.addCommentProperty(sheetSet, tags, correlationAttribute);
this.addCountProperty(sheetSet, correlationAttribute);
addScoreProperty(sheetSet, tags);
CorrelationAttributeInstance correlationAttribute = null;
if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
correlationAttribute = getCorrelationAttributeInstance();
}
addCommentProperty(sheetSet, tags, correlationAttribute);
if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
addCountProperty(sheetSet, correlationAttribute);
}
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), NO_DESCR, this.getContent().getParentPath()));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), NO_DESCR, getHashSetHitsCsvList(this.getContent())));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), NO_DESCR, this.getDataSource()));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), NO_DESCR, StringUtils.defaultString(this.getContent().getMIMEType())));
this.addTagProperty(sheetSet, tags);
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_caseColLbl1(), Bundle.CommonFilesSearchResultsViewerTable_caseColLbl1(), NO_DESCR, caseName));
return sheet;
}

View File

@ -21,9 +21,8 @@ package org.sleuthkit.autopsy.commonfilesearch;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
@ -31,6 +30,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeIns
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
@ -45,12 +45,10 @@ final public class CentralRepoCommonAttributeInstance extends AbstractCommonAttr
private final Integer crFileId;
private CorrelationAttributeInstance currentAttribute;
private final CorrelationAttributeInstance.Type correlationType;
private final Map<String, Long> dataSourceNameToIdMap;
CentralRepoCommonAttributeInstance(Integer attrInstId, Map<Long, String> dataSourceIdToNameMap, CorrelationAttributeInstance.Type correlationType) {
CentralRepoCommonAttributeInstance(Integer attrInstId, CorrelationAttributeInstance.Type correlationType) {
super();
this.crFileId = attrInstId;
this.dataSourceNameToIdMap = invertMap(dataSourceIdToNameMap);
this.correlationType = correlationType;
}
@ -71,22 +69,35 @@ final public class CentralRepoCommonAttributeInstance extends AbstractCommonAttr
final CorrelationAttributeInstance currentAttributeInstance = this.currentAttribute;
String currentFullPath = currentAttributeInstance.getFilePath();
String currentDataSource = currentAttributeInstance.getCorrelationDataSource().getName();
if (this.dataSourceNameToIdMap.containsKey(currentDataSource)) {
Long dataSourceObjectId = this.dataSourceNameToIdMap.get(currentDataSource);
try {
String currentFullPath = currentAttributeInstance.getFilePath();
currentCase = Case.getCurrentCaseThrows();
// Only attempt to make the abstract file if the attribute is from the current case
if (currentCase.getName().equals(currentAttributeInstance.getCorrelationCase().getCaseUUID())) {
SleuthkitCase tskDb = currentCase.getSleuthkitCase();
// Find the correct data source
Optional<DataSource> dataSource = tskDb.getDataSources().stream()
.filter(p -> p.getDeviceId().equals(currentAttribute.getCorrelationDataSource().getDeviceID()))
.findFirst();
if (!dataSource.isPresent()) {
LOGGER.log(Level.WARNING, String.format("Unable to find data source with device ID %s in the current case", currentAttribute.getCorrelationDataSource().getDeviceID()));
return null;
}
File fileFromPath = new File(currentFullPath);
String fileName = fileFromPath.getName();
String parentPath = (fileFromPath.getParent() + File.separator).replace("\\", "/");
final String whereClause = String.format("lower(name) = '%s' AND md5 = '%s' AND lower(parent_path) = '%s' AND data_source_obj_id = %s", fileName, currentAttribute.getCorrelationValue(), parentPath, dataSourceObjectId);
// Create the parent path. Make sure not to add a separator if there is already one there.
String parentPath = fileFromPath.getParent();
if (!parentPath.endsWith(File.separator)) {
parentPath += File.separator;
}
parentPath = parentPath.replace("\\", "/");
final String whereClause = String.format("lower(name) = '%s' AND md5 = '%s' AND lower(parent_path) = '%s' AND data_source_obj_id = %s", fileName, currentAttribute.getCorrelationValue(), parentPath, dataSource.get().getId());
List<AbstractFile> potentialAbstractFiles = tskDb.findAllFilesWhere(whereClause);
if (potentialAbstractFiles.isEmpty()) {
@ -97,46 +108,31 @@ final public class CentralRepoCommonAttributeInstance extends AbstractCommonAttr
} else {
return potentialAbstractFiles.get(0);
}
} catch (TskCoreException | NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, String.format("Unable to find AbstractFile for record with filePath: %s. Node not created.", new Object[]{currentFullPath}), ex);
return null;
}
} else {
return null;
}
} catch (TskCoreException | NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, String.format("Unable to find AbstractFile for record with filePath: %s. Node not created.", new Object[]{currentAttributeInstance.getFilePath()}), ex);
return null;
}
}
return null;
}
@Override
public DisplayableItemNode[] generateNodes() {
// @@@ We should be doing more of this work in teh generateKeys method. We want to do as little as possible in generateNodes
InterCaseSearchResultsProcessor eamDbAttrInst = new InterCaseSearchResultsProcessor(correlationType);
CorrelationAttributeInstance corrAttr = eamDbAttrInst.findSingleCorrelationAttribute(crFileId);
List<DisplayableItemNode> attrInstNodeList = new ArrayList<>(0);
String currCaseDbName = Case.getCurrentCase().getDisplayName();
try {
this.setCurrentAttributeInst(corrAttr);
AbstractFile abstractFileForAttributeInstance = this.getAbstractFile();
DisplayableItemNode generatedInstNode = AbstractCommonAttributeInstance.createNode(corrAttr, abstractFileForAttributeInstance, currCaseDbName);
DisplayableItemNode generatedInstNode = AbstractCommonAttributeInstance.createNode(currentAttribute, abstractFileForAttributeInstance, currCaseDbName);
attrInstNodeList.add(generatedInstNode);
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, String.format("Unable to get DataSource for record with md5: %s. Node not created.", new Object[]{corrAttr.getCorrelationValue()}), ex);
LOGGER.log(Level.SEVERE, String.format("Unable to get DataSource for record with md5: %s. Node not created.", new Object[]{currentAttribute.getCorrelationValue()}), ex);
}
return attrInstNodeList.toArray(new DisplayableItemNode[attrInstNodeList.size()]);
}
private Map<String, Long> invertMap(Map<Long, String> dataSourceIdToNameMap) {
HashMap<String, Long> invertedMap = new HashMap<>();
for (Map.Entry<Long, String> entry : dataSourceIdToNameMap.entrySet()) {
invertedMap.put(entry.getValue(), entry.getKey());
}
return invertedMap;
}
}

View File

@ -2,17 +2,12 @@
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<NonVisualComponents>
<Component class="javax.swing.ButtonGroup" name="fileTypeFilterButtonGroup">
</Component>
<Component class="javax.swing.ButtonGroup" name="interIntraButtonGroup">
</Component>
</NonVisualComponents>
<Properties>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[450, 440]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[450, 440]"/>
<Dimension value="[450, 460]"/>
</Property>
<Property name="resizable" type="boolean" value="false"/>
</Properties>
@ -32,7 +27,7 @@
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,-72,0,0,1,-61"/>
<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,118,0,0,1,-62"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
@ -40,13 +35,13 @@
<Container class="javax.swing.JPanel" name="jPanel1">
<Properties>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[450, 440]"/>
<Dimension value="[450, 460]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[450, 440]"/>
<Dimension value="[450, 460]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[450, 440]"/>
<Dimension value="[450, 460]"/>
</Property>
<Property name="requestFocusEnabled" type="boolean" value="false"/>
</Properties>
@ -59,55 +54,49 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Component id="errorText" pref="300" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="65" max="-2" attributes="0"/>
<Component id="searchButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cancelButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="filler1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="80" max="-2" attributes="0"/>
<Component id="filler2" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="errorText" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="commonFilesSearchLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="intraCaseRadio" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="interCaseRadio" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="commonFilesSearchLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="categoriesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="selectedFileCategoriesButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="29" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="documentsCheckbox" min="-2" max="-2" attributes="0"/>
<Component id="pictureVideoCheckbox" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Component id="allFileCategoriesRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Component id="layoutPanel" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="scopeLabel" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="37" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="percentageThresholdCheck" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="percentageThresholdTextOne" min="-2" pref="40" max="-2" attributes="0"/>
<Component id="percentageThresholdInputBox" min="-2" pref="40" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="percentageThresholdTextTwo" min="-2" max="-2" attributes="0"/>
<Component id="percentageThresholdTextTwo" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="1" max="-2" attributes="0">
<Component id="commonItemSearchDescription" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="intraCaseRadio" max="32767" attributes="0"/>
<Component id="interCaseRadio" pref="383" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
<Group type="103" alignment="0" groupAlignment="1" max="-2" attributes="0">
<Component id="interCasePanel" alignment="0" max="32767" attributes="0"/>
<Component id="intraCasePanel" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="21" pref="21" max="-2" attributes="0"/>
<Component id="dataSourcesLabel" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</Group>
@ -117,53 +106,40 @@
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="commonFilesSearchLabel1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="commonFilesSearchLabel2" min="-2" max="-2" attributes="0"/>
<Component id="commonItemSearchDescription" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="scopeLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="intraCaseRadio" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="interCaseRadio" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
<Component id="layoutPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="categoriesLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="selectedFileCategoriesButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="pictureVideoCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="documentsCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="allFileCategoriesRadioButton" min="-2" max="-2" attributes="0"/>
<Component id="interCasePanel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="intraCasePanel" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="percentageThresholdCheck" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="percentageThresholdTextOne" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="percentageThresholdInputBox" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="percentageThresholdTextTwo" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Component id="filler2" min="-2" max="-2" attributes="0"/>
<Component id="filler1" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="dataSourcesLabel" min="-2" pref="14" max="-2" attributes="0"/>
<EmptySpace type="separate" max="32767" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="searchButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="errorText" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="commonFilesSearchLabel2">
<Component class="javax.swing.JLabel" name="scopeLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.commonFilesSearchLabel2.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.scopeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="focusable" type="boolean" value="false"/>
</Properties>
@ -180,85 +156,6 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="searchButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="cancelButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="actionCommand" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.cancelButton.actionCommand" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="horizontalTextPosition" type="int" value="10"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cancelButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="allFileCategoriesRadioButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="fileTypeFilterButtonGroup"/>
</Property>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.allFileCategoriesRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.allFileCategoriesRadioButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="allFileCategoriesRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="selectedFileCategoriesButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="fileTypeFilterButtonGroup"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.selectedFileCategoriesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.selectedFileCategoriesButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="selectedFileCategoriesButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="pictureVideoCheckbox">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.pictureVideoCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="pictureVideoCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="documentsCheckbox">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.documentsCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="documentsCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="categoriesLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.categoriesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="name" type="java.lang.String" value="" noResource="true"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="errorText">
<Properties>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
@ -270,10 +167,10 @@
<Property name="verticalAlignment" type="int" value="1"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="commonFilesSearchLabel1">
<Component class="javax.swing.JLabel" name="commonItemSearchDescription">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.commonFilesSearchLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.commonItemSearchDescription.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="focusable" type="boolean" value="false"/>
</Properties>
@ -305,40 +202,21 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="interCaseRadioActionPerformed"/>
</Events>
</Component>
<Container class="java.awt.Panel" name="layoutPanel">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignCardLayout"/>
<SubComponents>
<Component class="org.sleuthkit.autopsy.commonfilesearch.IntraCasePanel" name="intraCasePanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignCardLayout" value="org.netbeans.modules.form.compat2.layouts.DesignCardLayout$CardConstraintsDescription">
<CardConstraints cardName="card3"/>
</Constraint>
</Constraints>
</Component>
<Component class="org.sleuthkit.autopsy.commonfilesearch.InterCasePanel" name="interCasePanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignCardLayout" value="org.netbeans.modules.form.compat2.layouts.DesignCardLayout$CardConstraintsDescription">
<CardConstraints cardName="card2"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JCheckBox" name="percentageThresholdCheck">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.percentageThresholdCheck.text_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.percentageThresholdCheck.text_1_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="percentageThresholdCheckActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JTextField" name="percentageThresholdTextOne">
<Component class="javax.swing.JTextField" name="percentageThresholdInputBox">
<Properties>
<Property name="horizontalAlignment" type="int" value="11"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.percentageThresholdTextOne.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.percentageThresholdInputBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[40, 24]"/>
@ -358,25 +236,45 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.Box$Filler" name="filler1">
<Component class="org.sleuthkit.autopsy.commonfilesearch.IntraCasePanel" name="intraCasePanel">
<Properties>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 32767]"/>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Current Case Options">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.intraCasePanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[32779, 192]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[204, 192]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[430, 192]"/>
</Property>
<Property name="verifyInputWhenFocusTarget" type="boolean" value="false"/>
</Properties>
<AuxValues>
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.VerticalGlue"/>
</AuxValues>
</Component>
<Component class="javax.swing.Box$Filler" name="filler2">
<Component class="org.sleuthkit.autopsy.commonfilesearch.InterCasePanel" name="interCasePanel">
<Properties>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[32767, 32767]"/>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Central Repository Options">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.interCasePanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[430, 230]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[430, 230]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.Glue"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="dataSourcesLabel">
</Component>
</SubComponents>
</Container>

View File

@ -19,14 +19,16 @@
package org.sleuthkit.autopsy.commonfilesearch;
import java.awt.event.ActionEvent;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import javax.swing.SwingWorker;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.util.actions.CallableSystemAction;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
@ -39,35 +41,11 @@ final public class CommonAttributeSearchAction extends CallableSystemAction {
private static CommonAttributeSearchAction instance = null;
private static final long serialVersionUID = 1L;
CommonAttributeSearchAction() {
super();
this.setEnabled(false);
}
@Override
public boolean isEnabled(){
boolean shouldBeEnabled = false;
try {
//dont refactor any of this to pull out common expressions - order of evaluation of each expression is significant
shouldBeEnabled =
(Case.isCaseOpen() &&
Case.getCurrentCase().getDataSources().size() > 1)
||
(EamDb.isEnabled() &&
EamDb.getInstance() != null &&
EamDb.getInstance().getCases().size() > 1 &&
Case.isCaseOpen() &&
Case.getCurrentCase() != null &&
EamDb.getInstance().getCase(Case.getCurrentCase()) != null);
} catch(TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error getting data sources for action enabled check", ex);
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error getting CR cases for action enabled check", ex);
}
return super.isEnabled() && shouldBeEnabled;
}
/**
* Get the default CommonAttributeSearchAction.
*
* @return the default instance of this action
*/
public static synchronized CommonAttributeSearchAction getDefault() {
if (instance == null) {
instance = new CommonAttributeSearchAction();
@ -75,18 +53,105 @@ final public class CommonAttributeSearchAction extends CallableSystemAction {
return instance;
}
/**
* Create a CommonAttributeSearchAction for opening the common attribute
* search dialog
*/
private CommonAttributeSearchAction() {
super();
this.setEnabled(false);
}
@Override
public boolean isEnabled() {
return super.isEnabled() && Case.isCaseOpen();
}
@Override
public void actionPerformed(ActionEvent event) {
new CommonAttributePanel().setVisible(true);
createAndShowPanel();
}
@Override
public void performAction() {
new CommonAttributePanel().setVisible(true);
createAndShowPanel();
}
/**
* Create the commonAttributePanel and display it.
*/
@NbBundle.Messages({
"CommonAttributeSearchAction.openPanel.intro=The common property search feature is not available because:",
"CommonAttributeSearchAction.openPanel.resolution=\n\nAddress one of these issues to enable this feature.",
"CommonAttributeSearchAction.openPanel.noCaseOpen=\n - No case is open.",
"CommonAttributeSearchAction.openPanel.notEnoughDataSources=\n - There are not multiple data sources in the current case.",
"CommonAttributeSearchAction.openPanel.centralRepoDisabled=\n - The Central Repository is disabled.",
"CommonAttributeSearchAction.openPanel.caseNotInCentralRepo=\n - The current case is not in the Central Repository.",
"CommonAttributeSearchAction.openPanel.notEnoughCases=\n - Fewer than 2 cases exist in the Central Repository.",
"CommonAttributeSearchAction.openPanel.centralRepoInvalid=\n - The Central Repository configuration is invalid."})
private void createAndShowPanel() {
new SwingWorker<Boolean, Void>() {
String reason = Bundle.CommonAttributeSearchAction_openPanel_intro();
@Override
protected Boolean doInBackground() throws Exception {
// Test whether we should open the common files panel
if (!Case.isCaseOpen()) {
reason += Bundle.CommonAttributeSearchAction_openPanel_noCaseOpen();
return false;
}
if (Case.getCurrentCase().getDataSources().size() > 1) {
// There are enough data sources to run the intra case seach
return true;
} else {
reason += Bundle.CommonAttributeSearchAction_openPanel_notEnoughDataSources();
}
if (!EamDb.isEnabled()) {
reason += Bundle.CommonAttributeSearchAction_openPanel_centralRepoDisabled();
return false;
}
if (EamDb.getInstance() == null) {
reason += Bundle.CommonAttributeSearchAction_openPanel_centralRepoInvalid();
return false;
}
if (EamDb.getInstance().getCases().size() < 2) {
reason += Bundle.CommonAttributeSearchAction_openPanel_notEnoughCases();
return false;
}
if (EamDb.getInstance().getCase(Case.getCurrentCase()) == null) {
reason += Bundle.CommonAttributeSearchAction_openPanel_caseNotInCentralRepo();
return false;
}
return true;
}
@Override
protected void done() {
super.done();
try {
boolean openPanel = get();
if (openPanel) {
CommonAttributePanel commonAttributePanel = new CommonAttributePanel();
//In order to update errors the CommonAttributePanel needs to observe its sub panels
commonAttributePanel.observeSubPanels();
commonAttributePanel.setVisible(true);
} else {
reason += Bundle.CommonAttributeSearchAction_openPanel_resolution();
NotifyDescriptor descriptor = new NotifyDescriptor.Message(reason, NotifyDescriptor.INFORMATION_MESSAGE);
DialogDisplayer.getDefault().notify(descriptor);
}
} catch (InterruptedException | ExecutionException ex) {
LOGGER.log(Level.SEVERE, "Unexpected exception while opening Common Properties Search", ex); //NON-NLS
}
}
}
.execute();
}
@NbBundle.Messages({
"CommonAttributeSearchAction.getName.text=Common Attribute Search"})
"CommonAttributeSearchAction.getName.text=Common Property Search"})
@Override
public String getName() {
return Bundle.CommonAttributeSearchAction_getName_text();

View File

@ -22,15 +22,18 @@ package org.sleuthkit.autopsy.commonfilesearch;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
/**
* Stores the results from the various types of common attribute searching
@ -42,34 +45,44 @@ final public class CommonAttributeSearchResults {
// maps instance count to list of attribute values.
private final Map<Integer, CommonAttributeValueList> instanceCountToAttributeValues;
private final Set<String> mimeTypesToInclude;
private final int percentageThreshold;
private final int resultTypeId;
/**
* Create a values object which can be handed off to the node factories.
*
* @param values list of CommonAttributeValue indexed by size of
* CommonAttributeValue
* @param metadata list of CommonAttributeValue indexed by size
* of CommonAttributeValue
* @param percentageThreshold threshold to filter out files which are too
* common, value of 0 is disabled
* @param resultType The type of Correlation Attribute being
* searched for
* @param mimeTypesToFilterOn Set of mime types to include for intercase
* searches
*/
CommonAttributeSearchResults(Map<Integer, CommonAttributeValueList> metadata, int percentageThreshold, CorrelationAttributeInstance.Type resultType) {
CommonAttributeSearchResults(Map<Integer, CommonAttributeValueList> metadata, int percentageThreshold, CorrelationAttributeInstance.Type resultType, Set<String> mimeTypesToFilterOn) {
//wrap in a new object in case any client code has used an unmodifiable collection
this.instanceCountToAttributeValues = new HashMap<>(metadata);
this.percentageThreshold = percentageThreshold;
this.resultTypeId = resultType.getId();
this.mimeTypesToInclude = mimeTypesToFilterOn;
}
/**
* Create a values object which can be handed off to the node factories.
*
* @param values list of CommonAttributeValue indexed by size of
* CommonAttributeValue
* @param metadata list of CommonAttributeValue indexed by size
* of CommonAttributeValue
* @param percentageThreshold threshold to filter out files which are too
* common, value of 0 is disabled
*/
CommonAttributeSearchResults(Map<Integer, CommonAttributeValueList> metadata, int percentageThreshold) {
//wrap in a new object in case any client code has used an unmodifiable collection
this.instanceCountToAttributeValues = new HashMap<>(metadata);
this.percentageThreshold = percentageThreshold;
this.resultTypeId = CorrelationAttributeInstance.FILES_TYPE_ID;
this.mimeTypesToInclude = new HashSet<>(); //don't filter on mimetypes
}
/**
@ -79,6 +92,7 @@ final public class CommonAttributeSearchResults {
* <code>getValues()</code>.
*
* @param instanceCount key
*
* @return list of values which represent matches
*/
CommonAttributeValueList getAttributeValuesForInstanceCount(Integer instanceCount) {
@ -93,7 +107,7 @@ final public class CommonAttributeSearchResults {
* @return map of sizes of children to list of matches
*/
public Map<Integer, CommonAttributeValueList> getMetadata() throws EamDbException {
if(this.percentageThreshold == 0){
if (this.percentageThreshold == 0 && mimeTypesToInclude.isEmpty()) {
return Collections.unmodifiableMap(this.instanceCountToAttributeValues);
} else {
return this.getMetadata(this.percentageThreshold);
@ -111,12 +125,7 @@ final public class CommonAttributeSearchResults {
* @return metadata
*/
private Map<Integer, CommonAttributeValueList> getMetadata(int maximumPercentageThreshold) throws EamDbException {
if(maximumPercentageThreshold == 0){
return Collections.unmodifiableMap(this.instanceCountToAttributeValues);
}
CorrelationAttributeInstance.Type fileAttributeType = CorrelationAttributeInstance
CorrelationAttributeInstance.Type attributeType = CorrelationAttributeInstance
.getDefaultCorrelationTypes()
.stream()
.filter(filterType -> filterType.getId() == this.resultTypeId)
@ -125,6 +134,9 @@ final public class CommonAttributeSearchResults {
EamDb eamDb = EamDb.getInstance();
Map<Integer, List<CommonAttributeValue>> itemsToRemove = new HashMap<>();
//Call countUniqueDataSources once to reduce the number of DB queries needed to get
//the frequencyPercentage
Double uniqueCaseDataSourceTuples = eamDb.getCountUniqueDataSources().doubleValue();
for (Entry<Integer, CommonAttributeValueList> listOfValues : Collections.unmodifiableMap(this.instanceCountToAttributeValues).entrySet()) {
@ -133,9 +145,39 @@ final public class CommonAttributeSearchResults {
for (CommonAttributeValue value : values.getDelayedMetadataList()) { // Need the real metadata
//Intracase common attribute searches will have been created with an empty mimeTypesToInclude list
//because when performing intra case search this filtering will have been done during the query of the case database
boolean mimeTypeToRemove = false; //allow code to be more efficient by not attempting to remove the same value multiple times
if (!mimeTypesToInclude.isEmpty()) { //only do the mime type filtering when mime types aren't empty
for (AbstractCommonAttributeInstance commonAttr : value.getInstances()) {
AbstractFile abstractFile = commonAttr.getAbstractFile();
if (abstractFile != null) {
String mimeType = commonAttr.getAbstractFile().getMIMEType();
if (mimeType != null && !mimeTypesToInclude.contains(mimeType)) {
if (itemsToRemove.containsKey(key)) {
itemsToRemove.get(key).add(value);
} else {
List<CommonAttributeValue> toRemove = new ArrayList<>();
toRemove.add(value);
itemsToRemove.put(key, toRemove);
}
//value will be removed as the mime type existed and was not in the set to be included
//because value is removed this value does not need to be checked further
mimeTypeToRemove = true;
break;
}
}
if (mimeTypeToRemove) {
break;
}
}
}
if (!mimeTypeToRemove && maximumPercentageThreshold != 0) { //only do the frequency filtering when a max % was set
try {
int frequencyPercentage = eamDb.getFrequencyPercentage(new CorrelationAttributeInstance(fileAttributeType, value.getValue()));
Double uniqueTypeValueTuples = eamDb.getCountUniqueCaseDataSourceTuplesHavingTypeValue(
attributeType, value.getValue()).doubleValue();
Double commonalityPercentage = uniqueTypeValueTuples / uniqueCaseDataSourceTuples * 100;
int frequencyPercentage = commonalityPercentage.intValue();
if (frequencyPercentage > maximumPercentageThreshold) {
if (itemsToRemove.containsKey(key)) {
itemsToRemove.get(key).add(value);
@ -150,21 +192,21 @@ final public class CommonAttributeSearchResults {
}
}
}
}
for (Entry<Integer, List<CommonAttributeValue>> valuesToRemove : itemsToRemove.entrySet()) {
final Integer key = valuesToRemove.getKey();
final List<CommonAttributeValue> values = valuesToRemove.getValue();
for (CommonAttributeValue value : values) {
final CommonAttributeValueList instanceCountValue = this.instanceCountToAttributeValues.get(key);
if (instanceCountValue != null) {
instanceCountValue.removeMetaData(value);
if (instanceCountValue.getDelayedMetadataList().isEmpty()) { // Check the real metadata
this.instanceCountToAttributeValues.remove(key);
}
}
}
}
return Collections.unmodifiableMap(this.instanceCountToAttributeValues);
}

View File

@ -29,11 +29,10 @@ import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
import org.sleuthkit.autopsy.corecomponents.DelayedLoadChildNodesOnTreeExpansion;
/**
* <code>DataResultViewerTable</code> which overrides the default column
* header width calculations. The <code>CommonAttributesSearchResultsViewerTable</code>
* <code>DataResultViewerTable</code> which overrides the default column header
* width calculations. The <code>CommonAttributesSearchResultsViewerTable</code>
* presents multiple tiers of data which are not always present and it may not
* make sense to try to calculate the column widths for such tables by sampling
* rows and looking for wide cells. Rather, we just pick some reasonable values.
@ -60,17 +59,18 @@ public class CommonAttributesSearchResultsViewerTable extends DataResultViewerTa
COLUMN_WIDTHS = Collections.unmodifiableMap(map);
}
/**
* Implements a DataResultViewerTable which constructs a tabular result viewer that
* displays the children of the given root node using an OutlineView. The explorer
* manager will be discovered at runtime.
* Implements a DataResultViewerTable which constructs a tabular result
* viewer that displays the children of the given root node using an
* OutlineView. The explorer manager will be discovered at runtime.
*
* Adds a TreeExpansionsListener to the outlineView to receive tree expansion events
* which dynamically loads children nodes when requested.
* Adds a TreeExpansionsListener to the outlineView to receive tree
* expansion events which dynamically loads children nodes when requested.
*/
public CommonAttributesSearchResultsViewerTable() {
super();
outlineView.addTreeExpansionListener(new DelayedLoadChildNodesOnTreeExpansion());
addTreeExpansionListener(new InstanceCountNodeTreeExpansionListener());
}
@NbBundle.Messages({

View File

@ -37,7 +37,7 @@ import org.sleuthkit.autopsy.datamodel.NodeProperty;
* Node used to indicate the number of matches found with the MD5 children of
* this Node.
*/
final public class InstanceCountNode extends DisplayableItemNode {
public final class InstanceCountNode extends DisplayableItemNode {
private static final Logger logger = Logger.getLogger(InstanceCountNode.class.getName());
@ -74,11 +74,10 @@ final public class InstanceCountNode extends DisplayableItemNode {
}
/**
* Refresh the node, by dynamically loading in the children when called, and
* calling the CommonAttributeValueNodeFactory to generate nodes for the
* children in attributeValues.
* Creates the Children of this node. By doing this here instead of in the
* constructor, lazy creation of the Children is made possible.
*/
public void refresh() {
void createChildren() {
attributeValues.displayDelayedMetadata();
setChildren(Children.create(new CommonAttributeValueNodeFactory(attributeValues.getMetadataList()), true));
}

View File

@ -17,38 +17,38 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.corecomponents;
package org.sleuthkit.autopsy.commonfilesearch;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import org.openide.explorer.view.Visualizer;
import org.openide.nodes.Node;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
/**
* A tree expansion listener that will trigger a recreation of childs through
* its child factory on re-expansion of a node (causes to recreate the
* ChildFactory for this purpose.).
*/
public final class DelayedLoadChildNodesOnTreeExpansion implements TreeExpansionListener {
/**
* A flag for avoiding endless recursion inside the expansion listener that
* could trigger collapsing and (re-)expanding nodes again.
* @param event
* A tree expansion listener used to do lazy creation of the Childfren of an
* InstanceCountNode when the node is expanded.
*/
final class InstanceCountNodeTreeExpansionListener implements TreeExpansionListener {
@Override
public synchronized void treeCollapsed(final TreeExpansionEvent event) {
// Do nothing on collapse. Netbeans should manage nodes falling out of scope and GC.
}
@Override
public synchronized void treeExpanded(final TreeExpansionEvent event) {
Node eventNode = Visualizer.findNode(event.getPath().getLastPathComponent());
final Node eventNode = Visualizer.findNode(event.getPath().getLastPathComponent());
if (eventNode instanceof TableFilterNode) {
final TableFilterNode node = (TableFilterNode) eventNode;
node.refresh();
final TableFilterNode tableFilterNode = (TableFilterNode) eventNode;
final DataResultFilterNode dataResultFilterNode = tableFilterNode.getLookup().lookup(DataResultFilterNode.class);
if (dataResultFilterNode != null) {
final InstanceCountNode instanceCountNode = dataResultFilterNode.getLookup().lookup(InstanceCountNode.class);
if (instanceCountNode != null) {
instanceCountNode.createChildren();
}
}
}
}
}
}

View File

@ -19,7 +19,6 @@
*/
package org.sleuthkit.autopsy.commonfilesearch;
import java.util.Map;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
@ -48,8 +47,8 @@ abstract class InterCaseCommonAttributeSearcher extends AbstractCommonAttributeS
*
* @throws EamDbException
*/
InterCaseCommonAttributeSearcher(Map<Long, String> dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType, Type corAttrType, int percentageThreshold) throws EamDbException {
super(dataSourceIdMap, filterByMediaMimeType, filterByDocMimeType, percentageThreshold);
InterCaseCommonAttributeSearcher(boolean filterByMediaMimeType, boolean filterByDocMimeType, Type corAttrType, int percentageThreshold) throws EamDbException {
super(filterByMediaMimeType, filterByDocMimeType, percentageThreshold);
dbManager = EamDb.getInstance();
this.corAttrType = corAttrType;
}

View File

@ -20,71 +20,72 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="anyCentralRepoCaseRadio" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="specificCentralRepoCaseRadio" min="-2" max="-2" attributes="0"/>
<Component id="specificCentralRepoCaseCheckbox" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="correlationComboBoxLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="categoriesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="19" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="allFileCategoriesRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="selectedFileCategoriesButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="21" pref="21" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="documentsCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="pictureVideoCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="21" max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="caseComboBox" min="-2" pref="261" max="-2" attributes="0"/>
<Group type="103" alignment="1" groupAlignment="0" attributes="0">
<Component id="comboBoxLabel" min="-2" max="-2" attributes="0"/>
<Component id="correlationTypeComboBox" min="-2" pref="260" max="-2" attributes="0"/>
<Component id="caseComboBox" max="32767" attributes="0"/>
<Component id="correlationTypeComboBox" alignment="1" pref="353" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
<EmptySpace max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="anyCentralRepoCaseRadio" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="specificCentralRepoCaseRadio" min="-2" max="-2" attributes="0"/>
<Component id="specificCentralRepoCaseCheckbox" min="-2" pref="18" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="caseComboBox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="comboBoxLabel" min="-2" max="-2" attributes="0"/>
<Component id="correlationComboBoxLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="correlationTypeComboBox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="categoriesLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="allFileCategoriesRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="selectedFileCategoriesButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="pictureVideoCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="documentsCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JRadioButton" name="anyCentralRepoCaseRadio">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="buttonGroup"/>
</Property>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="InterCasePanel.anyCentralRepoCaseRadio.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="anyCentralRepoCaseRadioActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="specificCentralRepoCaseRadio">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="buttonGroup"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="InterCasePanel.specificCentralRepoCaseRadio.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="specificCentralRepoCaseRadioActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JComboBox" name="caseComboBox">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
@ -96,10 +97,10 @@
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="comboBoxLabel">
<Component class="javax.swing.JLabel" name="correlationComboBoxLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="InterCasePanel.comboBoxLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="InterCasePanel.correlationComboBoxLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
@ -112,9 +113,90 @@
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="InterCasePanel.correlationTypeComboBox.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="correlationTypeComboBoxActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="categoriesLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="InterCasePanel.categoriesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="name" type="java.lang.String" value="" noResource="true"/>
</Properties>
</Component>
<Component class="javax.swing.JRadioButton" name="allFileCategoriesRadioButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="buttonGroup"/>
</Property>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="InterCasePanel.allFileCategoriesRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="InterCasePanel.allFileCategoriesRadioButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="allFileCategoriesRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="selectedFileCategoriesButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="buttonGroup"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="InterCasePanel.selectedFileCategoriesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="InterCasePanel.selectedFileCategoriesButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="selectedFileCategoriesButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="pictureVideoCheckbox">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="InterCasePanel.pictureVideoCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="pictureVideoCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="documentsCheckbox">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="InterCasePanel.documentsCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="documentsCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="specificCentralRepoCaseCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="InterCasePanel.specificCentralRepoCaseCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="specificCentralRepoCaseCheckboxActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@ -24,6 +24,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Observable;
import java.util.Observer;
import javax.swing.ComboBoxModel;
import org.openide.util.Exceptions;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
@ -33,20 +35,16 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
* UI controls for Common Files Search scenario where the user intends to find
* common files between cases in addition to the present case.
*/
public class InterCasePanel extends javax.swing.JPanel {
public final class InterCasePanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private final Observable fileTypeFilterObservable;
static final int NO_CASE_SELECTED = -1;
private ComboBoxModel<String> casesList = new DataSourceComboBoxModel();
private final Map<Integer, String> caseMap;
//True if we are looking in any or all cases,
// false if we must find matches in a given case plus the current case
private boolean anyCase;
private Map<String, CorrelationAttributeInstance.Type> correlationTypeFilters;
/**
@ -55,22 +53,63 @@ public class InterCasePanel extends javax.swing.JPanel {
public InterCasePanel() {
initComponents();
this.caseMap = new HashMap<>();
this.anyCase = true;
}
private void specificCaseSelected(boolean selected) {
this.specificCentralRepoCaseRadio.setEnabled(selected);
if (this.specificCentralRepoCaseRadio.isEnabled()) {
this.caseComboBox.setEnabled(true);
this.caseComboBox.setSelectedIndex(0);
fileTypeFilterObservable = new Observable() {
@Override
public void notifyObservers() {
//set changed before notify observers
//we want this observerable to always cause the observer to update when notified
this.setChanged();
super.notifyObservers();
}
};
}
/**
* If the EamDB is enabled, the UI will populate the correlation type ComboBox with
* available types in the CR.
* Add an Observer to the Observable portion of this panel so that it can be
* notified of changes to this panel.
*
* @param observer the object which is observing this panel
*/
void addObserver(Observer observer) {
fileTypeFilterObservable.addObserver(observer);
}
/**
* If the user has selected to show only results of specific file types.
*
* @return if the selected file categories button is enabled AND selected,
* true for enabled AND selected false for not selected OR not
* enabled
*/
boolean fileCategoriesButtonIsSelected() {
return selectedFileCategoriesButton.isEnabled() && selectedFileCategoriesButton.isSelected();
}
/**
* If the user has selected selected to show Picture and Video files as part
* of the filtered results.
*
* @return if the pictures and video checkbox is enabled AND selected, true
* for enabled AND selected false for not selected OR not enabled
*/
boolean pictureVideoCheckboxIsSelected() {
return pictureVideoCheckbox.isEnabled() && pictureVideoCheckbox.isSelected();
}
/**
* If the user has selected selected to show Document files as part of the
* filtered results.
*
* @return if the documents checkbox is enabled AND selected, true for
* enabled AND selected false for not selected OR not enabled
*/
boolean documentsCheckboxIsSelected() {
return documentsCheckbox.isEnabled() && documentsCheckbox.isSelected();
}
/**
* If the EamDB is enabled, the UI will populate the correlation type
* ComboBox with available types in the CR.
*/
void setupCorrelationTypeFilter() {
this.correlationTypeFilters = new HashMap<>();
@ -84,7 +123,6 @@ public class InterCasePanel extends javax.swing.JPanel {
Exceptions.printStackTrace(ex);
}
this.correlationTypeComboBox.setSelectedIndex(0);
}
/**
@ -97,138 +135,257 @@ public class InterCasePanel extends javax.swing.JPanel {
private void initComponents() {
buttonGroup = new javax.swing.ButtonGroup();
anyCentralRepoCaseRadio = new javax.swing.JRadioButton();
specificCentralRepoCaseRadio = new javax.swing.JRadioButton();
caseComboBox = new javax.swing.JComboBox<>();
comboBoxLabel = new javax.swing.JLabel();
correlationComboBoxLabel = new javax.swing.JLabel();
correlationTypeComboBox = new javax.swing.JComboBox<>();
buttonGroup.add(anyCentralRepoCaseRadio);
anyCentralRepoCaseRadio.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(anyCentralRepoCaseRadio, org.openide.util.NbBundle.getMessage(InterCasePanel.class, "InterCasePanel.anyCentralRepoCaseRadio.text")); // NOI18N
anyCentralRepoCaseRadio.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
anyCentralRepoCaseRadioActionPerformed(evt);
}
});
buttonGroup.add(specificCentralRepoCaseRadio);
org.openide.awt.Mnemonics.setLocalizedText(specificCentralRepoCaseRadio, org.openide.util.NbBundle.getMessage(InterCasePanel.class, "InterCasePanel.specificCentralRepoCaseRadio.text")); // NOI18N
specificCentralRepoCaseRadio.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
specificCentralRepoCaseRadioActionPerformed(evt);
}
});
categoriesLabel = new javax.swing.JLabel();
allFileCategoriesRadioButton = new javax.swing.JRadioButton();
selectedFileCategoriesButton = new javax.swing.JRadioButton();
pictureVideoCheckbox = new javax.swing.JCheckBox();
documentsCheckbox = new javax.swing.JCheckBox();
specificCentralRepoCaseCheckbox = new javax.swing.JCheckBox();
caseComboBox.setModel(casesList);
caseComboBox.setEnabled(false);
org.openide.awt.Mnemonics.setLocalizedText(comboBoxLabel, org.openide.util.NbBundle.getMessage(InterCasePanel.class, "InterCasePanel.comboBoxLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(correlationComboBoxLabel, org.openide.util.NbBundle.getMessage(InterCasePanel.class, "InterCasePanel.correlationComboBoxLabel.text")); // NOI18N
correlationTypeComboBox.setSelectedItem(null);
correlationTypeComboBox.setToolTipText(org.openide.util.NbBundle.getMessage(InterCasePanel.class, "InterCasePanel.correlationTypeComboBox.toolTipText")); // NOI18N
correlationTypeComboBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
correlationTypeComboBoxActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(categoriesLabel, org.openide.util.NbBundle.getMessage(InterCasePanel.class, "InterCasePanel.categoriesLabel.text")); // NOI18N
categoriesLabel.setEnabled(false);
categoriesLabel.setName(""); // NOI18N
buttonGroup.add(allFileCategoriesRadioButton);
allFileCategoriesRadioButton.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(allFileCategoriesRadioButton, org.openide.util.NbBundle.getMessage(InterCasePanel.class, "InterCasePanel.allFileCategoriesRadioButton.text")); // NOI18N
allFileCategoriesRadioButton.setToolTipText(org.openide.util.NbBundle.getMessage(InterCasePanel.class, "InterCasePanel.allFileCategoriesRadioButton.toolTipText")); // NOI18N
allFileCategoriesRadioButton.setEnabled(false);
allFileCategoriesRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
allFileCategoriesRadioButtonActionPerformed(evt);
}
});
buttonGroup.add(selectedFileCategoriesButton);
org.openide.awt.Mnemonics.setLocalizedText(selectedFileCategoriesButton, org.openide.util.NbBundle.getMessage(InterCasePanel.class, "InterCasePanel.selectedFileCategoriesButton.text")); // NOI18N
selectedFileCategoriesButton.setToolTipText(org.openide.util.NbBundle.getMessage(InterCasePanel.class, "InterCasePanel.selectedFileCategoriesButton.toolTipText")); // NOI18N
selectedFileCategoriesButton.setEnabled(false);
selectedFileCategoriesButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
selectedFileCategoriesButtonActionPerformed(evt);
}
});
pictureVideoCheckbox.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(pictureVideoCheckbox, org.openide.util.NbBundle.getMessage(InterCasePanel.class, "InterCasePanel.pictureVideoCheckbox.text")); // NOI18N
pictureVideoCheckbox.setEnabled(false);
pictureVideoCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
pictureVideoCheckboxActionPerformed(evt);
}
});
documentsCheckbox.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(documentsCheckbox, org.openide.util.NbBundle.getMessage(InterCasePanel.class, "InterCasePanel.documentsCheckbox.text")); // NOI18N
documentsCheckbox.setEnabled(false);
documentsCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
documentsCheckboxActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(specificCentralRepoCaseCheckbox, org.openide.util.NbBundle.getMessage(InterCasePanel.class, "InterCasePanel.specificCentralRepoCaseCheckbox.text")); // NOI18N
specificCentralRepoCaseCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
specificCentralRepoCaseCheckboxActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(specificCentralRepoCaseCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(correlationComboBoxLabel)
.addGap(0, 0, Short.MAX_VALUE))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(anyCentralRepoCaseRadio)
.addComponent(specificCentralRepoCaseRadio)
.addComponent(categoriesLabel)
.addGroup(layout.createSequentialGroup()
.addGap(19, 19, 19)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(allFileCategoriesRadioButton)
.addComponent(selectedFileCategoriesButton)
.addGroup(layout.createSequentialGroup()
.addGap(21, 21, 21)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(documentsCheckbox)
.addComponent(pictureVideoCheckbox))))))
.addGap(0, 0, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addGap(21, 21, 21)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(caseComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 261, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(comboBoxLabel)
.addComponent(correlationTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE)))))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(caseComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(correlationTypeComboBox, 0, 353, Short.MAX_VALUE))))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(anyCentralRepoCaseRadio)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(specificCentralRepoCaseRadio)
.addContainerGap()
.addComponent(specificCentralRepoCaseCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(caseComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(comboBoxLabel)
.addComponent(correlationComboBoxLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(correlationTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(categoriesLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(allFileCategoriesRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(selectedFileCategoriesButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(pictureVideoCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(documentsCheckbox)
.addGap(0, 0, 0))
);
}// </editor-fold>//GEN-END:initComponents
private void specificCentralRepoCaseRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_specificCentralRepoCaseRadioActionPerformed
this.caseComboBox.setEnabled(true);
if(this.caseComboBox.isEnabled() && this.caseComboBox.getSelectedItem() == null){
private void allFileCategoriesRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_allFileCategoriesRadioButtonActionPerformed
//When the allFileCategoriesRadioButton is selected disable the options
//related to selected file categories and notify observers that the panel has changed
//incase the current settings are invalid
pictureVideoCheckbox.setEnabled(false);
documentsCheckbox.setEnabled(false);
fileTypeFilterObservable.notifyObservers();
}//GEN-LAST:event_allFileCategoriesRadioButtonActionPerformed
private void selectedFileCategoriesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectedFileCategoriesButtonActionPerformed
//When the selectedFileCategoriesButton is selected enable its related options
//and notify observers that the panel has changed incase the current settings are invalid
pictureVideoCheckbox.setEnabled(true);
documentsCheckbox.setEnabled(true);
fileTypeFilterObservable.notifyObservers();
}//GEN-LAST:event_selectedFileCategoriesButtonActionPerformed
private void specificCentralRepoCaseCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_specificCentralRepoCaseCheckboxActionPerformed
//When the specificCentralRepoCaseCheckbox is clicked update its related options
this.caseComboBox.setEnabled(specificCentralRepoCaseCheckbox.isSelected());
if (specificCentralRepoCaseCheckbox.isSelected()) {
this.caseComboBox.setSelectedIndex(0);
}
this.anyCase = false;
}//GEN-LAST:event_specificCentralRepoCaseRadioActionPerformed
}//GEN-LAST:event_specificCentralRepoCaseCheckboxActionPerformed
private void anyCentralRepoCaseRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_anyCentralRepoCaseRadioActionPerformed
this.caseComboBox.setEnabled(false);
this.anyCase = true;
}//GEN-LAST:event_anyCentralRepoCaseRadioActionPerformed
private void correlationTypeComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_correlationTypeComboBoxActionPerformed
boolean enableFileTypesFilter = this.correlationTypeComboBox.getSelectedItem().equals("Files");
categoriesLabel.setEnabled(enableFileTypesFilter);
allFileCategoriesRadioButton.setEnabled(enableFileTypesFilter);
selectedFileCategoriesButton.setEnabled(enableFileTypesFilter);
boolean enableIndividualFilters = (enableFileTypesFilter && selectedFileCategoriesButton.isSelected());
pictureVideoCheckbox.setEnabled(enableIndividualFilters);
documentsCheckbox.setEnabled(enableIndividualFilters);
}//GEN-LAST:event_correlationTypeComboBoxActionPerformed
private void pictureVideoCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pictureVideoCheckboxActionPerformed
//notify observers that the panel has changed incase the current settings are invalid
fileTypeFilterObservable.notifyObservers();
}//GEN-LAST:event_pictureVideoCheckboxActionPerformed
private void documentsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_documentsCheckboxActionPerformed
//notify observers that the panel has changed incase the current settings are invalid
fileTypeFilterObservable.notifyObservers();
}//GEN-LAST:event_documentsCheckboxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JRadioButton anyCentralRepoCaseRadio;
private javax.swing.JRadioButton allFileCategoriesRadioButton;
private javax.swing.ButtonGroup buttonGroup;
private javax.swing.JComboBox<String> caseComboBox;
private javax.swing.JLabel comboBoxLabel;
private javax.swing.JLabel categoriesLabel;
private javax.swing.JLabel correlationComboBoxLabel;
private javax.swing.JComboBox<String> correlationTypeComboBox;
private javax.swing.JRadioButton specificCentralRepoCaseRadio;
private javax.swing.JCheckBox documentsCheckbox;
private javax.swing.JCheckBox pictureVideoCheckbox;
private javax.swing.JRadioButton selectedFileCategoriesButton;
private javax.swing.JCheckBox specificCentralRepoCaseCheckbox;
// End of variables declaration//GEN-END:variables
/**
* Get the map of cases which was used to populate the combo box on
* this panel.
*
* @return an unmodifiable copy of the map of cases
*/
Map<Integer, String> getCaseMap() {
return Collections.unmodifiableMap(this.caseMap);
}
void setCaseList(DataSourceComboBoxModel dataSourceComboBoxModel) {
/**
* Set the datamodel for the combo box which displays the cases in
* the central repository
*
* @param dataSourceComboBoxModel the DataSourceComboBoxModel to use
*/
void setCaseComboboxModel(DataSourceComboBoxModel dataSourceComboBoxModel) {
this.casesList = dataSourceComboBoxModel;
this.caseComboBox.setModel(dataSourceComboBoxModel);
}
void rigForMultipleCases(boolean multipleCases) {
this.anyCentralRepoCaseRadio.setEnabled(multipleCases);
this.anyCentralRepoCaseRadio.setEnabled(multipleCases);
if(!multipleCases){
this.specificCentralRepoCaseRadio.setSelected(true);
this.specificCaseSelected(true);
}
}
/**
* Update the map of cases that this panel allows the user to select from
*
* @param caseMap A map of cases
*/
void setCaseMap(Map<Integer, String> caseMap) {
this.caseMap.clear();
this.caseMap.putAll(caseMap);
}
/**
* Whether or not the central repository has multiple cases in it.
*
* @return true when the central repository has 2 or more case, false if it
* has 0 or 1 case in it.
*/
boolean centralRepoHasMultipleCases() {
return this.caseMap.size() >= 2;
}
/**
* Get the ID for the selected case
*
* @return the ID of the selected case or InterCasePanel.NO_CASE_SELECTED
* when none selected
*/
Integer getSelectedCaseId() {
if(this.anyCase){
return InterCasePanel.NO_CASE_SELECTED;
}
if (specificCentralRepoCaseCheckbox.isSelected()) {
for (Entry<Integer, String> entry : this.caseMap.entrySet()) {
if (entry.getValue().equals(this.caseComboBox.getSelectedItem())) {
return entry.getKey();
}
}
}
return InterCasePanel.NO_CASE_SELECTED;
}
/**
* Returns the selected Correlation Type by getting the Type from the stored HashMap.
* Returns the selected Correlation Type by getting the Type from the stored
* HashMap.
*
* @return Type the selected Correlation Type to query for.
*/
CorrelationAttributeInstance.Type getSelectedCorrelationType() {

View File

@ -44,8 +44,6 @@ import org.sleuthkit.datamodel.HashUtility;
*/
final class InterCaseSearchResultsProcessor {
private Map<Long, String> dataSources;
/**
* The CorrelationAttributeInstance.Type this Processor will query on
*/
@ -70,9 +68,8 @@ final class InterCaseSearchResultsProcessor {
* @param dataSources the cases to filter and correlate on
* @param theType the type of CR data to search
*/
InterCaseSearchResultsProcessor(Map<Long, String> dataSources, CorrelationAttributeInstance.Type theType) {
InterCaseSearchResultsProcessor(CorrelationAttributeInstance.Type theType) {
this.correlationType = theType;
this.dataSources = dataSources;
interCaseWhereClause = getInterCaseWhereClause();
singleInterCaseWhereClause = getSingleInterCaseWhereClause();
}
@ -101,18 +98,6 @@ final class InterCaseSearchResultsProcessor {
return sqlString.toString();
}
/**
* Used in the CentralRepoCommonAttributeInstance to find common attribute
* instances and generate nodes at the UI level.
*
* @param theType the type of CR data to search
*/
InterCaseSearchResultsProcessor(CorrelationAttributeInstance.Type theType) {
this.correlationType = theType;
interCaseWhereClause = getInterCaseWhereClause();
singleInterCaseWhereClause = getSingleInterCaseWhereClause();
}
/**
* Finds a single CorrelationAttribute given an id.
*
@ -212,11 +197,16 @@ final class InterCaseSearchResultsProcessor {
countAndAddCommonAttributes(corValue, resultId);
}
//Add the final instances
CommonAttributeValueList value = new CommonAttributeValueList();
//Add the final instance(s)
if (commonAttributeValue != null) {
int size = commonAttributeValue.getInstanceCount();
if (instanceCollatedCommonFiles.containsKey(size)) {
instanceCollatedCommonFiles.get(size).addMetadataToList(commonAttributeValue);
} else {
CommonAttributeValueList value = new CommonAttributeValueList();
value.addMetadataToList(commonAttributeValue);
instanceCollatedCommonFiles.put(commonAttributeValue.getInstanceCount(), value);
instanceCollatedCommonFiles.put(size, value);
}
}
} catch (SQLException ex) {
LOGGER.log(Level.WARNING, "Error getting artifact instances from database.", ex); // NON-NLS
@ -252,7 +242,9 @@ final class InterCaseSearchResultsProcessor {
// we don't *have* all the information for the rows in the CR,
// so we need to consult the present case via the SleuthkitCase object
// Later, when the FileInstanceNode is built. Therefore, build node generators for now.
AbstractCommonAttributeInstance searchResult = new CentralRepoCommonAttributeInstance(resultId, InterCaseSearchResultsProcessor.this.dataSources, correlationType);
CentralRepoCommonAttributeInstance searchResult = new CentralRepoCommonAttributeInstance(resultId, correlationType);
CorrelationAttributeInstance corrAttr = findSingleCorrelationAttribute(resultId);
searchResult.setCurrentAttributeInst(corrAttr);
commonAttributeValue.addInstance(searchResult);
}

View File

@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.commonfilesearch;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -46,6 +47,8 @@ public abstract class IntraCaseCommonAttributeSearcher extends AbstractCommonAtt
private static final String FILTER_BY_MIME_TYPES_WHERE_CLAUSE = " and mime_type in (%s)"; //NON-NLS // where %s is csv list of mime_types to filter on
private final Map<Long, String> dataSourceIdToNameMap;
/**
* Subclass this to implement different algorithms for getting common files.
*
@ -56,7 +59,13 @@ public abstract class IntraCaseCommonAttributeSearcher extends AbstractCommonAtt
* broadly categorized as document types
*/
IntraCaseCommonAttributeSearcher(Map<Long, String> dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType, int percentageThreshold) {
super(dataSourceIdMap, filterByMediaMimeType, filterByDocMimeType, percentageThreshold);
super(filterByMediaMimeType, filterByDocMimeType, percentageThreshold);
this.dataSourceIdToNameMap = dataSourceIdMap;
}
Map<Long, String> getDataSourceIdToNameMap() {
return Collections.unmodifiableMap(this.dataSourceIdToNameMap);
}
/**

View File

@ -23,62 +23,58 @@
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<EmptySpace min="-2" pref="21" max="-2" attributes="0"/>
<Component id="selectDataSourceComboBox" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="allDataSourcesRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="withinDataSourceRadioButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Component id="categoriesLabel" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="27" max="-2" attributes="0"/>
<Component id="selectDataSourceComboBox" min="-2" pref="261" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="19" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="allFileCategoriesRadioButton" min="-2" max="-2" attributes="0"/>
<Component id="selectedFileCategoriesButton" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="21" pref="21" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="documentsCheckbox" min="-2" max="-2" attributes="0"/>
<Component id="pictureVideoCheckbox" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
<Component id="onlySpecificDataSourceCheckbox" pref="384" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="allDataSourcesRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="withinDataSourceRadioButton" min="-2" max="-2" attributes="0"/>
<Component id="onlySpecificDataSourceCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="selectDataSourceComboBox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="categoriesLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="allFileCategoriesRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="selectedFileCategoriesButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="pictureVideoCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="documentsCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JRadioButton" name="allDataSourcesRadioButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="buttonGroup"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="IntraCasePanel.allDataSourcesRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="horizontalAlignment" type="int" value="0"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="allDataSourcesRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="withinDataSourceRadioButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="buttonGroup"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="IntraCasePanel.withinDataSourceRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="horizontalAlignment" type="int" value="0"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="withinDataSourceRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JComboBox" name="selectDataSourceComboBox">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
@ -86,12 +82,93 @@
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="selectDataSourceComboBoxActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="categoriesLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="IntraCasePanel.categoriesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="name" type="java.lang.String" value="" noResource="true"/>
</Properties>
</Component>
<Component class="javax.swing.JRadioButton" name="selectedFileCategoriesButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="buttonGroup"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="IntraCasePanel.selectedFileCategoriesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="IntraCasePanel.selectedFileCategoriesButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="selectedFileCategoriesButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="pictureVideoCheckbox">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="IntraCasePanel.pictureVideoCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="pictureVideoCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="documentsCheckbox">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="IntraCasePanel.documentsCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="documentsCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="allFileCategoriesRadioButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="buttonGroup"/>
</Property>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="IntraCasePanel.allFileCategoriesRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="IntraCasePanel.allFileCategoriesRadioButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="allFileCategoriesRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="onlySpecificDataSourceCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="IntraCasePanel.onlySpecificDataSourceCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[243, 23]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[243, 23]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[243, 23]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onlySpecificDataSourceCheckboxActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@ -23,19 +23,21 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Observable;
import java.util.Observer;
import javax.swing.ComboBoxModel;
/**
* UI controls for Common Files Search scenario where the user intends to find
* common files between datasources. It is an inner panel which provides the ability
* to select all datasources or a single datasource from a dropdown list of
* sources in the current case.
* common files between datasources. It is an inner panel which provides the
* ability to select all datasources or a single datasource from a dropdown list
* of sources in the current case.
*/
public class IntraCasePanel extends javax.swing.JPanel {
public final class IntraCasePanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
static final long NO_DATA_SOURCE_SELECTED = -1;
private boolean singleDataSource;
private final Observable fileTypeFilterObservable;
private ComboBoxModel<String> dataSourcesList = new DataSourceComboBoxModel();
private final Map<Long, String> dataSourceMap;
@ -45,27 +47,87 @@ public class IntraCasePanel extends javax.swing.JPanel {
public IntraCasePanel() {
initComponents();
this.dataSourceMap = new HashMap<>();
this.singleDataSource = true;
this.onlySpecificDataSourceCheckbox.setEnabled(true);
fileTypeFilterObservable = new Observable() {
@Override
public void notifyObservers() {
//set changed before notify observers
//we want this observerable to always cause the observer to update when notified
this.setChanged();
super.notifyObservers();
}
};
}
public Map<Long, String> getDataSourceMap(){
/**
* Add an Observer to the Observable portion of this panel so that it can be
* notified of changes to this panel.
*
* @param observer the object which is observing this panel
*/
void addObserver(Observer observer) {
fileTypeFilterObservable.addObserver(observer);
}
/**
* Get the map of datasources which was used to populate the combo box on
* this panel.
*
* @return an unmodifiable copy of the map of datasources
*/
Map<Long, String> getDataSourceMap() {
return Collections.unmodifiableMap(this.dataSourceMap);
}
/**
* Get the ID for the datasource selected in the combo box.
*
* @return the selected datasource ID or
* IntraCasePanel.NO_DATA_SOURCE_SELECTED if none is selected
*/
Long getSelectedDataSourceId() {
if(!this.singleDataSource){
return IntraCasePanel.NO_DATA_SOURCE_SELECTED;
}
if (onlySpecificDataSourceCheckbox.isSelected()) {
for (Entry<Long, String> entry : this.dataSourceMap.entrySet()) {
if (entry.getValue().equals(this.selectDataSourceComboBox.getSelectedItem())) {
return entry.getKey();
}
}
}
return IntraCasePanel.NO_DATA_SOURCE_SELECTED;
}
/**
* If the user has selected to show only results of specific file types.
*
* @return if the selected file categories button is selected, true for
* selected false for not selected
*/
boolean fileCategoriesButtonIsSelected() {
return selectedFileCategoriesButton.isSelected();
}
/**
* If the user has selected selected to show Picture and Video files as part
* of the filtered results.
*
* @return if the pictures and video checkbox is enabled AND selected, true
* for enabled AND selected false for not selected OR not enabled
*/
boolean pictureVideoCheckboxIsSelected() {
return pictureVideoCheckbox.isEnabled() && pictureVideoCheckbox.isSelected();
}
/**
* If the user has selected selected to show Document files as part of the
* filtered results.
*
* @return if the documents checkbox is enabled AND selected, true for
* enabled AND selected false for not selected OR not enabled
*/
boolean documentsCheckboxIsSelected() {
return documentsCheckbox.isEnabled() && documentsCheckbox.isSelected();
}
/**
* 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
@ -76,32 +138,67 @@ public class IntraCasePanel extends javax.swing.JPanel {
private void initComponents() {
buttonGroup = new javax.swing.ButtonGroup();
allDataSourcesRadioButton = new javax.swing.JRadioButton();
withinDataSourceRadioButton = new javax.swing.JRadioButton();
selectDataSourceComboBox = new javax.swing.JComboBox<>();
buttonGroup.add(allDataSourcesRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(allDataSourcesRadioButton, org.openide.util.NbBundle.getMessage(IntraCasePanel.class, "IntraCasePanel.allDataSourcesRadioButton.text")); // NOI18N
allDataSourcesRadioButton.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
allDataSourcesRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
allDataSourcesRadioButtonActionPerformed(evt);
}
});
buttonGroup.add(withinDataSourceRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(withinDataSourceRadioButton, org.openide.util.NbBundle.getMessage(IntraCasePanel.class, "IntraCasePanel.withinDataSourceRadioButton.text")); // NOI18N
withinDataSourceRadioButton.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
withinDataSourceRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
withinDataSourceRadioButtonActionPerformed(evt);
}
});
categoriesLabel = new javax.swing.JLabel();
selectedFileCategoriesButton = new javax.swing.JRadioButton();
pictureVideoCheckbox = new javax.swing.JCheckBox();
documentsCheckbox = new javax.swing.JCheckBox();
allFileCategoriesRadioButton = new javax.swing.JRadioButton();
onlySpecificDataSourceCheckbox = new javax.swing.JCheckBox();
selectDataSourceComboBox.setModel(dataSourcesList);
selectDataSourceComboBox.setActionCommand(org.openide.util.NbBundle.getMessage(IntraCasePanel.class, "IntraCasePanel.selectDataSourceComboBox.actionCommand")); // NOI18N
selectDataSourceComboBox.setEnabled(false);
org.openide.awt.Mnemonics.setLocalizedText(categoriesLabel, org.openide.util.NbBundle.getMessage(IntraCasePanel.class, "IntraCasePanel.categoriesLabel.text")); // NOI18N
categoriesLabel.setName(""); // NOI18N
buttonGroup.add(selectedFileCategoriesButton);
org.openide.awt.Mnemonics.setLocalizedText(selectedFileCategoriesButton, org.openide.util.NbBundle.getMessage(IntraCasePanel.class, "IntraCasePanel.selectedFileCategoriesButton.text")); // NOI18N
selectedFileCategoriesButton.setToolTipText(org.openide.util.NbBundle.getMessage(IntraCasePanel.class, "IntraCasePanel.selectedFileCategoriesButton.toolTipText")); // NOI18N
selectedFileCategoriesButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
selectedFileCategoriesButtonActionPerformed(evt);
}
});
pictureVideoCheckbox.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(pictureVideoCheckbox, org.openide.util.NbBundle.getMessage(IntraCasePanel.class, "IntraCasePanel.pictureVideoCheckbox.text")); // NOI18N
pictureVideoCheckbox.setEnabled(false);
pictureVideoCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
pictureVideoCheckboxActionPerformed(evt);
}
});
documentsCheckbox.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(documentsCheckbox, org.openide.util.NbBundle.getMessage(IntraCasePanel.class, "IntraCasePanel.documentsCheckbox.text")); // NOI18N
documentsCheckbox.setEnabled(false);
documentsCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
documentsCheckboxActionPerformed(evt);
}
});
buttonGroup.add(allFileCategoriesRadioButton);
allFileCategoriesRadioButton.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(allFileCategoriesRadioButton, org.openide.util.NbBundle.getMessage(IntraCasePanel.class, "IntraCasePanel.allFileCategoriesRadioButton.text")); // NOI18N
allFileCategoriesRadioButton.setToolTipText(org.openide.util.NbBundle.getMessage(IntraCasePanel.class, "IntraCasePanel.allFileCategoriesRadioButton.toolTipText")); // NOI18N
allFileCategoriesRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
allFileCategoriesRadioButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(onlySpecificDataSourceCheckbox, org.openide.util.NbBundle.getMessage(IntraCasePanel.class, "IntraCasePanel.onlySpecificDataSourceCheckbox.text")); // NOI18N
onlySpecificDataSourceCheckbox.setMaximumSize(new java.awt.Dimension(243, 23));
onlySpecificDataSourceCheckbox.setMinimumSize(new java.awt.Dimension(243, 23));
onlySpecificDataSourceCheckbox.setPreferredSize(new java.awt.Dimension(243, 23));
onlySpecificDataSourceCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
onlySpecificDataSourceCheckboxActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
@ -109,63 +206,109 @@ public class IntraCasePanel extends javax.swing.JPanel {
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(allDataSourcesRadioButton)
.addComponent(withinDataSourceRadioButton)))
.addGap(21, 21, 21)
.addComponent(selectDataSourceComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addGap(27, 27, 27)
.addComponent(selectDataSourceComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 261, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(categoriesLabel)
.addGroup(layout.createSequentialGroup()
.addGap(19, 19, 19)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(allFileCategoriesRadioButton)
.addComponent(selectedFileCategoriesButton)
.addGroup(layout.createSequentialGroup()
.addGap(21, 21, 21)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(documentsCheckbox)
.addComponent(pictureVideoCheckbox))))))
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
.addComponent(onlySpecificDataSourceCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, 384, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(allDataSourcesRadioButton)
.addContainerGap()
.addComponent(onlySpecificDataSourceCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(withinDataSourceRadioButton)
.addComponent(selectDataSourceComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(categoriesLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(selectDataSourceComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(allFileCategoriesRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(selectedFileCategoriesButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(pictureVideoCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(documentsCheckbox)
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
private void allDataSourcesRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_allDataSourcesRadioButtonActionPerformed
selectDataSourceComboBox.setEnabled(!allDataSourcesRadioButton.isSelected());
singleDataSource = false;
}//GEN-LAST:event_allDataSourcesRadioButtonActionPerformed
private void selectedFileCategoriesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectedFileCategoriesButtonActionPerformed
//When the selectedFileCategoriesButton is selected enable its related options
//and notify observers that the panel has changed incase the current settings are invalid
pictureVideoCheckbox.setEnabled(true);
documentsCheckbox.setEnabled(true);
fileTypeFilterObservable.notifyObservers();
}//GEN-LAST:event_selectedFileCategoriesButtonActionPerformed
private void withinDataSourceRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_withinDataSourceRadioButtonActionPerformed
withinDataSourceSelected(withinDataSourceRadioButton.isSelected());
}//GEN-LAST:event_withinDataSourceRadioButtonActionPerformed
private void allFileCategoriesRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_allFileCategoriesRadioButtonActionPerformed
//When the allFileCategoriesRadioButton is selected disable the options
//related to selected file categories and notify observers that the panel has changed
//incase the current settings are invalid
pictureVideoCheckbox.setEnabled(false);
documentsCheckbox.setEnabled(false);
fileTypeFilterObservable.notifyObservers();
}//GEN-LAST:event_allFileCategoriesRadioButtonActionPerformed
private void withinDataSourceSelected(boolean selected) {
selectDataSourceComboBox.setEnabled(selected);
private void onlySpecificDataSourceCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_onlySpecificDataSourceCheckboxActionPerformed
//When the onlySpecificDataSourceCheckbox is clicked update its related options
selectDataSourceComboBox.setEnabled(onlySpecificDataSourceCheckbox.isSelected());
if (selectDataSourceComboBox.isEnabled()) {
selectDataSourceComboBox.setSelectedIndex(0);
singleDataSource = true;
}
}
}//GEN-LAST:event_onlySpecificDataSourceCheckboxActionPerformed
private void pictureVideoCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pictureVideoCheckboxActionPerformed
//notify observers that the panel has changed incase the current settings are invalid
fileTypeFilterObservable.notifyObservers();
}//GEN-LAST:event_pictureVideoCheckboxActionPerformed
private void documentsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_documentsCheckboxActionPerformed
//notify observers that the panel has changed incase the current settings are invalid
fileTypeFilterObservable.notifyObservers();
}//GEN-LAST:event_documentsCheckboxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JRadioButton allDataSourcesRadioButton;
private javax.swing.JRadioButton allFileCategoriesRadioButton;
private javax.swing.ButtonGroup buttonGroup;
private javax.swing.JLabel categoriesLabel;
private javax.swing.JCheckBox documentsCheckbox;
private javax.swing.JCheckBox onlySpecificDataSourceCheckbox;
private javax.swing.JCheckBox pictureVideoCheckbox;
private javax.swing.JComboBox<String> selectDataSourceComboBox;
private javax.swing.JRadioButton withinDataSourceRadioButton;
private javax.swing.JRadioButton selectedFileCategoriesButton;
// End of variables declaration//GEN-END:variables
void setDataModel(DataSourceComboBoxModel dataSourceComboBoxModel) {
/**
* Set the datamodel for the combo box which displays the data sources in
* the current case
*
* @param dataSourceComboBoxModel the DataSourceComboBoxModel to use
*/
void setDatasourceComboboxModel(DataSourceComboBoxModel dataSourceComboBoxModel) {
this.dataSourcesList = dataSourceComboBoxModel;
this.selectDataSourceComboBox.setModel(dataSourcesList);
}
void rigForMultipleDataSources(boolean multipleDataSources) {
this.withinDataSourceRadioButton.setEnabled(multipleDataSources);
this.allDataSourcesRadioButton.setSelected(!multipleDataSources);
this.withinDataSourceRadioButton.setSelected(multipleDataSources);
this.withinDataSourceSelected(multipleDataSources);
}
/**
* Update the map of datasources that this panel allows the user to select
* from
*
* @param dataSourceMap A map of datasources
*/
void setDataSourceMap(Map<Long, String> dataSourceMap) {
this.dataSourceMap.clear();
this.dataSourceMap.putAll(dataSourceMap);

View File

@ -20,13 +20,17 @@
package org.sleuthkit.autopsy.commonfilesearch;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance.Type;
import static org.sleuthkit.autopsy.commonfilesearch.AbstractCommonAttributeSearcher.MEDIA_PICS_VIDEO_MIME_TYPES;
/**
*
@ -42,11 +46,14 @@ public class SingleInterCaseCommonAttributeSearcher extends InterCaseCommonAttri
* @param correlationCaseId
* @param filterByMediaMimeType
* @param filterByDocMimeType
* @param corAttrType
* @param percentageThreshold
*
* @throws EamDbException
*/
public SingleInterCaseCommonAttributeSearcher(int correlationCaseId, Map<Long, String> dataSourceIdMap, boolean filterByMediaMimeType,
public SingleInterCaseCommonAttributeSearcher(int correlationCaseId, boolean filterByMediaMimeType,
boolean filterByDocMimeType, Type corAttrType, int percentageThreshold) throws EamDbException {
super(dataSourceIdMap, filterByMediaMimeType, filterByDocMimeType, corAttrType, percentageThreshold);
super(filterByMediaMimeType, filterByDocMimeType, corAttrType, percentageThreshold);
this.corrleationCaseId = correlationCaseId;
this.correlationCaseName = "";
@ -56,9 +63,8 @@ public class SingleInterCaseCommonAttributeSearcher extends InterCaseCommonAttri
* Collect metadata required to render the tree table where matches must
* occur in the case with the given ID.
*
* @param correlationCaseId id of case where matches must occur (no other
* matches will be shown)
* @return business object needed to populate tree table with results
*
* @throws TskCoreException
* @throws NoCurrentCaseException
* @throws SQLException
@ -73,15 +79,30 @@ public class SingleInterCaseCommonAttributeSearcher extends InterCaseCommonAttri
}
CommonAttributeSearchResults findFiles(CorrelationCase correlationCase) throws TskCoreException, NoCurrentCaseException, SQLException, EamDbException {
InterCaseSearchResultsProcessor eamDbAttrInst = new InterCaseSearchResultsProcessor(this.getDataSourceIdToNameMap(), this.corAttrType);
InterCaseSearchResultsProcessor eamDbAttrInst = new InterCaseSearchResultsProcessor(this.corAttrType);
Map<Integer, CommonAttributeValueList> interCaseCommonFiles = eamDbAttrInst.findSingleInterCaseCommonAttributeValues(Case.getCurrentCase(), correlationCase);
return new CommonAttributeSearchResults(interCaseCommonFiles, this.frequencyPercentageThreshold, this.corAttrType);
Set<String> mimeTypesToFilterOn = new HashSet<>();
if (isFilterByMedia()) {
mimeTypesToFilterOn.addAll(MEDIA_PICS_VIDEO_MIME_TYPES);
}
if (isFilterByDoc()) {
mimeTypesToFilterOn.addAll(TEXT_FILES_MIME_TYPES);
}
return new CommonAttributeSearchResults(interCaseCommonFiles, this.frequencyPercentageThreshold, this.corAttrType, mimeTypesToFilterOn);
}
@NbBundle.Messages({
"# {0} - case name",
"# {1} - attr type",
"# {2} - threshold string",
"SingleInterCaseCommonAttributeSearcher.buildTabTitle.titleInterSingle=Common Properties (Central Repository Case: {0}, {1}{2})"})
@Override
String buildTabTitle() {
final String titleTemplate = Bundle.AbstractCommonFilesMetadataBuilder_buildTabTitle_titleInterSingle();
return String.format(titleTemplate, new Object[]{this.correlationCaseName, this.corAttrType.getDisplayName()});
String getTabTitle() {
String typeString = this.corAttrType.getDisplayName();
if (typeString.equals("Files")) {
typeString = this.buildCategorySelectionString();
}
return Bundle.SingleInterCaseCommonAttributeSearcher_buildTabTitle_titleInterSingle(this.correlationCaseName, typeString, this.getPercentThresholdString());
}
}

View File

@ -20,6 +20,7 @@
package org.sleuthkit.autopsy.commonfilesearch;
import java.util.Map;
import org.openide.util.NbBundle;
import org.sleuthkit.datamodel.TskData.FileKnown;
/**
@ -34,12 +35,15 @@ final public class SingleIntraCaseCommonAttributeSearcher extends IntraCaseCommo
/**
* Implements the algorithm for getting common files that appear at least
* once in the given data source
* @param dataSourceId data source id for which common files must appear at least once
*
* @param dataSourceId data source id for which common files must
* appear at least once
* @param dataSourceIdMap a map of obj_id to datasource name
* @param filterByMediaMimeType match only on files whose mime types can be
* broadly categorized as media types
* @param filterByDocMimeType match only on files whose mime types can be
* broadly categorized as document types
* @param percentageThreshold omit any matches with frequency above this threshold
*/
public SingleIntraCaseCommonAttributeSearcher(Long dataSourceId, Map<Long, String> dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType, int percentageThreshold) {
super(dataSourceIdMap, filterByMediaMimeType, filterByDocMimeType, percentageThreshold);
@ -53,10 +57,13 @@ final public class SingleIntraCaseCommonAttributeSearcher extends IntraCaseCommo
return String.format(SingleIntraCaseCommonAttributeSearcher.WHERE_CLAUSE, args);
}
@NbBundle.Messages({
"# {0} - data source name",
"# {1} - build category",
"# {2} - threshold string",
"SingleIntraCaseCommonAttributeSearcher.buildTabTitle.titleIntraSingle=Common Properties (Data Source: {0}, {1}{2})"})
@Override
public String buildTabTitle() {
final String buildCategorySelectionString = this.buildCategorySelectionString();
final String titleTemplate = Bundle.AbstractCommonFilesMetadataBuilder_buildTabTitle_titleIntraSingle();
return String.format(titleTemplate, new Object[]{this.dataSourceName, buildCategorySelectionString});
String getTabTitle() {
return Bundle.SingleIntraCaseCommonAttributeSearcher_buildTabTitle_titleIntraSingle(this.dataSourceName, this.buildCategorySelectionString(), this.getPercentThresholdString());
}
}

View File

@ -24,6 +24,8 @@ import java.util.logging.Level;
import org.apache.commons.lang3.StringUtils;
import org.openide.nodes.Sheet;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
@ -68,10 +70,18 @@ final class RelationshipNode extends BlackboardArtifactNode {
}
sheetSet.put(new NodeProperty<>("Type", "Type", "Type", getDisplayName()));
CorrelationAttributeInstance correlationAttribute = getCorrelationAttributeInstance();
addScoreProperty(sheetSet, tags);
CorrelationAttributeInstance correlationAttribute = null;
if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
correlationAttribute = getCorrelationAttributeInstance();
}
addCommentProperty(sheetSet, tags, correlationAttribute);
if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
addCountProperty(sheetSet, correlationAttribute);
}
final BlackboardArtifact artifact = getArtifact();
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(getArtifact().getArtifactTypeID());
if (null != fromID) {
@ -120,7 +130,6 @@ final class RelationshipNode extends BlackboardArtifactNode {
break;
}
}
addTagProperty(sheetSet, tags);
return sheet;
}

View File

@ -234,12 +234,12 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
}
if (commentDataFound == false) {
addMessage(html, "There is no comment data for the selected content in the central repository.");
addMessage(html, "There is no comment data for the selected content in the Central Repository.");
}
} catch (EamDbException | TskCoreException ex) {
logger.log(Level.SEVERE, "Error connecting to the central repository database.", ex); // NON-NLS
logger.log(Level.SEVERE, "Error connecting to the Central Repository database.", ex); // NON-NLS
} catch (CorrelationAttributeNormalizationException ex) {
logger.log(Level.SEVERE, "Error normalizing instance from repository database.", ex); // NON-NLS
logger.log(Level.SEVERE, "Error normalizing instance from Central Repository database.", ex); // NON-NLS
}
endSection(html);
}
@ -273,7 +273,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
* @param message The message text.
*/
private void addMessage(StringBuilder html, String message) {
html.append("<p style=\"font-style:italic;\">")
html.append("<p style=\"font-size:11px;font-style:italic;\">")
.append(message)
.append("</p><br>"); //NON-NLS
}
@ -299,12 +299,11 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
/**
* Add a data table containing information about a correlation attribute
* instance in the central repository.
* instance in the Central Repository.
*
* @param html The HTML text to add the table to.
* @param attributeInstance The attribute instance whose information will be
* used to populate the table.
* @param correlationType The correlation data type.
*/
@NbBundle.Messages({
"AnnotationsContentViewer.centralRepositoryEntryDataLabel.case=Case:",

View File

@ -37,6 +37,8 @@ import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
import org.sleuthkit.autopsy.corecomponents.DataResultPanel;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
@ -729,15 +731,22 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
AbstractFile file = getContent();
sheetSet.put(new NodeProperty<>("Name", "Name", "Name", file.getName()));
CorrelationAttributeInstance correlationAttribute = getCorrelationAttributeInstance();
addScoreProperty(sheetSet, tags);
CorrelationAttributeInstance correlationAttribute = null;
if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
correlationAttribute = getCorrelationAttributeInstance();
}
addCommentProperty(sheetSet, tags, correlationAttribute);
if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
addCountProperty(sheetSet, correlationAttribute);
}
sheetSet.put(new NodeProperty<>("Size", "Size", "Size", file.getSize()));
sheetSet.put(new NodeProperty<>("Mime Type", "Mime Type", "Mime Type", StringUtils.defaultString(file.getMIMEType())));
sheetSet.put(new NodeProperty<>("Known", "Known", "Known", file.getKnown().getName()));
addTagProperty(sheetSet, tags);
return sheet;
}
}

View File

@ -22,16 +22,24 @@ import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Cursor;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.logging.Level;
import java.util.stream.Collectors;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
@ -43,11 +51,8 @@ import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.tabulardatareader.AbstractReader;
import org.sleuthkit.autopsy.tabulardatareader.AbstractReader.FileReaderException;
import org.sleuthkit.autopsy.tabulardatareader.AbstractReader.FileReaderInitException;
import org.sleuthkit.autopsy.tabulardatareader.FileReaderFactory;
/**
* A file content viewer for SQLite database files.
@ -62,7 +67,7 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
private final SQLiteTableView selectedTableView = new SQLiteTableView();
private AbstractFile sqliteDbFile;
private File tmpDbFile;
private AbstractReader sqliteReader;
private Connection connection;
private int numRows; // num of rows in the selected table
private int currPage = 0; // curr page of rows being displayed
@ -339,9 +344,13 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
numEntriesField.setText("");
// close DB connection to file
if (null != sqliteReader) {
sqliteReader.close();
sqliteReader = null;
if (null != connection) {
try {
connection.close();
connection = null;
} catch (SQLException ex) {
logger.log(Level.SEVERE, "Failed to close DB connection to file.", ex); //NON-NLS
}
}
sqliteDbFile = null;
@ -359,45 +368,65 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
"SQLiteViewer.errorMessage.failedToinitJDBCDriver=The JDBC driver for SQLite could not be loaded.",
"# {0} - exception message", "SQLiteViewer.errorMessage.unexpectedError=An unexpected error occurred:\n{0).",})
private void processSQLiteFile() {
tablesDropdownList.removeAllItems();
try {
String localDiskPath = Case.getCurrentCaseThrows().getTempDirectory() +
File.separator + sqliteDbFile.getName();
sqliteReader = FileReaderFactory.createReader(SUPPORTED_MIMETYPES[0], sqliteDbFile, localDiskPath);
Map<String, String> dbTablesMap = sqliteReader.getTableSchemas();
String localDiskPath = SqliteUtil.writeAbstractFileToLocalDisk(sqliteDbFile);
SqliteUtil.findAndCopySQLiteMetaFile(sqliteDbFile);
// Load the SQLite JDBC driver, if necessary.
Class.forName("org.sqlite.JDBC"); //NON-NLS
connection = DriverManager.getConnection("jdbc:sqlite:" + localDiskPath); //NON-NLS
Collection<String> dbTablesMap = getTables();
if (dbTablesMap.isEmpty()) {
tablesDropdownList.addItem(Bundle.SQLiteViewer_comboBox_noTableEntry());
tablesDropdownList.setEnabled(false);
} else {
dbTablesMap.keySet().forEach((tableName) -> {
dbTablesMap.forEach((tableName) -> {
tablesDropdownList.addItem(tableName);
});
}
} catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Current case has been closed", ex); //NON-NLS
MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_errorMessage_noCurrentCase());
} catch (FileReaderException ex) {
logger.log(Level.SEVERE, String.format(
"Failed to get tables from DB file '%s' (objId=%d)", //NON-NLS
sqliteDbFile.getName(), sqliteDbFile.getId()), ex);
MessageNotifyUtil.Message.error(
Bundle.SQLiteViewer_errorMessage_failedToQueryDatabase());
} catch (FileReaderInitException ex) {
logger.log(Level.SEVERE, String.format(
"Failed to create a SQLiteReader '%s' (objId=%d)", //NON-NLS
sqliteDbFile.getName(), sqliteDbFile.getId()), ex);
} catch (ClassNotFoundException ex) {
logger.log(Level.SEVERE, String.format("Failed to initialize JDBC SQLite '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_errorMessage_failedToinitJDBCDriver());
} catch (SQLException ex) {
logger.log(Level.SEVERE, String.format("Failed to get tables from DB file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_errorMessage_failedToQueryDatabase());
} catch (IOException | NoCurrentCaseException | TskCoreException ex) {
logger.log(Level.SEVERE, String.format("Failed to create temp copy of DB file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_errorMessage_failedToExtractFile());
}
}
/**
* Gets a collection of table names from the SQLite database file.
*
* @return A collection of table names
*/
private Collection<String> getTables() throws SQLException {
Collection<String> tableNames = new LinkedList<>();
try (Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(
"SELECT name FROM sqlite_master "
+ " WHERE type= 'table' ")){
while (resultSet.next()) {
tableNames.add(resultSet.getString("name")); //NON-NLS
}
}
return tableNames;
}
@NbBundle.Messages({"# {0} - tableName",
"SQLiteViewer.selectTable.errorText=Error getting row count for table: {0}"
})
private void selectTable(String tableName) {
try {
numRows = sqliteReader.getRowCountFromTable(tableName);
try (Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(
"SELECT count (*) as count FROM " + "\"" + tableName + "\"")) { //NON-NLS{
numRows = resultSet.getInt("count");
numEntriesField.setText(numRows + " entries");
currPage = 1;
@ -416,12 +445,9 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
selectedTableView.setupTable(Collections.emptyList());
}
} catch (FileReaderException ex) {
logger.log(Level.SEVERE, String.format(
"Failed to load table %s from DB file '%s' (objId=%d)", tableName, //NON-NLS
sqliteDbFile.getName(), sqliteDbFile.getId()), ex);
MessageNotifyUtil.Message.error(
Bundle.SQLiteViewer_selectTable_errorText(tableName));
} catch (SQLException ex) {
logger.log(Level.SEVERE, String.format("Failed to load table %s from DB file '%s' (objId=%d)", tableName, sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_selectTable_errorText(tableName));
}
}
@ -429,40 +455,63 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
"SQLiteViewer.readTable.errorText=Error getting rows for table: {0}"})
private void readTable(String tableName, int startRow, int numRowsToRead) {
try {
List<Map<String, Object>> rows = sqliteReader.getRowsFromTable(
tableName, startRow, numRowsToRead);
try (
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(
"SELECT * FROM " + "\"" + tableName + "\""
+ " LIMIT " + Integer.toString(numRowsToRead)
+ " OFFSET " + Integer.toString(startRow - 1))) {
List<Map<String, Object>> rows = resultSetToArrayList(resultSet);
if (Objects.nonNull(rows)) {
selectedTableView.setupTable(rows);
} else {
selectedTableView.setupTable(Collections.emptyList());
}
} catch (FileReaderException ex) {
logger.log(Level.SEVERE, String.format(
"Failed to read table %s from DB file '%s' (objId=%d)", tableName, //NON-NLS
sqliteDbFile.getName(), sqliteDbFile.getId()), ex);
MessageNotifyUtil.Message.error(
Bundle.SQLiteViewer_readTable_errorText(tableName));
} catch (SQLException ex) {
logger.log(Level.SEVERE, String.format("Failed to read table %s from DB file '%s' (objId=%d)", tableName, sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_readTable_errorText(tableName));
}
}
/**
* Converts a sqlite table into a CSV file.
*
* @param file
* @param tableName
* @param rowMap A list of rows in the table, where each row is represented as a column-value
* map.
* @throws FileNotFoundException
* @throws IOException
*/
@NbBundle.Messages({
@NbBundle.Messages("SQLiteViewer.BlobNotShown.message=BLOB Data not shown")
private List<Map<String, Object>> resultSetToArrayList(ResultSet resultSet) throws SQLException {
ResultSetMetaData metaData = resultSet.getMetaData();
int columns = metaData.getColumnCount();
ArrayList<Map<String, Object>> rowlist = new ArrayList<>();
while (resultSet.next()) {
Map<String, Object> row = new LinkedHashMap<>(columns);
for (int i = 1; i <= columns; ++i) {
if (resultSet.getObject(i) == null) {
row.put(metaData.getColumnName(i), "");
} else {
if (metaData.getColumnTypeName(i).compareToIgnoreCase("blob") == 0) {
row.put(metaData.getColumnName(i), Bundle.SQLiteViewer_BlobNotShown_message());
} else {
row.put(metaData.getColumnName(i), resultSet.getObject(i));
}
}
}
rowlist.add(row);
}
return rowlist;
}
@NbBundle.Messages({"SQLiteViewer.exportTableToCsv.write.errText=Failed to export table content to csv file.",
"SQLiteViewer.exportTableToCsv.FileName=File name: ",
"SQLiteViewer.exportTableToCsv.TableName=Table name: "
})
public void exportTableToCSV(File file, String tableName,
List<Map<String, Object>> rowMap) throws FileNotFoundException, IOException{
private void exportTableToCsv(File file) {
String tableName = (String) this.tablesDropdownList.getSelectedItem();
try (
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM " + "\"" + tableName + "\"")) {
List<Map<String, Object>> currentTableRows = resultSetToArrayList(resultSet);
if (Objects.isNull(currentTableRows) || currentTableRows.isEmpty()) {
logger.log(Level.INFO, String.format("The table %s is empty. (objId=%d)", tableName, sqliteDbFile.getId())); //NON-NLS
} else {
File csvFile;
String fileName = file.getName();
if (FilenameUtils.getExtension(fileName).equalsIgnoreCase("csv")) {
@ -475,62 +524,40 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
out.write((Bundle.SQLiteViewer_exportTableToCsv_FileName() + csvFile.getName() + "\n").getBytes());
out.write((Bundle.SQLiteViewer_exportTableToCsv_TableName() + tableName + "\n").getBytes());
String header = createColumnHeader(rowMap.get(0)).concat("\n");
out.write(header.getBytes());
for (Map<String, Object> maps : rowMap) {
String row = maps.values()
.stream()
.map(Object::toString)
.collect(Collectors.joining(","))
.concat("\n");
out.write(row.getBytes());
}
}
}
@NbBundle.Messages({
"SQLiteViewer.exportTableToCsv.write.errText=Failed to export table content to csv file.",
})
private void exportTableToCsv(File file) {
String tableName = (String) this.tablesDropdownList.getSelectedItem();
try {
List<Map<String, Object>> currentTableRows =
sqliteReader.getRowsFromTable(tableName);
if (Objects.isNull(currentTableRows) || currentTableRows.isEmpty()) {
logger.log(Level.INFO, String.format(
"The table %s is empty. (objId=%d)", tableName, //NON-NLS
sqliteDbFile.getId()));
// Set up the column names
Map<String, Object> row = currentTableRows.get(0);
StringBuffer header = new StringBuffer();
for (Map.Entry<String, Object> col : row.entrySet()) {
String colName = col.getKey();
if (header.length() > 0) {
header.append(',').append(colName);
} else {
exportTableToCSV(file, tableName, currentTableRows);
header.append(colName);
}
} catch (FileReaderException ex) {
logger.log(Level.SEVERE, String.format(
"Failed to read table %s from DB file '%s' (objId=%d)", //NON-NLS
tableName, sqliteDbFile.getName(), sqliteDbFile.getId()), ex);
MessageNotifyUtil.Message.error(
Bundle.SQLiteViewer_readTable_errorText(tableName));
}
out.write(header.append('\n').toString().getBytes());
for (Map<String, Object> maps : currentTableRows) {
StringBuffer valueLine = new StringBuffer();
maps.values().forEach((value) -> {
if (valueLine.length() > 0) {
valueLine.append(',').append(value.toString());
} else {
valueLine.append(value.toString());
}
});
out.write(valueLine.append('\n').toString().getBytes());
}
}
}
} catch (SQLException ex) {
logger.log(Level.SEVERE, String.format("Failed to read table %s from DB file '%s' (objId=%d)", tableName, sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_readTable_errorText(tableName));
} catch (IOException ex) {
logger.log(Level.SEVERE, String.format(
"Failed to export table %s to file '%s'", tableName, file.getName()), ex); //NON-NLS
MessageNotifyUtil.Message.error(
Bundle.SQLiteViewer_exportTableToCsv_write_errText());
logger.log(Level.SEVERE, String.format("Failed to export table %s to file '%s'", tableName, file.getName()), ex); //NON-NLS
MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_exportTableToCsv_write_errText());
}
}
/**
* Returns a comma seperated header string from the keys of the column
* row map.
*
* @param row column header row map
* @return comma seperated header string
*/
private String createColumnHeader(Map<String, Object> row) {
return row.entrySet()
.stream()
.map(Map.Entry::getKey)
.collect(Collectors.joining(","));
}
}

View File

@ -0,0 +1,130 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018-2018 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.contentviewers;
import java.io.File;
import java.io.IOException;
import java.util.List;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.services.FileManager;
import org.sleuthkit.autopsy.casemodule.services.Services;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Sqlite utility class. Find and copy metafiles, write sqlite abstract files to
* temp directory, and generate unique temp directory paths.
*/
final class SqliteUtil {
private SqliteUtil() {
}
/**
* Overloaded implementation of
* {@link #findAndCopySQLiteMetaFile(AbstractFile, String) findAndCopySQLiteMetaFile}
* , automatically tries to copy -wal and -shm files without needing to know
* their existence.
*
* @param sqliteFile file which has -wal and -shm meta files
*
* @throws NoCurrentCaseException Case has been closed.
* @throws TskCoreException fileManager cannot find AbstractFile
* files.
* @throws IOException Issue during writing to file.
*/
public static void findAndCopySQLiteMetaFile(AbstractFile sqliteFile)
throws NoCurrentCaseException, TskCoreException, IOException {
findAndCopySQLiteMetaFile(sqliteFile, sqliteFile.getName() + "-wal");
findAndCopySQLiteMetaFile(sqliteFile, sqliteFile.getName() + "-shm");
}
/**
* Searches for a meta file associated with the give SQLite database. If
* found, it copies this file into the temp directory of the current case.
*
* @param sqliteFile file being processed
* @param metaFileName name of meta file to look for
*
* @throws NoCurrentCaseException Case has been closed.
* @throws TskCoreException fileManager cannot find AbstractFile
* files.
* @throws IOException Issue during writing to file.
*/
public static void findAndCopySQLiteMetaFile(AbstractFile sqliteFile,
String metaFileName) throws NoCurrentCaseException, TskCoreException, IOException {
Case openCase = Case.getCurrentCaseThrows();
SleuthkitCase sleuthkitCase = openCase.getSleuthkitCase();
Services services = new Services(sleuthkitCase);
FileManager fileManager = services.getFileManager();
List<AbstractFile> metaFiles = fileManager.findFiles(
sqliteFile.getDataSource(), metaFileName,
sqliteFile.getParent().getName());
if (metaFiles != null) {
for (AbstractFile metaFile : metaFiles) {
writeAbstractFileToLocalDisk(metaFile);
}
}
}
/**
* Copies the file contents into a unique path in the current case temp
* directory.
*
* @param file AbstractFile from the data source
*
* @return The path of the file on disk
*
* @throws IOException Exception writing file contents
* @throws NoCurrentCaseException Current case closed during file copying
*/
public static String writeAbstractFileToLocalDisk(AbstractFile file)
throws IOException, NoCurrentCaseException {
String localDiskPath = getUniqueTempDirectoryPath(file);
File localDatabaseFile = new File(localDiskPath);
if (!localDatabaseFile.exists()) {
ContentUtils.writeToFile(file, localDatabaseFile);
}
return localDiskPath;
}
/**
* Generates a unique local disk path that resides in the temp directory of
* the current case.
*
* @param file The database abstract file
*
* @return Unique local disk path living in the temp directory of the case
*
* @throws org.sleuthkit.autopsy.casemodule.NoCurrentCaseException
*/
public static String getUniqueTempDirectoryPath(AbstractFile file) throws NoCurrentCaseException {
return Case.getCurrentCaseThrows().getTempDirectory()
+ File.separator + file.getId() + file.getName();
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2017 Basis Technology Corp.
* Copyright 2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -71,6 +71,7 @@ public final class UserPreferences {
private static final int LOG_FILE_NUM_INT = 10;
public static final String GROUP_ITEMS_IN_TREE_BY_DATASOURCE = "GroupItemsInTreeByDataSource"; //NON-NLS
public static final String SHOW_ONLY_CURRENT_USER_TAGS = "ShowOnlyCurrentUserTags";
public static final String HIDE_CENTRAL_REPO_COMMENTS_AND_OCCURRENCES = "HideCentralRepoCommentsAndOccurrences";
// Prevent instantiation.
private UserPreferences() {
@ -189,10 +190,12 @@ public final class UserPreferences {
preferences.putInt(NUMBER_OF_FILE_INGEST_THREADS, value);
}
@Deprecated
public static boolean groupItemsInTreeByDatasource() {
return preferences.getBoolean(GROUP_ITEMS_IN_TREE_BY_DATASOURCE, false);
}
@Deprecated
public static void setGroupItemsInTreeByDatasource(boolean value) {
preferences.putBoolean(GROUP_ITEMS_IN_TREE_BY_DATASOURCE, value);
}
@ -218,6 +221,30 @@ public final class UserPreferences {
preferences.putBoolean(SHOW_ONLY_CURRENT_USER_TAGS, value);
}
/**
* Get the user preference which identifies whether the Central Repository
* should be called to get comments and occurrences for the (C)omments and
* (O)ccurrences columns in the result view.
*
* @return True if hiding Central Repository data for comments and
* occurrences; otherwise false.
*/
public static boolean hideCentralRepoCommentsAndOccurrences() {
return preferences.getBoolean(HIDE_CENTRAL_REPO_COMMENTS_AND_OCCURRENCES, false);
}
/**
* Set the user preference which identifies whether the Central Repository
* should be called to get comments and occurrences for the (C)omments and
* (O)ccurrences columns in the result view.
*
* @param value The value of which to assign to the user preference.
*/
public static void setHideCentralRepoCommentsAndOccurrences(boolean value) {
preferences.putBoolean(HIDE_CENTRAL_REPO_COMMENTS_AND_OCCURRENCES, value);
}
/**
* Reads persisted case database connection info.
*

View File

@ -35,7 +35,7 @@
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="jScrollPane1" pref="479" max="32767" attributes="0"/>
<Component id="jScrollPane1" max="32767" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
@ -64,15 +64,11 @@
<Layout>
<DimensionLayout dim="0">
<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="1" attributes="0">
<Component id="logoPanel" pref="1010" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="viewPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="runtimePanel" max="32767" attributes="0"/>
</Group>
<Component id="logoPanel" alignment="0" pref="1002" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
@ -81,14 +77,11 @@
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="viewPanel" max="32767" attributes="0"/>
<Component id="runtimePanel" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="runtimePanel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="logoPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<EmptySpace pref="185" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -128,7 +121,7 @@
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="agencyLogoPreview" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<EmptySpace pref="479" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -232,219 +225,6 @@
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="viewPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="View">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.viewPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="useGMTTimeRB" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="keepCurrentViewerRB" min="-2" max="-2" attributes="0"/>
<Component id="useBestViewerRB" min="-2" max="-2" attributes="0"/>
<Component id="dataSourcesHideKnownCB" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="viewsHideKnownCB" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="dataSourcesHideSlackCB" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="viewsHideSlackCB" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="useLocalTimeRB" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="158" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jLabelHideSlackFiles" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="jLabelTimeDisplay" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="jLabelHideKnownFiles" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="jLabelSelectFile" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="30" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="jLabelSelectFile" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="useBestViewerRB" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="keepCurrentViewerRB" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="jLabelHideKnownFiles" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="dataSourcesHideKnownCB" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="viewsHideKnownCB" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jLabelHideSlackFiles" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="dataSourcesHideSlackCB" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="viewsHideSlackCB" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jLabelTimeDisplay" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="useLocalTimeRB" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="useGMTTimeRB" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="jLabelSelectFile">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.jLabelSelectFile.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JRadioButton" name="useBestViewerRB">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="fileSelectionButtonGroup"/>
</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.useBestViewerRB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.useBestViewerRB.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useBestViewerRBActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="keepCurrentViewerRB">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="fileSelectionButtonGroup"/>
</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.keepCurrentViewerRB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.keepCurrentViewerRB.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="keepCurrentViewerRBActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="jLabelHideKnownFiles">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.jLabelHideKnownFiles.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="dataSourcesHideKnownCB">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.dataSourcesHideKnownCB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="dataSourcesHideKnownCBActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="viewsHideKnownCB">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.viewsHideKnownCB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="viewsHideKnownCBActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="jLabelHideSlackFiles">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.jLabelHideSlackFiles.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="dataSourcesHideSlackCB">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.dataSourcesHideSlackCB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="dataSourcesHideSlackCBActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="viewsHideSlackCB">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.viewsHideSlackCB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="viewsHideSlackCBActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="jLabelTimeDisplay">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.jLabelTimeDisplay.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JRadioButton" name="useLocalTimeRB">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="displayTimesButtonGroup"/>
</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.useLocalTimeRB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useLocalTimeRBActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="useGMTTimeRB">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="displayTimesButtonGroup"/>
</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.useGMTTimeRB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useGMTTimeRBActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="runtimePanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
@ -471,7 +251,7 @@
<Group type="102" attributes="0">
<Component id="maxMemoryUnitsLabel1" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="restartNecessaryWarning" max="32767" attributes="0"/>
<Component id="restartNecessaryWarning" pref="783" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="maxMemoryUnitsLabel" min="-2" max="-2" attributes="0"/>

View File

@ -285,16 +285,6 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
* Load the saved user preferences.
*/
void load() {
boolean keepPreferredViewer = UserPreferences.keepPreferredContentViewer();
keepCurrentViewerRB.setSelected(keepPreferredViewer);
useBestViewerRB.setSelected(!keepPreferredViewer);
dataSourcesHideKnownCB.setSelected(UserPreferences.hideKnownFilesInDataSourcesTree());
viewsHideKnownCB.setSelected(UserPreferences.hideKnownFilesInViewsTree());
dataSourcesHideSlackCB.setSelected(UserPreferences.hideSlackFilesInDataSourcesTree());
viewsHideSlackCB.setSelected(UserPreferences.hideSlackFilesInViewsTree());
boolean useLocalTime = UserPreferences.displayTimesInLocalTime();
useLocalTimeRB.setSelected(useLocalTime);
useGMTTimeRB.setSelected(!useLocalTime);
String path = ModuleSettings.getConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP);
boolean useDefault = (path == null || path.isEmpty());
defaultLogoRB.setSelected(useDefault);
@ -350,12 +340,6 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
* Store the current user preferences.
*/
void store() {
UserPreferences.setKeepPreferredContentViewer(keepCurrentViewerRB.isSelected());
UserPreferences.setHideKnownFilesInDataSourcesTree(dataSourcesHideKnownCB.isSelected());
UserPreferences.setHideKnownFilesInViewsTree(viewsHideKnownCB.isSelected());
UserPreferences.setHideSlackFilesInDataSourcesTree(dataSourcesHideSlackCB.isSelected());
UserPreferences.setHideSlackFilesInViewsTree(viewsHideSlackCB.isSelected());
UserPreferences.setDisplayTimesInLocalTime(useLocalTimeRB.isSelected());
UserPreferences.setLogFileCount(Integer.parseInt(logFileCount.getText()));
if (!agencyLogoPathField.getText().isEmpty()) {
File file = new File(agencyLogoPathField.getText());
@ -535,19 +519,6 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
defaultLogoRB = new javax.swing.JRadioButton();
specifyLogoRB = new javax.swing.JRadioButton();
agencyLogoPathFieldValidationLabel = new javax.swing.JLabel();
viewPanel = new javax.swing.JPanel();
jLabelSelectFile = new javax.swing.JLabel();
useBestViewerRB = new javax.swing.JRadioButton();
keepCurrentViewerRB = new javax.swing.JRadioButton();
jLabelHideKnownFiles = new javax.swing.JLabel();
dataSourcesHideKnownCB = new javax.swing.JCheckBox();
viewsHideKnownCB = new javax.swing.JCheckBox();
jLabelHideSlackFiles = new javax.swing.JLabel();
dataSourcesHideSlackCB = new javax.swing.JCheckBox();
viewsHideSlackCB = new javax.swing.JCheckBox();
jLabelTimeDisplay = new javax.swing.JLabel();
useLocalTimeRB = new javax.swing.JRadioButton();
useGMTTimeRB = new javax.swing.JRadioButton();
runtimePanel = new javax.swing.JPanel();
maxMemoryLabel = new javax.swing.JLabel();
maxMemoryUnitsLabel = new javax.swing.JLabel();
@ -624,7 +595,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
.addComponent(agencyLogoPathFieldValidationLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(agencyLogoPreview, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap(479, Short.MAX_VALUE))
);
logoPanelLayout.setVerticalGroup(
logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -643,139 +614,6 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
.addGap(0, 0, Short.MAX_VALUE))
);
viewPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.viewPanel.border.title"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectFile, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelSelectFile.text")); // NOI18N
fileSelectionButtonGroup.add(useBestViewerRB);
org.openide.awt.Mnemonics.setLocalizedText(useBestViewerRB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.useBestViewerRB.text")); // NOI18N
useBestViewerRB.setToolTipText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.useBestViewerRB.toolTipText")); // NOI18N
useBestViewerRB.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
useBestViewerRBActionPerformed(evt);
}
});
fileSelectionButtonGroup.add(keepCurrentViewerRB);
org.openide.awt.Mnemonics.setLocalizedText(keepCurrentViewerRB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.keepCurrentViewerRB.text")); // NOI18N
keepCurrentViewerRB.setToolTipText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.keepCurrentViewerRB.toolTipText")); // NOI18N
keepCurrentViewerRB.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
keepCurrentViewerRBActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(jLabelHideKnownFiles, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelHideKnownFiles.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(dataSourcesHideKnownCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.dataSourcesHideKnownCB.text")); // NOI18N
dataSourcesHideKnownCB.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
dataSourcesHideKnownCBActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(viewsHideKnownCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.viewsHideKnownCB.text")); // NOI18N
viewsHideKnownCB.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
viewsHideKnownCBActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(jLabelHideSlackFiles, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelHideSlackFiles.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(dataSourcesHideSlackCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.dataSourcesHideSlackCB.text")); // NOI18N
dataSourcesHideSlackCB.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
dataSourcesHideSlackCBActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(viewsHideSlackCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.viewsHideSlackCB.text")); // NOI18N
viewsHideSlackCB.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
viewsHideSlackCBActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(jLabelTimeDisplay, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelTimeDisplay.text")); // NOI18N
displayTimesButtonGroup.add(useLocalTimeRB);
org.openide.awt.Mnemonics.setLocalizedText(useLocalTimeRB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.useLocalTimeRB.text")); // NOI18N
useLocalTimeRB.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
useLocalTimeRBActionPerformed(evt);
}
});
displayTimesButtonGroup.add(useGMTTimeRB);
org.openide.awt.Mnemonics.setLocalizedText(useGMTTimeRB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.useGMTTimeRB.text")); // NOI18N
useGMTTimeRB.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
useGMTTimeRBActionPerformed(evt);
}
});
javax.swing.GroupLayout viewPanelLayout = new javax.swing.GroupLayout(viewPanel);
viewPanel.setLayout(viewPanelLayout);
viewPanelLayout.setHorizontalGroup(
viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, viewPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(viewPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(viewPanelLayout.createSequentialGroup()
.addGroup(viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(useGMTTimeRB)
.addComponent(keepCurrentViewerRB)
.addComponent(useBestViewerRB)
.addComponent(dataSourcesHideKnownCB)
.addComponent(viewsHideKnownCB))
.addGap(0, 0, Short.MAX_VALUE))
.addGroup(viewPanelLayout.createSequentialGroup()
.addGroup(viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(dataSourcesHideSlackCB)
.addComponent(viewsHideSlackCB)
.addComponent(useLocalTimeRB))
.addContainerGap(158, Short.MAX_VALUE))))
.addGroup(viewPanelLayout.createSequentialGroup()
.addGroup(viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabelHideSlackFiles)
.addComponent(jLabelTimeDisplay)
.addComponent(jLabelHideKnownFiles)
.addComponent(jLabelSelectFile))
.addGap(30, 30, 30))))
);
viewPanelLayout.setVerticalGroup(
viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, viewPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabelSelectFile)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(useBestViewerRB)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(keepCurrentViewerRB)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jLabelHideKnownFiles)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(dataSourcesHideKnownCB)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(viewsHideKnownCB)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabelHideSlackFiles)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(dataSourcesHideSlackCB)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(viewsHideSlackCB)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabelTimeDisplay)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(useLocalTimeRB)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(useGMTTimeRB))
);
runtimePanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.runtimePanel.border.title"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(maxMemoryLabel, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.maxMemoryLabel.text")); // NOI18N
@ -831,7 +669,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
.addGroup(runtimePanelLayout.createSequentialGroup()
.addComponent(maxMemoryUnitsLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(restartNecessaryWarning, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(restartNecessaryWarning, javax.swing.GroupLayout.DEFAULT_SIZE, 783, Short.MAX_VALUE))
.addGroup(runtimePanelLayout.createSequentialGroup()
.addComponent(maxMemoryUnitsLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
@ -884,26 +722,21 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(logoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1010, Short.MAX_VALUE)
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(viewPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(runtimePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addContainerGap()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(runtimePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(logoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1002, Short.MAX_VALUE))
.addContainerGap())
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGap(0, 0, 0)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(viewPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(runtimePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap()
.addComponent(runtimePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(logoPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
.addContainerGap(185, Short.MAX_VALUE))
);
jScrollPane1.setViewportView(jPanel1);
@ -917,7 +750,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 479, Short.MAX_VALUE)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGap(0, 0, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
@ -940,38 +773,6 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_memFieldKeyReleased
private void useGMTTimeRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useGMTTimeRBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_useGMTTimeRBActionPerformed
private void useLocalTimeRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useLocalTimeRBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_useLocalTimeRBActionPerformed
private void viewsHideSlackCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewsHideSlackCBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_viewsHideSlackCBActionPerformed
private void dataSourcesHideSlackCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dataSourcesHideSlackCBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_dataSourcesHideSlackCBActionPerformed
private void viewsHideKnownCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewsHideKnownCBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_viewsHideKnownCBActionPerformed
private void dataSourcesHideKnownCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dataSourcesHideKnownCBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_dataSourcesHideKnownCBActionPerformed
private void keepCurrentViewerRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_keepCurrentViewerRBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_keepCurrentViewerRBActionPerformed
private void useBestViewerRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useBestViewerRBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_useBestViewerRBActionPerformed
private void specifyLogoRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_specifyLogoRBActionPerformed
agencyLogoPathField.setEnabled(true);
browseLogosButton.setEnabled(true);
@ -1028,18 +829,11 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
private javax.swing.JLabel agencyLogoPathFieldValidationLabel;
private javax.swing.JLabel agencyLogoPreview;
private javax.swing.JButton browseLogosButton;
private javax.swing.JCheckBox dataSourcesHideKnownCB;
private javax.swing.JCheckBox dataSourcesHideSlackCB;
private javax.swing.JRadioButton defaultLogoRB;
private javax.swing.ButtonGroup displayTimesButtonGroup;
private javax.swing.ButtonGroup fileSelectionButtonGroup;
private javax.swing.JLabel jLabelHideKnownFiles;
private javax.swing.JLabel jLabelHideSlackFiles;
private javax.swing.JLabel jLabelSelectFile;
private javax.swing.JLabel jLabelTimeDisplay;
private javax.swing.JPanel jPanel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JRadioButton keepCurrentViewerRB;
private javax.swing.JTextField logFileCount;
private javax.swing.JTextField logNumAlert;
private javax.swing.JPanel logoPanel;
@ -1055,12 +849,6 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
private javax.swing.JRadioButton specifyLogoRB;
private javax.swing.JLabel systemMemoryTotal;
private javax.swing.JLabel totalMemoryLabel;
private javax.swing.JRadioButton useBestViewerRB;
private javax.swing.JRadioButton useGMTTimeRB;
private javax.swing.JRadioButton useLocalTimeRB;
private javax.swing.JPanel viewPanel;
private javax.swing.JCheckBox viewsHideKnownCB;
private javax.swing.JCheckBox viewsHideSlackCB;
// End of variables declaration//GEN-END:variables
}

View File

@ -26,7 +26,6 @@ LBL_Description=<div style=\"font-size: 12pt; font-family: Verdana, 'Verdana CE'
Format_OperatingSystem_Value={0} version {1} running on {2}
LBL_Copyright=<div style\="font-size\: 12pt; font-family\: Verdana, 'Verdana CE', Arial, 'Arial CE', 'Lucida Grande CE', lucida, 'Helvetica CE', sans-serif; ">Autopsy&trade; is a digital forensics platform based on The Sleuth Kit&trade; and other tools. <br><ul><li>General Information: <a style\="color\: \#1E2A60;" href\="http\://www.sleuthkit.org">http\://www.sleuthkit.org</a>.</li><li>Training: <a style\="color\: \#1E2A60;" href\="http://www.basistech.com/autopsy-training">http://www.basistech.com/autopsy-training</a></li><li>Commercial Support: <a style\="color\: \#1E2A60;" href\="http://www.basistech.com/digital-forensics/autopsy/support/">http://www.basistech.com/digital-forensics/autopsy/support/</a></li></ul>Copyright &copy; 2003-2018. </div>
URL_ON_IMG=http://www.sleuthkit.org/
URL_ON_HELP=http://sleuthkit.org/autopsy/docs/user-docs/4.8.0/
FILE_FOR_LOCAL_HELP=file:///
INDEX_FOR_LOCAL_HELP=/docs/index.html
LBL_Close=Close
@ -96,17 +95,6 @@ DataResultViewerThumbnail.comboBox.mediumThumbnails=Medium Thumbnails
DataResultViewerThumbnail.comboBox.largeThumbnails=Large Thumbnails
DataResultViewerThumbnail.switchPage.done.errMsg=Error making thumbnails\: {0}
AboutWindowPanel.actVerboseLogging.text=Activate verbose logging
AutopsyOptionsPanel.viewsHideKnownCB.text=Views area
AutopsyOptionsPanel.dataSourcesHideKnownCB.text=Data Sources area (the directory hierarchy)
AutopsyOptionsPanel.useBestViewerRB.toolTipText=For example, change from Hex to Media when a JPEG is selected.
AutopsyOptionsPanel.useBestViewerRB.text=Change to the most specific file viewer
AutopsyOptionsPanel.useGMTTimeRB.text=Use GMT
AutopsyOptionsPanel.useLocalTimeRB.text=Use local time zone
AutopsyOptionsPanel.keepCurrentViewerRB.toolTipText=For example, stay in Hex view when a JPEG is selected.
AutopsyOptionsPanel.keepCurrentViewerRB.text=Stay on the same file viewer
AutopsyOptionsPanel.jLabelSelectFile.text=When selecting a file:
AutopsyOptionsPanel.jLabelHideKnownFiles.text=Hide known files (i.e. those in the NIST NSRL) in the:
AutopsyOptionsPanel.jLabelTimeDisplay.text=When displaying times:
OptionsCategory_Name_Multi_User_Settings=Multi-User
OptionsCategory_Keywords_Multi_User_Options=Multi-User Settings
MultiUserSettingsPanel.lbSolrSettings.text=Solr Settings
@ -153,9 +141,6 @@ MultiUserSettingsPanel.lbTestSolrWarning.text=
MultiUserSettingsPanel.lbTestDbWarning.text=
MultiUserSettingsPanel.KeywordSearchNull=Cannot find keyword search service
MultiUserSettingsPanel.InvalidPortNumber=Invalid port number
AutopsyOptionsPanel.jLabelHideSlackFiles.text=Hide slack files in the:
AutopsyOptionsPanel.dataSourcesHideSlackCB.text=Data Sources area (the directory hierarchy)
AutopsyOptionsPanel.viewsHideSlackCB.text=Views area
AutopsyOptionsPanel.agencyLogoImageLabel.toolTipText=
AutopsyOptionsPanel.agencyLogoPathField.text=
SortChooserDialog.label=remove
@ -177,7 +162,33 @@ AutopsyOptionsPanel.specifyLogoRB.text=Specify a logo
AutopsyOptionsPanel.agencyLogoPreview.text=<html><div style='text-align: center;'>No logo<br>selected</div></html>
AutopsyOptionsPanel.logoPanel.border.title=Logo
AutopsyOptionsPanel.runtimePanel.border.title=Runtime
AutopsyOptionsPanel.viewPanel.border.title=View
DataResultPanel.matchLabel.text=Results
DataResultPanel.numberOfChildNodesLabel.text=0
DataResultPanel.descriptionLabel.text=directoryPath
ViewPreferencesPanel.selectFileLabel.text=When selecting a file:
ViewPreferencesPanel.globalSettingsPanel.border.title=Global Settings
ViewPreferencesPanel.displayTimeLabel.text=When displaying times:
ViewPreferencesPanel.hideSlackFilesLabel.text=Hide slack files in the:
ViewPreferencesPanel.groupByDataSourceCheckbox.text=Group by data source
ViewPreferencesPanel.hideKnownFilesLabel.text=Hide known files (i.e. those in the NIST NSRL) in the:
ViewPreferencesPanel.hideOtherUsersTagsCheckbox.text=Tags area in the tree
ViewPreferencesPanel.currentCaseSettingsPanel.border.title=Current Case Settings
OptionsCategory_Name_View=View
OptionsCategory_Keywords_View=View
ViewPreferencesPanel.useBestViewerRadioButton.toolTipText=For example, change from Hex to Media when a JPEG is selected.
ViewPreferencesPanel.useBestViewerRadioButton.text=Change to the most specific file viewer
ViewPreferencesPanel.keepCurrentViewerRadioButton.toolTipText=For example, stay in Hex view when a JPEG is selected.
ViewPreferencesPanel.keepCurrentViewerRadioButton.text=Stay on the same file viewer
ViewPreferencesPanel.useLocalTimeRadioButton.text=Use local time zone
ViewPreferencesPanel.useGMTTimeRadioButton.text=Use GMT
ViewPreferencesPanel.dataSourcesHideKnownCheckbox.text=Data Sources area (the directory hierarchy)
ViewPreferencesPanel.viewsHideKnownCheckbox.text=Views area
ViewPreferencesPanel.dataSourcesHideSlackCheckbox.text=Data Sources area (the directory hierarchy)
ViewPreferencesPanel.viewsHideSlackCheckbox.text=Views area
ViewPreferencesPanel.currentSessionSettingsPanel.border.title=Current Session Settings
ViewPreferencesPanel.hideRejectedResultsCheckbox.text=Hide rejected results
ViewPreferencesPanel.hideOtherUsersTagsLabel.text=Hide other users' tags in the:
ViewPreferencesPanel.centralRepoLabel.text=Do not use Central Repository for:
ViewPreferencesPanel.commentsOccurencesColumnsCheckbox.text=C(omments) and O(ccurences) columns to reduce loading times
ViewPreferencesPanel.deletedFilesLimitCheckbox.text=Limit to 10,000
ViewPreferencesPanel.deletedFilesLimitLabel.text=Limit number of deleted files displayed:

View File

@ -79,17 +79,6 @@ DataResultViewerThumbnail.comboBox.mediumThumbnails=\u30b5\u30e0\u30cd\u30a4\u30
DataResultViewerThumbnail.comboBox.largeThumbnails=\u30b5\u30e0\u30cd\u30a4\u30eb\uff08\u5927\uff09
DataResultViewerThumbnail.switchPage.done.errMsg=\u30b5\u30e0\u30cd\u30a4\u30eb\u4f5c\u6210\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\uff1a {0}
AboutWindowPanel.actVerboseLogging.text=Verbose\u30ed\u30b0\u3092\u30a2\u30af\u30c6\u30a3\u30d9\u30fc\u30c8
AutopsyOptionsPanel.viewsHideKnownCB.text=\u30d3\u30e5\u30fc\u30a8\u30ea\u30a2
AutopsyOptionsPanel.dataSourcesHideKnownCB.text=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u30a8\u30ea\u30a2\uff08\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u968e\u5c64\uff09
AutopsyOptionsPanel.useBestViewerRB.toolTipText=\u4f8b\u3048\u3070\u3001JPEG\u304c\u9078\u629e\u3055\u308c\u305f\u5834\u5408\u306b\u306fHEX\u304b\u3089\u30e1\u30c7\u30a3\u30a2\u306b\u5909\u66f4\u3059\u308b\u3002
AutopsyOptionsPanel.useBestViewerRB.text=\u6700\u3082\u5c02\u9580\u7684\u306a\u30d5\u30a1\u30a4\u30eb\u30d3\u30e5\u30fc\u30a2\u306b\u5909\u66f4
AutopsyOptionsPanel.useGMTTimeRB.text=GMT\u3092\u4f7f\u7528
AutopsyOptionsPanel.useLocalTimeRB.text=\u30ed\u30fc\u30ab\u30eb\u30bf\u30a4\u30e0\u30be\u30fc\u30f3\u3092\u4f7f\u7528
AutopsyOptionsPanel.keepCurrentViewerRB.toolTipText=\u4f8b\u3048\u3070\u3001JPEG\u304c\u9078\u629e\u3055\u308c\u305f\u5834\u5408\u306b\u305d\u306e\u307e\u307eHEX\u30d3\u30e5\u30fc\u3092\u4f7f\u7528\u3002
AutopsyOptionsPanel.keepCurrentViewerRB.text=\u305d\u306e\u307e\u307e\u540c\u3058\u30d5\u30a1\u30a4\u30eb\u30d3\u30e5\u30fc\u30a2\u3092\u4f7f\u7528
AutopsyOptionsPanel.jLabelSelectFile.text=\u30d5\u30a1\u30a4\u30eb\u3092\u9078\u629e\u3059\u308b\u5834\u5408\uff1a
AutopsyOptionsPanel.jLabelHideKnownFiles.text=\u65e2\u77e5\u30d5\u30a1\u30a4\u30eb\uff08NIST NSRL\u5185\u306e\uff09\u3092\u6b21\u306b\u96a0\u3059\uff1a
AutopsyOptionsPanel.jLabelTimeDisplay.text=\u6642\u9593\u3092\u8868\u793a\u3059\u308b\u5834\u5408\uff1a
OptionsCategory_Name_Multi_User_Settings=\u8907\u6570\u306e\u30e6\u30fc\u30b6\u30fc
OptionsCategory_Keywords_Multi_User_Options=\u8907\u6570\u306e\u30e6\u30fc\u30b6\u30fc\u30aa\u30d7\u30b7\u30e7\u30f3
MultiUserSettingsPanel.lbSolrSettings.text=Solr\u8a2d\u5b9a
@ -131,3 +120,14 @@ MediaViewImagePanel.externalViewerButton.text=\u5916\u90e8\u30d3\u30e5\u30fc\u30
DataResultPanel.matchLabel.text=\u7d50\u679c
DataResultPanel.numberOfChildNodesLabel.text=0
DataResultPanel.descriptionLabel.text=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30d1\u30b9
ViewPreferencesPanel.selectFileLabel.text=\u30d5\u30a1\u30a4\u30eb\u3092\u9078\u629e\u3059\u308b\u5834\u5408\uff1a
ViewPreferencesPanel.displayTimeLabel.text=\u6642\u9593\u3092\u8868\u793a\u3059\u308b\u5834\u5408\uff1a
ViewPreferencesPanel.hideKnownFilesLabel.text=\u65e2\u77e5\u30d5\u30a1\u30a4\u30eb\uff08NIST NSRL\u5185\u306e\uff09\u3092\u6b21\u306b\u96a0\u3059\uff1a
ViewPreferencesPanel.useBestViewerRadioButton.toolTipText=\u4f8b\u3048\u3070\u3001JPEG\u304c\u9078\u629e\u3055\u308c\u305f\u5834\u5408\u306b\u306fHEX\u304b\u3089\u30e1\u30c7\u30a3\u30a2\u306b\u5909\u66f4\u3059\u308b\u3002
ViewPreferencesPanel.useBestViewerRadioButton.text=\u6700\u3082\u5c02\u9580\u7684\u306a\u30d5\u30a1\u30a4\u30eb\u30d3\u30e5\u30fc\u30a2\u306b\u5909\u66f4
ViewPreferencesPanel.keepCurrentViewerRadioButton.text=\u305d\u306e\u307e\u307e\u540c\u3058\u30d5\u30a1\u30a4\u30eb\u30d3\u30e5\u30fc\u30a2\u3092\u4f7f\u7528
ViewPreferencesPanel.keepCurrentViewerRadioButton.toolTipText=\u4f8b\u3048\u3070\u3001JPEG\u304c\u9078\u629e\u3055\u308c\u305f\u5834\u5408\u306b\u305d\u306e\u307e\u307eHEX\u30d3\u30e5\u30fc\u3092\u4f7f\u7528\u3002
ViewPreferencesPanel.useLocalTimeRadioButton.text=\u30ed\u30fc\u30ab\u30eb\u30bf\u30a4\u30e0\u30be\u30fc\u30f3\u3092\u4f7f\u7528
ViewPreferencesPanel.useGMTTimeRadioButton.text=GMT\u3092\u4f7f\u7528
ViewPreferencesPanel.dataSourcesHideKnownCheckbox.text=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u30a8\u30ea\u30a2\uff08\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u968e\u5c64\uff09
ViewPreferencesPanel.viewsHideKnownCheckbox.text=\u30d3\u30e5\u30fc\u30a8\u30ea\u30a2

View File

@ -29,7 +29,6 @@
<Container class="org.openide.explorer.view.OutlineView" name="outlineView">
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new OutlineView(DataResultViewerTable.FIRST_COLUMN_LABEL);"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="4"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>

View File

@ -18,7 +18,6 @@
*/
package org.sleuthkit.autopsy.corecomponents;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.FontMetrics;
@ -47,6 +46,7 @@ import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.event.TreeExpansionListener;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
@ -96,7 +96,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
private static final ImageIcon NOTABLE_ICON_SCORE = new ImageIcon(ImageUtilities.loadImage(RED_CIRCLE_ICON_PATH, false));
@NbBundle.Messages("DataResultViewerTable.firstColLbl=Name")
static private final String FIRST_COLUMN_LABEL = Bundle.DataResultViewerTable_firstColLbl();
static private final Color TAGGED_ROW_COLOR = new Color(255, 255, 195);
private final String title;
private final Map<String, ETableColumn> columnMap;
private final Map<Integer, Property<?>> propertiesMap;
@ -160,7 +159,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
outline.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
outline.setRootVisible(false);
outline.setDragEnabled(false);
outline.setDefaultRenderer(Object.class, new ColorTagCustomRenderer());
/*
* Add a table listener to the child OutlineView (explorer view) to
@ -268,6 +266,16 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
}
}
/**
* Adds a tree expansion listener to the OutlineView of this tabular results
* viewer.
*
* @param listener The listener
*/
protected void addTreeExpansionListener(TreeExpansionListener listener) {
outlineView.addTreeExpansionListener(listener);
}
/**
* Sets up the Outline view of this tabular result viewer by creating column
* headers based on the children of the current root node. The persisted
@ -664,19 +672,25 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
private class IconRendererTableListener implements TableColumnModelListener {
@NbBundle.Messages({"DataResultViewerTable.commentRender.name=C",
"DataResultViewerTable.commentRender.toolTip=C(omments) indicates whether the item has a comment",
"DataResultViewerTable.scoreRender.name=S",
"DataResultViewerTable.countRender.name=O"})
"DataResultViewerTable.scoreRender.toolTip=S(core) indicates whether the item is interesting or notable",
"DataResultViewerTable.countRender.name=O",
"DataResultViewerTable.countRender.toolTip=O(ccurrences) indicates the number of data sources containing the item in the Central Repository"})
@Override
public void columnAdded(TableColumnModelEvent e) {
if (e.getSource() instanceof ETableColumnModel) {
TableColumn column = ((TableColumnModel) e.getSource()).getColumn(e.getToIndex());
if (column.getHeaderValue().toString().equals(Bundle.DataResultViewerTable_commentRender_name())) {
//if the current column is a comment column set the cell renderer to be the HasCommentCellRenderer
outlineView.setPropertyColumnDescription(column.getHeaderValue().toString(), Bundle.DataResultViewerTable_commentRender_toolTip());
column.setCellRenderer(new HasCommentCellRenderer());
} else if (column.getHeaderValue().toString().equals(Bundle.DataResultViewerTable_scoreRender_name())) {
//if the current column is a score column set the cell renderer to be the ScoreCellRenderer
outlineView.setPropertyColumnDescription(column.getHeaderValue().toString(), Bundle.DataResultViewerTable_scoreRender_toolTip());
column.setCellRenderer(new ScoreCellRenderer());
} else if (column.getHeaderValue().toString().equals(Bundle.DataResultViewerTable_countRender_name())) {
outlineView.setPropertyColumnDescription(column.getHeaderValue().toString(), Bundle.DataResultViewerTable_countRender_toolTip());
column.setCellRenderer(new CountCellRenderer());
}
}
@ -842,54 +856,11 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
}
}
/**
* This custom renderer extends the renderer that was already being used by
* the outline table. This renderer colors a row if the tags property of the
* node is not empty.
*/
private class ColorTagCustomRenderer extends DefaultOutlineCellRenderer {
private static final long serialVersionUID = 1L;
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
// only override the color if a node is not selected
if (rootNode != null && !isSelected) {
Node node = rootNode.getChildren().getNodeAt(table.convertRowIndexToModel(row));
boolean tagFound = false;
if (node != null) {
Node.PropertySet[] propSets = node.getPropertySets();
if (propSets.length != 0) {
// currently, a node has only one property set, named Sheet.PROPERTIES ("properties")
Node.Property<?>[] props = propSets[0].getProperties();
for (Property<?> prop : props) {
if ("Tags".equals(prop.getName())) {//NON-NLS
try {
tagFound = !prop.getValue().equals("");
} catch (IllegalAccessException | InvocationTargetException ignore) {
//if unable to get the tags property value, treat it like it not having a comment
}
break;
}
}
}
}
//if the node does have associated tags, set its background color
if (tagFound) {
component.setBackground(TAGGED_ROW_COLOR);
}
}
return component;
}
}
/*
* A renderer which based on the contents of the cell will display an icon
* to indicate the presence of a comment related to the content.
*/
private final class HasCommentCellRenderer extends ColorTagCustomRenderer {
private final class HasCommentCellRenderer extends DefaultOutlineCellRenderer {
private static final long serialVersionUID = 1L;
@ -900,7 +871,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
setBackground(component.getBackground()); //inherit highlighting
setBackground(component.getBackground()); //inherit highlighting for selection
setHorizontalAlignment(CENTER);
Object switchValue = null;
if ((value instanceof NodeProperty)) {
@ -949,14 +920,14 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
* A renderer which based on the contents of the cell will display an icon
* to indicate the score associated with the item.
*/
private final class ScoreCellRenderer extends ColorTagCustomRenderer {
private final class ScoreCellRenderer extends DefaultOutlineCellRenderer {
private static final long serialVersionUID = 1L;
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
setBackground(component.getBackground()); //inherit highlighting
setBackground(component.getBackground()); //inherit highlighting for selection
setHorizontalAlignment(CENTER);
Object switchValue = null;
if ((value instanceof NodeProperty)) {
@ -998,14 +969,14 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
* A renderer which based on the contents of the cell will display an empty
* cell if no count was available.
*/
private final class CountCellRenderer extends ColorTagCustomRenderer {
private final class CountCellRenderer extends DefaultOutlineCellRenderer {
private static final long serialVersionUID = 1L;
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
setBackground(component.getBackground()); //inherit highlighting
setBackground(component.getBackground()); //inherit highlighting for selection
setHorizontalAlignment(LEFT);
Object countValue = null;
if ((value instanceof NodeProperty)) {
@ -1076,7 +1047,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
protected org.openide.explorer.view.OutlineView outlineView;
private org.openide.explorer.view.OutlineView outlineView;
// End of variables declaration//GEN-END:variables
}

View File

@ -31,7 +31,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
@OptionsPanelController.TopLevelRegistration(categoryName = "#OptionsCategory_Name_Multi_User_Settings",
iconBase = "org/sleuthkit/autopsy/images/User-Group-icon-green32.png",
position = 3,
position = 4,
keywords = "#OptionsCategory_Keywords_Multi_User_Options",
keywordsCategory = "Multi-User")
public final class MultiUserSettingsPanelController extends OptionsPanelController {

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2014 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -33,9 +33,9 @@ import org.openide.awt.ActionRegistration;
import org.openide.awt.HtmlBrowser;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.Version;
/**
* Implements a hyperlink to the Online Documentation.
@ -69,12 +69,12 @@ public final class OnlineHelpAction implements ActionListener {
*/
private void viewOnlineHelp() {
try {
uri = new URI(NbBundle.getMessage(OnlineHelpAction.class, "URL_ON_HELP"));
uri = new URI("http://sleuthkit.org/autopsy/docs/user-docs/" + Version.getVersion() + "/");
} catch (URISyntaxException ex) {
Logger.log(Level.SEVERE, "Unable to load Online Documentation", ex); //NON-NLS
}
if (uri != null) {
// Display URL in the SYstem browser
// Display URL in the System browser
if (Desktop.isDesktopSupported()) {
Desktop desktop = Desktop.getDesktop();
try {

View File

@ -129,16 +129,6 @@ public class TableFilterNode extends FilterNode {
}
}
/**
* Refreshes the inner node, which depending on the actual node type that was wrapped
* could trigger a dynamic refresh of the children, if supported.
*/
void refresh() {
DataResultFilterNode innerNode = getLookup().lookup(DataResultFilterNode.class);
innerNode.refresh();
}
/**
* @return the column order key, which allows custom column ordering to be
* written into a properties file and be reloaded for future use in a table

View File

@ -0,0 +1,452 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.4" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="viewPreferencesScrollPane" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="viewPreferencesScrollPane" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="viewPreferencesScrollPane">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="viewPreferencesPanel">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="currentSessionSettingsPanel" max="32767" attributes="0"/>
<Component id="currentCaseSettingsPanel" max="32767" attributes="0"/>
<Component id="globalSettingsPanel" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="globalSettingsPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="currentCaseSettingsPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="currentSessionSettingsPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="globalSettingsPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Global Settings">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.globalSettingsPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="commentsOccurencesColumnsCheckbox" min="-2" max="-2" attributes="0"/>
<Component id="hideOtherUsersTagsCheckbox" min="-2" max="-2" attributes="0"/>
<Component id="deletedFilesLimitCheckbox" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="hideKnownFilesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="103" alignment="0" groupAlignment="1" attributes="0">
<Group type="103" alignment="1" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="dataSourcesHideSlackCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="viewsHideSlackCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Component id="hideSlackFilesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="dataSourcesHideKnownCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="viewsHideKnownCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="displayTimeLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="keepCurrentViewerRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="useBestViewerRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="useGMTTimeRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="useLocalTimeRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Component id="selectFileLabel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Component id="hideOtherUsersTagsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="centralRepoLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="deletedFilesLimitLabel" alignment="0" min="-2" pref="215" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="10" max="32767" 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="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="hideKnownFilesLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="dataSourcesHideKnownCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="viewsHideKnownCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="hideSlackFilesLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="dataSourcesHideSlackCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="viewsHideSlackCheckbox" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="selectFileLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="useBestViewerRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="keepCurrentViewerRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="displayTimeLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="useLocalTimeRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="useGMTTimeRadioButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="hideOtherUsersTagsLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="hideOtherUsersTagsCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="centralRepoLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="commentsOccurencesColumnsCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="deletedFilesLimitLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="deletedFilesLimitCheckbox" min="-2" pref="33" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="selectFileLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.selectFileLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JRadioButton" name="useBestViewerRadioButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.useBestViewerRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.useBestViewerRadioButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useBestViewerRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="keepCurrentViewerRadioButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.keepCurrentViewerRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.keepCurrentViewerRadioButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="keepCurrentViewerRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="hideKnownFilesLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.hideKnownFilesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="dataSourcesHideKnownCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.dataSourcesHideKnownCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="dataSourcesHideKnownCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="viewsHideKnownCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.viewsHideKnownCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="viewsHideKnownCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="hideSlackFilesLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.hideSlackFilesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="dataSourcesHideSlackCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.dataSourcesHideSlackCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="dataSourcesHideSlackCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="viewsHideSlackCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.viewsHideSlackCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="viewsHideSlackCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="displayTimeLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.displayTimeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JRadioButton" name="useLocalTimeRadioButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.useLocalTimeRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useLocalTimeRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="useGMTTimeRadioButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.useGMTTimeRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useGMTTimeRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="hideOtherUsersTagsCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.hideOtherUsersTagsCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="hideOtherUsersTagsCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="hideOtherUsersTagsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.hideOtherUsersTagsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="commentsOccurencesColumnsCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.commentsOccurencesColumnsCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="commentsOccurencesColumnsCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="centralRepoLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.centralRepoLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="deletedFilesLimitCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.deletedFilesLimitCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="deletedFilesLimitCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="deletedFilesLimitLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.deletedFilesLimitLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="currentCaseSettingsPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Current Case Settings">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.currentCaseSettingsPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="groupByDataSourceCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="32767" attributes="0"/>
<Component id="groupByDataSourceCheckbox" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JCheckBox" name="groupByDataSourceCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.groupByDataSourceCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="groupByDataSourceCheckboxActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="currentSessionSettingsPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Current Session Settings">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.currentSessionSettingsPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="hideRejectedResultsCheckbox" min="-2" pref="259" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="32767" attributes="0"/>
<Component id="hideRejectedResultsCheckbox" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JCheckBox" name="hideRejectedResultsCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.hideRejectedResultsCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="hideRejectedResultsCheckboxActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,566 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 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.corecomponents;
import java.util.Objects;
import javax.swing.JPanel;
import org.netbeans.spi.options.OptionsPanelController;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.deletedFiles.DeletedFilePreferences;
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
/**
* Panel for configuring view preferences.
*/
public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
private final boolean immediateUpdates;
/**
* Creates new form ViewPreferencesPanel
*
* @param immediateUpdates If true, value changes will be persisted at the
* moment they occur.
*/
public ViewPreferencesPanel(boolean immediateUpdates) {
initComponents();
this.immediateUpdates = immediateUpdates;
}
@Override
public void load() {
// Global Settings
boolean keepPreferredViewer = UserPreferences.keepPreferredContentViewer();
keepCurrentViewerRadioButton.setSelected(keepPreferredViewer);
useBestViewerRadioButton.setSelected(!keepPreferredViewer);
boolean useLocalTime = UserPreferences.displayTimesInLocalTime();
useLocalTimeRadioButton.setSelected(useLocalTime);
useGMTTimeRadioButton.setSelected(!useLocalTime);
dataSourcesHideKnownCheckbox.setSelected(UserPreferences.hideKnownFilesInDataSourcesTree());
viewsHideKnownCheckbox.setSelected(UserPreferences.hideKnownFilesInViewsTree());
dataSourcesHideSlackCheckbox.setSelected(UserPreferences.hideSlackFilesInDataSourcesTree());
viewsHideSlackCheckbox.setSelected(UserPreferences.hideSlackFilesInViewsTree());
commentsOccurencesColumnsCheckbox.setEnabled(EamDbUtil.useCentralRepo());
commentsOccurencesColumnsCheckbox.setSelected(UserPreferences.hideCentralRepoCommentsAndOccurrences());
deletedFilesLimitCheckbox.setSelected(DeletedFilePreferences.getDefault().getShouldLimitDeletedFiles());
// Current Case Settings
boolean caseIsOpen = Case.isCaseOpen();
currentCaseSettingsPanel.setEnabled(caseIsOpen);
groupByDataSourceCheckbox.setEnabled(caseIsOpen);
hideOtherUsersTagsCheckbox.setSelected(UserPreferences.showOnlyCurrentUserTags());
groupByDataSourceCheckbox.setSelected(Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true));
// Current Session Settings
hideRejectedResultsCheckbox.setSelected(DirectoryTreeTopComponent.getDefault().getShowRejectedResults() == false);
}
@Override
public void store() {
UserPreferences.setKeepPreferredContentViewer(keepCurrentViewerRadioButton.isSelected());
UserPreferences.setDisplayTimesInLocalTime(useLocalTimeRadioButton.isSelected());
UserPreferences.setHideKnownFilesInDataSourcesTree(dataSourcesHideKnownCheckbox.isSelected());
UserPreferences.setHideKnownFilesInViewsTree(viewsHideKnownCheckbox.isSelected());
UserPreferences.setHideSlackFilesInDataSourcesTree(dataSourcesHideSlackCheckbox.isSelected());
UserPreferences.setHideSlackFilesInViewsTree(viewsHideSlackCheckbox.isSelected());
UserPreferences.setShowOnlyCurrentUserTags(hideOtherUsersTagsCheckbox.isSelected());
UserPreferences.setHideCentralRepoCommentsAndOccurrences(commentsOccurencesColumnsCheckbox.isSelected());
storeGroupItemsInTreeByDataSource();
DirectoryTreeTopComponent.getDefault().setShowRejectedResults(hideRejectedResultsCheckbox.isSelected() == false);
DeletedFilePreferences.getDefault().setShouldLimitDeletedFiles(deletedFilesLimitCheckbox.isSelected());
}
/**
* Store the 'groupByDataSourceCheckbox' value.
*
* Note: The value will not be stored if the value hasn't previously been
* stored and the checkbox isn't selected. This is so GroupDataSourcesDialog
* can prompt the user for this in the event the value hasn't been
* initialized.
*/
private void storeGroupItemsInTreeByDataSource() {
if (Case.isCaseOpen() && (CasePreferences.getGroupItemsInTreeByDataSource() != null || groupByDataSourceCheckbox.isSelected())) {
CasePreferences.setGroupItemsInTreeByDataSource(groupByDataSourceCheckbox.isSelected());
}
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
viewPreferencesScrollPane = new javax.swing.JScrollPane();
viewPreferencesPanel = new javax.swing.JPanel();
globalSettingsPanel = new javax.swing.JPanel();
selectFileLabel = new javax.swing.JLabel();
useBestViewerRadioButton = new javax.swing.JRadioButton();
keepCurrentViewerRadioButton = new javax.swing.JRadioButton();
hideKnownFilesLabel = new javax.swing.JLabel();
dataSourcesHideKnownCheckbox = new javax.swing.JCheckBox();
viewsHideKnownCheckbox = new javax.swing.JCheckBox();
hideSlackFilesLabel = new javax.swing.JLabel();
dataSourcesHideSlackCheckbox = new javax.swing.JCheckBox();
viewsHideSlackCheckbox = new javax.swing.JCheckBox();
displayTimeLabel = new javax.swing.JLabel();
useLocalTimeRadioButton = new javax.swing.JRadioButton();
useGMTTimeRadioButton = new javax.swing.JRadioButton();
hideOtherUsersTagsCheckbox = new javax.swing.JCheckBox();
hideOtherUsersTagsLabel = new javax.swing.JLabel();
commentsOccurencesColumnsCheckbox = new javax.swing.JCheckBox();
centralRepoLabel = new javax.swing.JLabel();
deletedFilesLimitCheckbox = new javax.swing.JCheckBox();
deletedFilesLimitLabel = new javax.swing.JLabel();
currentCaseSettingsPanel = new javax.swing.JPanel();
groupByDataSourceCheckbox = new javax.swing.JCheckBox();
currentSessionSettingsPanel = new javax.swing.JPanel();
hideRejectedResultsCheckbox = new javax.swing.JCheckBox();
viewPreferencesScrollPane.setBorder(null);
globalSettingsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.globalSettingsPanel.border.title"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(selectFileLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.selectFileLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(useBestViewerRadioButton, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.useBestViewerRadioButton.text")); // NOI18N
useBestViewerRadioButton.setToolTipText(org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.useBestViewerRadioButton.toolTipText")); // NOI18N
useBestViewerRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
useBestViewerRadioButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(keepCurrentViewerRadioButton, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.keepCurrentViewerRadioButton.text")); // NOI18N
keepCurrentViewerRadioButton.setToolTipText(org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.keepCurrentViewerRadioButton.toolTipText")); // NOI18N
keepCurrentViewerRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
keepCurrentViewerRadioButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(hideKnownFilesLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.hideKnownFilesLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(dataSourcesHideKnownCheckbox, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.dataSourcesHideKnownCheckbox.text")); // NOI18N
dataSourcesHideKnownCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
dataSourcesHideKnownCheckboxActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(viewsHideKnownCheckbox, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.viewsHideKnownCheckbox.text")); // NOI18N
viewsHideKnownCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
viewsHideKnownCheckboxActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(hideSlackFilesLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.hideSlackFilesLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(dataSourcesHideSlackCheckbox, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.dataSourcesHideSlackCheckbox.text")); // NOI18N
dataSourcesHideSlackCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
dataSourcesHideSlackCheckboxActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(viewsHideSlackCheckbox, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.viewsHideSlackCheckbox.text")); // NOI18N
viewsHideSlackCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
viewsHideSlackCheckboxActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(displayTimeLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.displayTimeLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(useLocalTimeRadioButton, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.useLocalTimeRadioButton.text")); // NOI18N
useLocalTimeRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
useLocalTimeRadioButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(useGMTTimeRadioButton, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.useGMTTimeRadioButton.text")); // NOI18N
useGMTTimeRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
useGMTTimeRadioButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(hideOtherUsersTagsCheckbox, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.hideOtherUsersTagsCheckbox.text")); // NOI18N
hideOtherUsersTagsCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
hideOtherUsersTagsCheckboxActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(hideOtherUsersTagsLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.hideOtherUsersTagsLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(commentsOccurencesColumnsCheckbox, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.commentsOccurencesColumnsCheckbox.text")); // NOI18N
commentsOccurencesColumnsCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
commentsOccurencesColumnsCheckboxActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(centralRepoLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.centralRepoLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(deletedFilesLimitCheckbox, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.deletedFilesLimitCheckbox.text")); // NOI18N
deletedFilesLimitCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
deletedFilesLimitCheckboxActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(deletedFilesLimitLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.deletedFilesLimitLabel.text")); // NOI18N
javax.swing.GroupLayout globalSettingsPanelLayout = new javax.swing.GroupLayout(globalSettingsPanel);
globalSettingsPanel.setLayout(globalSettingsPanelLayout);
globalSettingsPanelLayout.setHorizontalGroup(
globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(commentsOccurencesColumnsCheckbox)
.addComponent(hideOtherUsersTagsCheckbox)
.addComponent(deletedFilesLimitCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(hideKnownFilesLabel)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(dataSourcesHideSlackCheckbox)
.addComponent(viewsHideSlackCheckbox)))
.addComponent(hideSlackFilesLabel))
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(dataSourcesHideKnownCheckbox)
.addComponent(viewsHideKnownCheckbox)))))
.addGap(18, 18, 18)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(displayTimeLabel)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(keepCurrentViewerRadioButton)
.addComponent(useBestViewerRadioButton)
.addComponent(useGMTTimeRadioButton)
.addComponent(useLocalTimeRadioButton)))
.addComponent(selectFileLabel)))
.addComponent(hideOtherUsersTagsLabel)
.addComponent(centralRepoLabel)
.addComponent(deletedFilesLimitLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(0, 10, Short.MAX_VALUE)))
.addContainerGap())
);
globalSettingsPanelLayout.setVerticalGroup(
globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addComponent(hideKnownFilesLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(dataSourcesHideKnownCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(viewsHideKnownCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(hideSlackFilesLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(dataSourcesHideSlackCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(viewsHideSlackCheckbox))
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addComponent(selectFileLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(useBestViewerRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(keepCurrentViewerRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(displayTimeLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(useLocalTimeRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(useGMTTimeRadioButton)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(hideOtherUsersTagsLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(hideOtherUsersTagsCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(centralRepoLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(commentsOccurencesColumnsCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(deletedFilesLimitLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(deletedFilesLimitCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 33, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0))
);
currentCaseSettingsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.currentCaseSettingsPanel.border.title"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(groupByDataSourceCheckbox, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.groupByDataSourceCheckbox.text")); // NOI18N
groupByDataSourceCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
groupByDataSourceCheckboxActionPerformed(evt);
}
});
javax.swing.GroupLayout currentCaseSettingsPanelLayout = new javax.swing.GroupLayout(currentCaseSettingsPanel);
currentCaseSettingsPanel.setLayout(currentCaseSettingsPanelLayout);
currentCaseSettingsPanelLayout.setHorizontalGroup(
currentCaseSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(currentCaseSettingsPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(groupByDataSourceCheckbox)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
currentCaseSettingsPanelLayout.setVerticalGroup(
currentCaseSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(currentCaseSettingsPanelLayout.createSequentialGroup()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(groupByDataSourceCheckbox))
);
currentSessionSettingsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.currentSessionSettingsPanel.border.title"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(hideRejectedResultsCheckbox, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.hideRejectedResultsCheckbox.text")); // NOI18N
hideRejectedResultsCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
hideRejectedResultsCheckboxActionPerformed(evt);
}
});
javax.swing.GroupLayout currentSessionSettingsPanelLayout = new javax.swing.GroupLayout(currentSessionSettingsPanel);
currentSessionSettingsPanel.setLayout(currentSessionSettingsPanelLayout);
currentSessionSettingsPanelLayout.setHorizontalGroup(
currentSessionSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(currentSessionSettingsPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(hideRejectedResultsCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 259, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
currentSessionSettingsPanelLayout.setVerticalGroup(
currentSessionSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(currentSessionSettingsPanelLayout.createSequentialGroup()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(hideRejectedResultsCheckbox))
);
javax.swing.GroupLayout viewPreferencesPanelLayout = new javax.swing.GroupLayout(viewPreferencesPanel);
viewPreferencesPanel.setLayout(viewPreferencesPanelLayout);
viewPreferencesPanelLayout.setHorizontalGroup(
viewPreferencesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, viewPreferencesPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(viewPreferencesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(currentSessionSettingsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(currentCaseSettingsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(globalSettingsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
viewPreferencesPanelLayout.setVerticalGroup(
viewPreferencesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(viewPreferencesPanelLayout.createSequentialGroup()
.addComponent(globalSettingsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(currentCaseSettingsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(currentSessionSettingsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
viewPreferencesScrollPane.setViewportView(viewPreferencesPanel);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(viewPreferencesScrollPane)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(viewPreferencesScrollPane)
);
}// </editor-fold>//GEN-END:initComponents
private void useBestViewerRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useBestViewerRadioButtonActionPerformed
useBestViewerRadioButton.setSelected(true);
keepCurrentViewerRadioButton.setSelected(false);
if (immediateUpdates) {
UserPreferences.setKeepPreferredContentViewer(false);
} else {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
}//GEN-LAST:event_useBestViewerRadioButtonActionPerformed
private void keepCurrentViewerRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_keepCurrentViewerRadioButtonActionPerformed
useBestViewerRadioButton.setSelected(false);
keepCurrentViewerRadioButton.setSelected(true);
if (immediateUpdates) {
UserPreferences.setKeepPreferredContentViewer(true);
} else {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
}//GEN-LAST:event_keepCurrentViewerRadioButtonActionPerformed
private void useLocalTimeRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useLocalTimeRadioButtonActionPerformed
useLocalTimeRadioButton.setSelected(true);
useGMTTimeRadioButton.setSelected(false);
if (immediateUpdates) {
UserPreferences.setDisplayTimesInLocalTime(true);
} else {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
}//GEN-LAST:event_useLocalTimeRadioButtonActionPerformed
private void useGMTTimeRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useGMTTimeRadioButtonActionPerformed
useLocalTimeRadioButton.setSelected(false);
useGMTTimeRadioButton.setSelected(true);
if (immediateUpdates) {
UserPreferences.setDisplayTimesInLocalTime(false);
} else {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
}//GEN-LAST:event_useGMTTimeRadioButtonActionPerformed
private void dataSourcesHideKnownCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dataSourcesHideKnownCheckboxActionPerformed
if (immediateUpdates) {
UserPreferences.setHideKnownFilesInDataSourcesTree(dataSourcesHideKnownCheckbox.isSelected());
} else {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
}//GEN-LAST:event_dataSourcesHideKnownCheckboxActionPerformed
private void viewsHideKnownCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewsHideKnownCheckboxActionPerformed
if (immediateUpdates) {
UserPreferences.setHideKnownFilesInViewsTree(viewsHideKnownCheckbox.isSelected());
} else {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
}//GEN-LAST:event_viewsHideKnownCheckboxActionPerformed
private void dataSourcesHideSlackCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dataSourcesHideSlackCheckboxActionPerformed
if (immediateUpdates) {
UserPreferences.setHideSlackFilesInDataSourcesTree(dataSourcesHideSlackCheckbox.isSelected());
} else {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
}//GEN-LAST:event_dataSourcesHideSlackCheckboxActionPerformed
private void viewsHideSlackCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewsHideSlackCheckboxActionPerformed
if (immediateUpdates) {
UserPreferences.setHideSlackFilesInViewsTree(viewsHideSlackCheckbox.isSelected());
} else {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
}//GEN-LAST:event_viewsHideSlackCheckboxActionPerformed
private void hideOtherUsersTagsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hideOtherUsersTagsCheckboxActionPerformed
if (immediateUpdates) {
UserPreferences.setShowOnlyCurrentUserTags(hideOtherUsersTagsCheckbox.isSelected());
} else {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
}//GEN-LAST:event_hideOtherUsersTagsCheckboxActionPerformed
private void groupByDataSourceCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_groupByDataSourceCheckboxActionPerformed
if (immediateUpdates) {
storeGroupItemsInTreeByDataSource();
} else {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
}//GEN-LAST:event_groupByDataSourceCheckboxActionPerformed
private void hideRejectedResultsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hideRejectedResultsCheckboxActionPerformed
if (immediateUpdates) {
DirectoryTreeTopComponent.getDefault().setShowRejectedResults(hideRejectedResultsCheckbox.isSelected() == false);
} else {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
}//GEN-LAST:event_hideRejectedResultsCheckboxActionPerformed
private void commentsOccurencesColumnsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_commentsOccurencesColumnsCheckboxActionPerformed
if (immediateUpdates) {
UserPreferences.setHideCentralRepoCommentsAndOccurrences(commentsOccurencesColumnsCheckbox.isSelected());
} else {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
}//GEN-LAST:event_commentsOccurencesColumnsCheckboxActionPerformed
private void deletedFilesLimitCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deletedFilesLimitCheckboxActionPerformed
if (immediateUpdates) {
DeletedFilePreferences.getDefault().setShouldLimitDeletedFiles(deletedFilesLimitCheckbox.isSelected());
} else {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
}//GEN-LAST:event_deletedFilesLimitCheckboxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel centralRepoLabel;
private javax.swing.JCheckBox commentsOccurencesColumnsCheckbox;
private javax.swing.JPanel currentCaseSettingsPanel;
private javax.swing.JPanel currentSessionSettingsPanel;
private javax.swing.JCheckBox dataSourcesHideKnownCheckbox;
private javax.swing.JCheckBox dataSourcesHideSlackCheckbox;
private javax.swing.JCheckBox deletedFilesLimitCheckbox;
private javax.swing.JLabel deletedFilesLimitLabel;
private javax.swing.JLabel displayTimeLabel;
private javax.swing.JPanel globalSettingsPanel;
private javax.swing.JCheckBox groupByDataSourceCheckbox;
private javax.swing.JLabel hideKnownFilesLabel;
private javax.swing.JCheckBox hideOtherUsersTagsCheckbox;
private javax.swing.JLabel hideOtherUsersTagsLabel;
private javax.swing.JCheckBox hideRejectedResultsCheckbox;
private javax.swing.JLabel hideSlackFilesLabel;
private javax.swing.JRadioButton keepCurrentViewerRadioButton;
private javax.swing.JLabel selectFileLabel;
private javax.swing.JRadioButton useBestViewerRadioButton;
private javax.swing.JRadioButton useGMTTimeRadioButton;
private javax.swing.JRadioButton useLocalTimeRadioButton;
private javax.swing.JPanel viewPreferencesPanel;
private javax.swing.JScrollPane viewPreferencesScrollPane;
private javax.swing.JCheckBox viewsHideKnownCheckbox;
private javax.swing.JCheckBox viewsHideSlackCheckbox;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,149 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 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.corecomponents;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import javax.swing.JComponent;
import org.netbeans.spi.options.OptionsPanelController;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import java.util.logging.Level;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Controller for the main settings panel
*/
@OptionsPanelController.TopLevelRegistration(categoryName = "#OptionsCategory_Name_View",
iconBase = "org/sleuthkit/autopsy/images/view-preferences-32.png",
position = 2,
keywords = "#OptionsCategory_Keywords_View",
keywordsCategory = "View")
public final class ViewPreferencesPanelController extends OptionsPanelController {
private ViewPreferencesPanel panel;
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
private boolean changed;
private static final Logger logger = Logger.getLogger(ViewPreferencesPanelController.class.getName());
@Override
public void update() {
getPanel().load();
changed = false;
}
@Override
public void applyChanges() {
getPanel().store();
changed = false;
}
@Override
public void cancel() {
}
@Override
public boolean isValid() {
return true;
}
@Override
public boolean isChanged() {
return changed;
}
@Override
public HelpCtx getHelpCtx() {
return null;
}
@Override
public JComponent getComponent(Lookup masterLookup) {
return getPanel();
}
@Override
public void addPropertyChangeListener(PropertyChangeListener l) {
if (pcs.getPropertyChangeListeners().length == 0) {
pcs.addPropertyChangeListener(l);
}
}
@Override
public void removePropertyChangeListener(PropertyChangeListener l) {
/**
* Note the NetBeans Framework does not appear to call this at all. We
* are using NetBeans 7.3.1 Build 201306052037. Perhaps in a future
* version of the Framework this will be resolved, but for now, simply
* don't unregister anything and add one time only in the
* addPropertyChangeListener() method above.
*/
}
/**
* Retrieve an instance of the ViewPreferencesPanel.
*
* @return A ViewPreferencesPanel instance.
*/
private ViewPreferencesPanel getPanel() {
if (panel == null) {
panel = new ViewPreferencesPanel(false);
panel.addPropertyChangeListener((PropertyChangeEvent evt) -> {
if (evt.getPropertyName().equals(OptionsPanelController.PROP_CHANGED)) {
changed();
}
});
}
return panel;
}
/**
* Executed whenever a property change occurs.
*/
@Messages({"ViewOptionsController.moduleErr=Error processing value changes.",
"ViewOptionsController.moduleErr.msg=Value change processing failed."})
void changed() {
if (!changed) {
changed = true;
try {
pcs.firePropertyChange(OptionsPanelController.PROP_CHANGED, false, true);
} catch (Exception ex) {
logger.log(Level.SEVERE, "Error processing property change", ex); //NON-NLS
MessageNotifyUtil.Notify.show(
Bundle.ViewOptionsController_moduleErr(),
Bundle.ViewOptionsController_moduleErr_msg(),
MessageNotifyUtil.MessageType.ERROR);
}
}
try {
pcs.firePropertyChange(OptionsPanelController.PROP_VALID, null, null);
} catch (Exception e) {
logger.log(Level.SEVERE, "Error processing property change validation.", e); //NON-NLS
MessageNotifyUtil.Notify.show(
Bundle.ViewOptionsController_moduleErr(),
Bundle.ViewOptionsController_moduleErr_msg(),
MessageNotifyUtil.MessageType.ERROR);
}
}
}

View File

@ -39,18 +39,23 @@ import javax.annotation.concurrent.ThreadSafe;
@ThreadSafe
public class History<T> {
// Stack of things that were previously shown before an 'advance' was done
@GuardedBy("this")
private final ObservableStack<T> historyStack = new ObservableStack<>();
// stack of things that were previously shown before a 'retreat' (i.e. a back) was done
@GuardedBy("this")
private final ObservableStack<T> forwardStack = new ObservableStack<>();
// what is currently being shown
@GuardedBy("this")
private final ReadOnlyObjectWrapper<T> currentState = new ReadOnlyObjectWrapper<>();
// Is the forward stack empty?
@GuardedBy("this")
private final ReadOnlyBooleanWrapper canAdvance = new ReadOnlyBooleanWrapper();
// is the historyStack empty?
@GuardedBy("this")
private final ReadOnlyBooleanWrapper canRetreat = new ReadOnlyBooleanWrapper();

View File

@ -195,7 +195,6 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
"AbstractAbstractFileNode.typeDirColLbl=Type(Dir)",
"AbstractAbstractFileNode.typeMetaColLbl=Type(Meta)",
"AbstractAbstractFileNode.knownColLbl=Known",
"AbstractAbstractFileNode.inHashsetsColLbl=In Hashsets",
"AbstractAbstractFileNode.md5HashColLbl=MD5 Hash",
"AbstractAbstractFileNode.objectId=Object ID",
"AbstractAbstractFileNode.mimeType=MIME Type",
@ -219,7 +218,6 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
TYPE_DIR(AbstractAbstractFileNode_typeDirColLbl()),
TYPE_META(AbstractAbstractFileNode_typeMetaColLbl()),
KNOWN(AbstractAbstractFileNode_knownColLbl()),
HASHSETS(AbstractAbstractFileNode_inHashsetsColLbl()),
MD5HASH(AbstractAbstractFileNode_md5HashColLbl()),
ObjectID(AbstractAbstractFileNode_objectId()),
MIMETYPE(AbstractAbstractFileNode_mimeType()),
@ -262,7 +260,6 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
map.put(TYPE_DIR.toString(), content.getDirType().getLabel());
map.put(TYPE_META.toString(), content.getMetaType().toString());
map.put(KNOWN.toString(), content.getKnown().getName());
map.put(HASHSETS.toString(), getHashSetHitsCsvList(content));
map.put(MD5HASH.toString(), StringUtils.defaultString(content.getMd5Hash()));
map.put(ObjectID.toString(), content.getId());
map.put(MIMETYPE.toString(), StringUtils.defaultString(content.getMIMEType()));
@ -339,10 +336,11 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
"AbstractAbstractFileNode.createSheet.notableFile.description=File recognized as notable.",
"AbstractAbstractFileNode.createSheet.interestingResult.description=File has interesting result associated with it.",
"AbstractAbstractFileNode.createSheet.taggedFile.description=File has been tagged.",
"AbstractAbstractFileNode.createSheet.notableTaggedFile.description=File tagged with notable tag."})
"AbstractAbstractFileNode.createSheet.notableTaggedFile.description=File tagged with notable tag.",
"AbstractAbstractFileNode.createSheet.noScore.description=No score"})
protected final void addScoreProperty(Sheet.Set sheetSet, List<ContentTag> tags) {
Score score = Score.NO_SCORE;
String description = NO_DESCR;
String description = Bundle.AbstractAbstractFileNode_createSheet_noScore_description();
if (content.getKnown() == TskData.FileKnown.BAD) {
score = Score.NOTABLE_SCORE;
description = Bundle.AbstractAbstractFileNode_createSheet_notableFile_description();
@ -402,6 +400,7 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
*
* @param sheetSet the modifiable Sheet.Set returned by
* Sheet.get(Sheet.PROPERTIES)
* @deprecated
*/
@NbBundle.Messages("AbstractAbstractFileNode.tagsProperty.displayName=Tags")
@Deprecated
@ -418,21 +417,6 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
.collect(Collectors.joining(", "))));
}
/**
* Used by subclasses of AbstractAbstractFileNode to add the tags property
* to their sheets.
*
* @param sheetSet the modifiable Sheet.Set returned by
* Sheet.get(Sheet.PROPERTIES)
* @param tags the list of tags associated with the file
*/
protected final void addTagProperty(Sheet.Set sheetSet, List<ContentTag> tags) {
sheetSet.put(new NodeProperty<>("Tags", AbstractAbstractFileNode_tagsProperty_displayName(),
NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName())
.distinct()
.collect(Collectors.joining(", "))));
}
private static String getContentPath(AbstractFile file) {
try {
return file.getUniquePath();
@ -462,7 +446,9 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
* @param file The file.
*
* @return The CSV list of hash set names.
* @deprecated
*/
@Deprecated
protected static String getHashSetHitsCsvList(AbstractFile file) {
try {
return StringUtils.join(file.getHashSetNames(), ", ");

View File

@ -24,6 +24,8 @@ import java.util.Map;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.ContentTag;
@ -82,12 +84,20 @@ public abstract class AbstractFsContentNode<T extends AbstractFile> extends Abst
AbstractFilePropertyType.NAME.toString(),
NO_DESCR,
getName()));
//add the cr status property before the propertyMap to ensure it is early in column order
addScoreProperty(sheetSet, tags);
//add the comment property before the propertyMap to ensure it is early in column order
CorrelationAttributeInstance correlationAttribute = getCorrelationAttributeInstance();
CorrelationAttributeInstance correlationAttribute = null;
if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
correlationAttribute = getCorrelationAttributeInstance();
}
addCommentProperty(sheetSet, tags, correlationAttribute);
if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
addCountProperty(sheetSet, correlationAttribute);
}
for (AbstractFilePropertyType propType : AbstractFilePropertyType.values()) {
final String propString = propType.toString();
sheetSet.put(new NodeProperty<>(propString, propString, NO_DESCR, map.get(propString)));
@ -96,9 +106,6 @@ public abstract class AbstractFsContentNode<T extends AbstractFile> extends Abst
sheetSet.put(new NodeProperty<>(HIDE_PARENT, HIDE_PARENT, HIDE_PARENT, HIDE_PARENT));
}
// add tags property to the sheet
addTagProperty(sheetSet, tags);
return sheet;
}

View File

@ -24,10 +24,12 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.logging.Level;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Node;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
@ -53,7 +55,7 @@ public final class AutopsyTreeChildFactory extends ChildFactory.Detachable<Objec
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString()) &&
UserPreferences.groupItemsInTreeByDatasource()) {
Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
refreshChildren();
}
}
@ -83,7 +85,7 @@ public final class AutopsyTreeChildFactory extends ChildFactory.Detachable<Objec
try {
SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase();
if (UserPreferences.groupItemsInTreeByDatasource()) {
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
List<DataSource> dataSources = tskCase.getDataSources();
List<DataSourceGrouping> keys = new ArrayList<>();
dataSources.forEach((datasource) -> {

View File

@ -55,11 +55,13 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable.Score;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import static org.sleuthkit.autopsy.datamodel.DisplayableItemNode.findLinked;
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable.HasCommentStatus;
import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager;
import org.sleuthkit.autopsy.timeline.actions.ViewArtifactInTimelineAction;
import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction;
import org.sleuthkit.datamodel.AbstractFile;
@ -350,10 +352,18 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.srcFile.displayName"),
NO_DESCR,
this.getSourceName()));
CorrelationAttributeInstance correlationAttribute = getCorrelationAttributeInstance();
addScoreProperty(sheetSet, tags);
CorrelationAttributeInstance correlationAttribute = null;
if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
correlationAttribute = getCorrelationAttributeInstance();
}
addCommentProperty(sheetSet, tags, correlationAttribute);
if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
addCountProperty(sheetSet, correlationAttribute);
}
if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
try {
BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
@ -501,7 +511,6 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
NO_DESCR,
path));
}
addTagProperty(sheetSet, tags);
return sheet;
}
@ -556,6 +565,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
* @param tags the list of tags which should appear as the value for the
* property
*/
@Deprecated
protected final void addTagProperty(Sheet.Set sheetSet, List<Tag> tags) {
sheetSet.put(new NodeProperty<>("Tags", Bundle.BlackboardArtifactNode_createSheet_tags_displayName(),
NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName()).collect(Collectors.joining(", "))));
@ -618,16 +628,34 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
"BlackboardArtifactNode.createSheet.notableFile.description=Associated file recognized as notable.",
"BlackboardArtifactNode.createSheet.interestingResult.description=Result has an interesting result associated with it.",
"BlackboardArtifactNode.createSheet.taggedItem.description=Result or associated file has been tagged.",
"BlackboardArtifactNode.createSheet.notableTaggedItem.description=Result or associated file tagged with notable tag."})
"BlackboardArtifactNode.createSheet.notableTaggedItem.description=Result or associated file tagged with notable tag.",
"BlackboardArtifactNode.createSheet.noScore.description=No score"})
protected final void addScoreProperty(Sheet.Set sheetSet, List<Tag> tags) {
Score score = Score.NO_SCORE;
String description = "";
String description = Bundle.BlackboardArtifactNode_createSheet_noScore_description();
if (associated instanceof AbstractFile) {
if (((AbstractFile) associated).getKnown() == TskData.FileKnown.BAD) {
score = Score.NOTABLE_SCORE;
description = Bundle.BlackboardArtifactNode_createSheet_notableFile_description();
}
}
//if the artifact being viewed is a hashhit check if the hashset is notable
if ((score == Score.NO_SCORE || score == Score.INTERESTING_SCORE) && content.getArtifactTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) {
try {
BlackboardAttribute attr = content.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SET_NAME));
List<HashDbManager.HashDb> notableHashsets = HashDbManager.getInstance().getKnownBadFileHashSets();
for (HashDbManager.HashDb hashDb : notableHashsets) {
if (hashDb.getHashSetName().equals(attr.getValueString())) {
score = Score.NOTABLE_SCORE;
description = Bundle.BlackboardArtifactNode_createSheet_notableFile_description();
break;
}
}
} catch (TskCoreException ex) {
//unable to get the attribute so we can not update the status based on the attribute
logger.log(Level.WARNING, "Unable to get TSK_SET_NAME attribute for artifact of type TSK_HASHSET_HIT with artifact ID " + content.getArtifactID(), ex);
}
}
try {
if (score == Score.NO_SCORE && !content.getArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT).isEmpty()) {
score = Score.INTERESTING_SCORE;
@ -670,8 +698,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
}
} catch (EamDbException ex) {
logger.log(Level.WARNING, "Error getting count of datasources with correlation attribute", ex);
}
catch (CorrelationAttributeNormalizationException ex) {
} catch (CorrelationAttributeNormalizationException ex) {
logger.log(Level.WARNING, "Unable to normalize data to get count of datasources with correlation attribute", ex);
}
sheetSet.put(

View File

@ -10,7 +10,6 @@ AbstractAbstractFileNode.modeColLbl=\u30e2\u30fc\u30c9
AbstractAbstractFileNode.useridColLbl=\u30e6\u30fc\u30b6ID
AbstractAbstractFileNode.groupidColLbl=\u30b0\u30eb\u30fc\u30d7ID
AbstractAbstractFileNode.knownColLbl=\u65e2\u77e5
AbstractAbstractFileNode.inHashsetsColLbl=HashSet\u306b\u5b58\u5728
AbstractAbstractFileNode.md5HashColLbl=MD5\u30cf\u30c3\u30b7\u30e5
AbstractContentChildren.CreateTSKNodeVisitor.exception.noNodeMsg=\u6307\u5b9a\u3055\u308c\u305fSleuthkitItem\u306e\u30ce\u30fc\u30c9\u304c\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u307e\u305b\u3093
AbstractContentChildren.createAutopsyNodeVisitor.exception.noNodeMsg=\u6307\u5b9a\u3055\u308c\u305f\u8868\u793a\u53ef\u80fd\u306a\u30a2\u30a4\u30c6\u30e0(DisplayableItem)\u306e\u30ce\u30fc\u30c9\u304c\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u307e\u305b\u3093

View File

@ -24,6 +24,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
@ -39,10 +40,12 @@ import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
import static org.sleuthkit.autopsy.datamodel.Bundle.*;
import org.sleuthkit.autopsy.deletedFiles.DeletedFilePreferences;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
@ -189,6 +192,7 @@ public class DeletedContent implements AutopsyVisitableItem {
* fired. Other nodes are listening to this for changes.
*/
private static final class DeletedContentsChildrenObservable extends Observable {
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(
Case.Events.DATA_SOURCE_ADDED,
Case.Events.CURRENT_CASE
@ -211,12 +215,11 @@ public class DeletedContent implements AutopsyVisitableItem {
String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
/**
* + // @@@ COULD CHECK If the new file is deleted
* before notifying... Checking for a current case is a
* stop gap measure + update(); until a different way of
* handling the closing of cases is worked out.
* Currently, remote events may be received for a case
* that is already closed.
* + // @@@ COULD CHECK If the new file is deleted before
* notifying... Checking for a current case is a stop gap
* measure + update(); until a different way of handling the
* closing of cases is worked out. Currently, remote events
* may be received for a case that is already closed.
*/
try {
Case.getCurrentCaseThrows();
@ -232,10 +235,10 @@ public class DeletedContent implements AutopsyVisitableItem {
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
|| eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
/**
* Checking for a current case is a stop gap measure
* until a different way of handling the closing of
* cases is worked out. Currently, remote events may be
* received for a case that is already closed.
* Checking for a current case is a stop gap measure until a
* different way of handling the closing of cases is worked
* out. Currently, remote events may be received for a case
* that is already closed.
*/
try {
Case.getCurrentCaseThrows();
@ -364,7 +367,7 @@ public class DeletedContent implements AutopsyVisitableItem {
private final SleuthkitCase skCase;
private final DeletedContent.DeletedContentFilter filter;
private static final Logger logger = Logger.getLogger(DeletedContentChildren.class.getName());
private static final int MAX_OBJECTS = 10001;
private final Observable notifier;
private final long datasourceObjId;
@ -406,15 +409,16 @@ public class DeletedContent implements AutopsyVisitableItem {
+ "There are more Deleted Files than can be displayed."
+ " Only the first {0} Deleted Files will be shown."})
protected boolean createKeys(List<AbstractFile> list) {
DeletedFilePreferences deletedPreferences = DeletedFilePreferences.getDefault();
List<AbstractFile> queryList = runFsQuery();
if (queryList.size() == MAX_OBJECTS) {
if (deletedPreferences.getShouldLimitDeletedFiles() && queryList.size() == deletedPreferences.getDeletedFilesLimit()) {
queryList.remove(queryList.size() - 1);
// only show the dialog once - not each time we refresh
if (maxFilesDialogShown == false) {
maxFilesDialogShown = true;
SwingUtilities.invokeLater(()
-> JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
DeletedContent_createKeys_maxObjects_msg(MAX_OBJECTS - 1))
DeletedContent_createKeys_maxObjects_msg(deletedPreferences.getDeletedFilesLimit() - 1))
);
}
}
@ -460,11 +464,13 @@ public class DeletedContent implements AutopsyVisitableItem {
+ " OR known IS NULL)"; //NON-NLS
}
if (UserPreferences.groupItemsInTreeByDatasource()) {
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
query += " AND data_source_obj_id = " + filteringDSObjId;
}
query += " LIMIT " + MAX_OBJECTS; //NON-NLS
DeletedFilePreferences deletedPreferences = DeletedFilePreferences.getDefault();
if (deletedPreferences.getShouldLimitDeletedFiles()) {
query += " LIMIT " + deletedPreferences.getDeletedFilesLimit(); //NON-NLS
}
return query;
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-16 Basis Technology Corp.
* Copyright 2013-18 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -19,31 +19,20 @@
package org.sleuthkit.autopsy.datamodel;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.Border;
import javafx.scene.layout.BorderStroke;
import javafx.scene.layout.BorderStrokeStyle;
import javafx.scene.layout.BorderWidths;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.datamodel.Bundle;
/**
* Enum to represent the six categories in the DHS image categorization scheme.
*/
@NbBundle.Messages({"Category.one=CAT-1: Child Exploitation (Illegal)",
@NbBundle.Messages({
"Category.one=CAT-1: Child Exploitation (Illegal)",
"Category.two=CAT-2: Child Exploitation (Non-Illegal/Age Difficult)",
"Category.three=CAT-3: CGI/Animation (Child Exploitive)",
"Category.four=CAT-4: Exemplar/Comparison (Internal Use Only)",
@ -56,29 +45,32 @@ public enum DhsImageCategory {
* preserves the fact that lower category numbers are first/most sever,
* except 0 which is last
*/
ONE(Color.RED, 1, Bundle.Category_one()),
TWO(Color.ORANGE, 2, Bundle.Category_two()),
THREE(Color.YELLOW, 3, Bundle.Category_three()),
FOUR(Color.BISQUE, 4, Bundle.Category_four()),
FIVE(Color.GREEN, 5, Bundle.Category_five()),
ZERO(Color.LIGHTGREY, 0, Bundle.Category_zero());
ONE(Color.RED, 1, Bundle.Category_one(), "cat1.png"),
TWO(Color.ORANGE, 2, Bundle.Category_two(), "cat2.png"),
THREE(Color.YELLOW, 3, Bundle.Category_three(), "cat3.png"),
FOUR(Color.BISQUE, 4, Bundle.Category_four(), "cat4.png"),
FIVE(Color.GREEN, 5, Bundle.Category_five(), "cat5.png"),
ZERO(Color.LIGHTGREY, 0, Bundle.Category_zero(), "cat0.png");
private static final BorderWidths BORDER_WIDTHS_2 = new BorderWidths(2);
private static final CornerRadii CORNER_RADII_4 = new CornerRadii(4);
/** Map from displayName to enum value */
private static final Map<String, DhsImageCategory> nameMap
= Maps.uniqueIndex(Arrays.asList(values()), DhsImageCategory::getDisplayName);
public static ImmutableList<DhsImageCategory> getNonZeroCategories() {
return nonZeroCategories;
private final Color color;
private final String displayName;
private final int id;
private final Image icon;
private DhsImageCategory(Color color, int id, String name, String filename) {
this.color = color;
this.displayName = name;
this.id = id;
this.icon = new Image(getClass().getResourceAsStream("/org/sleuthkit/autopsy/images/" + filename));
}
private static final ImmutableList<DhsImageCategory> nonZeroCategories =
ImmutableList.of(DhsImageCategory.FIVE, DhsImageCategory.FOUR, DhsImageCategory.THREE, DhsImageCategory.TWO, DhsImageCategory.ONE);
/**
* map from displayName to enum value
*/
private static final Map<String, DhsImageCategory> nameMap =
Stream.of(values()).collect(Collectors.toMap(DhsImageCategory::getDisplayName,
Function.identity()));
public static ImmutableList<DhsImageCategory> getNonZeroCategories() {
return ImmutableList.of(FIVE, FOUR, THREE, TWO, ONE);
}
public static DhsImageCategory fromDisplayName(String displayName) {
return nameMap.get(displayName);
@ -92,19 +84,6 @@ public enum DhsImageCategory {
return nameMap.containsKey(tName) == false;
}
private final Color color;
private final String displayName;
private final int id;
private Image snapshot;
private DhsImageCategory(Color color, int id, String name) {
this.color = color;
this.displayName = name;
this.id = id;
}
public int getCategoryNumber() {
return id;
}
@ -122,15 +101,7 @@ public enum DhsImageCategory {
return displayName;
}
synchronized public Node getGraphic() {
if (snapshot == null) {
Region region = new Region();
region.setBackground(new Background(new BackgroundFill(getColor(), CORNER_RADII_4, Insets.EMPTY)));
region.setPrefSize(16, 16);
region.setBorder(new Border(new BorderStroke(getColor().darker(), BorderStrokeStyle.SOLID, CORNER_RADII_4, BORDER_WIDTHS_2)));
Scene scene = new Scene(region, 16, 16, Color.TRANSPARENT);
snapshot = region.snapshot(null, null);
}
return new ImageView(snapshot);
public Node getGraphic() {
return new ImageView(icon);
}
}

View File

@ -28,6 +28,7 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
@ -39,6 +40,7 @@ import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
@ -161,7 +163,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
+ "attribute_type_id=" + pathAttrId //NON-NLS
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
if (UserPreferences.groupItemsInTreeByDatasource()) {
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
query += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId;
}

View File

@ -26,6 +26,7 @@ import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.logging.Level;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
@ -34,6 +35,7 @@ import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
@ -290,10 +292,9 @@ public class ExtractedContent implements AutopsyVisitableItem {
@Override
protected boolean createKeys(List<BlackboardArtifact.Type> list) {
//TEST COMMENT
if (skCase != null) {
try {
List<BlackboardArtifact.Type> types = (UserPreferences.groupItemsInTreeByDatasource()) ?
List<BlackboardArtifact.Type> types = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) ?
blackboard.getArtifactTypesInUse(datasourceObjId) :
skCase.getArtifactTypesInUse() ;
@ -358,7 +359,7 @@ public class ExtractedContent implements AutopsyVisitableItem {
// a performance increase might be had by adding a
// "getBlackboardArtifactCount()" method to skCase
try {
this.childCount = UserPreferences.groupItemsInTreeByDatasource() ?
this.childCount = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) ?
blackboard.getArtifactsCount(type.getTypeID(), datasourceObjId) :
skCase.getBlackboardArtifactsTypeCount(type.getTypeID());
} catch (TskException ex) {
@ -483,7 +484,7 @@ public class ExtractedContent implements AutopsyVisitableItem {
if (skCase != null) {
try {
List<BlackboardArtifact> arts =
UserPreferences.groupItemsInTreeByDatasource() ?
Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) ?
blackboard.getArtifacts(type.getTypeID(), datasourceObjId) :
skCase.getBlackboardArtifacts(type.getTypeID());
list.addAll(arts);

View File

@ -24,6 +24,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
@ -36,6 +37,7 @@ import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
@ -445,8 +447,8 @@ public class FileSize implements AutopsyVisitableItem {
query += " AND (type != " + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType() + ")"; //NON-NLS
}
// filter by datasource if indicated in user preferences
if (UserPreferences.groupItemsInTreeByDatasource()) {
// filter by datasource if indicated in case preferences
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
query += " AND data_source_obj_id = " + filteringDSObjId;
}

View File

@ -23,6 +23,7 @@ import java.beans.PropertyChangeListener;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
@ -37,6 +38,7 @@ import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
@ -363,7 +365,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
+ (UserPreferences.hideKnownFilesInViewsTree()
? " AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")"
: " ")
+ (UserPreferences.groupItemsInTreeByDatasource()
+ (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
? " AND data_source_obj_id = " + filteringDataSourceObjId()
: " ")
+ " AND (extension IN (" + filter.getFilter().stream()

View File

@ -28,6 +28,7 @@ import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
@ -41,6 +42,7 @@ import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences;
import static org.sleuthkit.autopsy.core.UserPreferences.hideKnownFilesInViewsTree;
@ -101,7 +103,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
+ TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()
+ (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()))
+ "))"
+ ( UserPreferences.groupItemsInTreeByDatasource() ? " AND data_source_obj_id = " + this.filteringDataSourceObjId() : " ")
+ ( Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) ? " AND data_source_obj_id = " + this.filteringDataSourceObjId() : " ")
+ (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : "");
}

View File

@ -30,6 +30,7 @@ import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
@ -41,6 +42,7 @@ import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
@ -141,7 +143,7 @@ public class HashsetHits implements AutopsyVisitableItem {
+ "attribute_type_id=" + setNameId //NON-NLS
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
if (UserPreferences.groupItemsInTreeByDatasource()) {
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
query += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId;
}

View File

@ -30,6 +30,7 @@ import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
@ -41,8 +42,8 @@ import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
@ -132,7 +133,7 @@ public class InterestingHits implements AutopsyVisitableItem {
+ "attribute_type_id=" + setNameId //NON-NLS
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
if (UserPreferences.groupItemsInTreeByDatasource()) {
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
query += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId;
}
@ -474,11 +475,13 @@ public class InterestingHits implements AutopsyVisitableItem {
BlackboardArtifact art = skCase.getBlackboardArtifact(id);
artifactHits.put(id, art);
}
list.add(id);
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "TSK Exception occurred", ex); //NON-NLS
}
});
list.addAll(artifactHits.keySet());
return true;
}

View File

@ -29,6 +29,7 @@ import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
@ -43,6 +44,7 @@ import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
@ -321,7 +323,7 @@ public class KeywordHits implements AutopsyVisitableItem {
}
String queryStr = KEYWORD_HIT_ATTRIBUTES_QUERY;
if (UserPreferences.groupItemsInTreeByDatasource()) {
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
queryStr += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId;
}

View File

@ -32,6 +32,8 @@ import org.openide.util.Utilities;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
@ -46,6 +48,7 @@ import org.sleuthkit.datamodel.TskData;
*/
public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
@Deprecated
public static enum LayoutContentPropertyType {
PARTS {
@ -90,18 +93,23 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
NbBundle.getMessage(this.getClass(), "LayoutFileNode.createSheet.name.displayName"),
NbBundle.getMessage(this.getClass(), "LayoutFileNode.createSheet.name.desc"),
getName()));
CorrelationAttributeInstance correlationAttribute = getCorrelationAttributeInstance();
addScoreProperty(sheetSet, tags);
CorrelationAttributeInstance correlationAttribute = null;
if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
correlationAttribute = getCorrelationAttributeInstance();
}
addCommentProperty(sheetSet, tags, correlationAttribute);
if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
addCountProperty(sheetSet, correlationAttribute);
}
final String NO_DESCR = NbBundle.getMessage(this.getClass(), "LayoutFileNode.createSheet.noDescr.text");
for (Map.Entry<String, Object> entry : map.entrySet()) {
sheetSet.put(new NodeProperty<>(entry.getKey(), entry.getKey(), NO_DESCR, entry.getValue()));
}
// add tags property to the sheet
addTagProperty(sheetSet, tags);
return sheet;
}
@ -145,7 +153,6 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
void fillPropertyMap(Map<String, Object> map) {
AbstractAbstractFileNode.fillPropertyMap(map, getContent());
map.put(LayoutContentPropertyType.PARTS.toString(), content.getNumParts());
}
@Override

View File

@ -24,6 +24,8 @@ import java.util.Map;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.LocalDirectory;
@ -63,10 +65,18 @@ public class LocalDirectoryNode extends SpecialDirectoryNode {
Bundle.LocalDirectoryNode_createSheet_name_displayName(),
Bundle.LocalDirectoryNode_createSheet_name_desc(),
getName()));
CorrelationAttributeInstance correlationAttribute = getCorrelationAttributeInstance();
addScoreProperty(sheetSet, tags);
CorrelationAttributeInstance correlationAttribute = null;
if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
correlationAttribute = getCorrelationAttributeInstance();
}
addCommentProperty(sheetSet, tags, correlationAttribute);
if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
addCountProperty(sheetSet, correlationAttribute);
}
// At present, a LocalDirectory will never be a datasource - the top level of a logical
// file set is a VirtualDirectory
Map<String, Object> map = new LinkedHashMap<>();
@ -76,7 +86,6 @@ public class LocalDirectoryNode extends SpecialDirectoryNode {
for (Map.Entry<String, Object> entry : map.entrySet()) {
sheetSet.put(new NodeProperty<>(entry.getKey(), entry.getKey(), NO_DESCR, entry.getValue()));
}
addTagProperty(sheetSet, tags);
return sheet;
}

View File

@ -33,6 +33,8 @@ import org.openide.util.Utilities;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
@ -82,18 +84,23 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
NbBundle.getMessage(this.getClass(), "LocalFileNode.createSheet.name.displayName"),
NbBundle.getMessage(this.getClass(), "LocalFileNode.createSheet.name.desc"),
getName()));
CorrelationAttributeInstance correlationAttribute = getCorrelationAttributeInstance();
addScoreProperty(sheetSet, tags);
CorrelationAttributeInstance correlationAttribute = null;
if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
correlationAttribute = getCorrelationAttributeInstance();
}
addCommentProperty(sheetSet, tags, correlationAttribute);
if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
addCountProperty(sheetSet, correlationAttribute);
}
final String NO_DESCR = NbBundle.getMessage(this.getClass(), "LocalFileNode.createSheet.noDescr.text");
for (Map.Entry<String, Object> entry : map.entrySet()) {
sheetSet.put(new NodeProperty<>(entry.getKey(), entry.getKey(), NO_DESCR, entry.getValue()));
}
// add tags property to the sheet
addTagProperty(sheetSet, tags);
return sheet;
}

View File

@ -19,6 +19,7 @@
package org.sleuthkit.autopsy.datamodel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.Action;
import org.openide.util.NbBundle;
@ -27,6 +28,7 @@ import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.FileSearchAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.SpecialDirectory;
/**
@ -60,7 +62,11 @@ public abstract class SpecialDirectoryNode extends AbstractAbstractFileNode<Spec
actions.add(ExtractAction.getInstance());
actions.add(null); // creates a menu separator
actions.add(new FileSearchAction(Bundle.ImageNode_getActions_openFileSearchByAttr_text()));
if (content.isDataSource()) {
actions.add(new RunIngestModulesAction(Collections.<Content>singletonList(content)));
} else {
actions.add(new RunIngestModulesAction(content));
}
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions.toArray(new Action[0]);
}

View File

@ -23,6 +23,7 @@ import java.beans.PropertyChangeListener;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
@ -34,6 +35,7 @@ import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.core.UserPreferences;
@ -244,11 +246,11 @@ public class Tags implements AutopsyVisitableItem {
List<TagName> tagNamesInUse;
if (UserPreferences.showOnlyCurrentUserTags()) {
String userName = System.getProperty(USER_NAME_PROPERTY);
tagNamesInUse = UserPreferences.groupItemsInTreeByDatasource()
tagNamesInUse = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUseForUser(datasourceObjId, userName)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUseForUser(userName);
} else {
tagNamesInUse = UserPreferences.groupItemsInTreeByDatasource()
tagNamesInUse = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(datasourceObjId)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse();
}
@ -301,7 +303,7 @@ public class Tags implements AutopsyVisitableItem {
TagsManager tm = Case.getCurrentCaseThrows().getServices().getTagsManager();
if (UserPreferences.showOnlyCurrentUserTags()) {
String userName = System.getProperty(USER_NAME_PROPERTY);
if (UserPreferences.groupItemsInTreeByDatasource()) {
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
tagsCount = tm.getContentTagsCountByTagNameForUser(tagName, datasourceObjId, userName);
tagsCount += tm.getBlackboardArtifactTagsCountByTagNameForUser(tagName, datasourceObjId, userName);
} else {
@ -309,7 +311,7 @@ public class Tags implements AutopsyVisitableItem {
tagsCount += tm.getBlackboardArtifactTagsCountByTagNameForUser(tagName, userName);
}
} else {
if (UserPreferences.groupItemsInTreeByDatasource()) {
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
tagsCount = tm.getContentTagsCountByTagName(tagName, datasourceObjId);
tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName, datasourceObjId);
} else {
@ -422,11 +424,11 @@ public class Tags implements AutopsyVisitableItem {
if (UserPreferences.showOnlyCurrentUserTags()) {
String userName = System.getProperty(USER_NAME_PROPERTY);
tagsCount = UserPreferences.groupItemsInTreeByDatasource()
tagsCount = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagNameForUser(tagName, datasourceObjId, userName)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagNameForUser(tagName, userName);
} else {
tagsCount = UserPreferences.groupItemsInTreeByDatasource()
tagsCount = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName, datasourceObjId)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName);
}
@ -484,7 +486,7 @@ public class Tags implements AutopsyVisitableItem {
protected boolean createKeys(List<ContentTag> keys) {
// Use the content tags bearing the specified tag name as the keys.
try {
List<ContentTag> contentTags = UserPreferences.groupItemsInTreeByDatasource()
List<ContentTag> contentTags = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName, datasourceObjId)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName);
if (UserPreferences.showOnlyCurrentUserTags()) {
@ -542,11 +544,11 @@ public class Tags implements AutopsyVisitableItem {
try {
if (UserPreferences.showOnlyCurrentUserTags()) {
String userName = System.getProperty(USER_NAME_PROPERTY);
tagsCount = UserPreferences.groupItemsInTreeByDatasource()
tagsCount = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagNameForUser(tagName, datasourceObjId, userName)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagNameForUser(tagName, userName);
} else {
tagsCount = UserPreferences.groupItemsInTreeByDatasource()
tagsCount = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName, datasourceObjId)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName);
}
@ -604,7 +606,7 @@ public class Tags implements AutopsyVisitableItem {
protected boolean createKeys(List<BlackboardArtifactTag> keys) {
try {
// Use the blackboard artifact tags bearing the specified tag name as the keys.
List<BlackboardArtifactTag> artifactTags = UserPreferences.groupItemsInTreeByDatasource()
List<BlackboardArtifactTag> artifactTags = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName, datasourceObjId)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName);
if (UserPreferences.showOnlyCurrentUserTags()) {

View File

@ -29,6 +29,8 @@ import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.SleuthkitCase;
@ -90,10 +92,17 @@ public class VirtualDirectoryNode extends SpecialDirectoryNode {
NbBundle.getMessage(this.getClass(), "VirtualDirectoryNode.createSheet.name.desc"),
getName()));
if (!this.content.isDataSource()) {
CorrelationAttributeInstance correlationAttribute = getCorrelationAttributeInstance();
addScoreProperty(sheetSet, tags);
CorrelationAttributeInstance correlationAttribute = null;
if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
correlationAttribute = getCorrelationAttributeInstance();
}
addCommentProperty(sheetSet, tags, correlationAttribute);
if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
addCountProperty(sheetSet, correlationAttribute);
}
Map<String, Object> map = new LinkedHashMap<>();
fillPropertyMap(map, getContent());
@ -101,7 +110,6 @@ public class VirtualDirectoryNode extends SpecialDirectoryNode {
for (Map.Entry<String, Object> entry : map.entrySet()) {
sheetSet.put(new NodeProperty<>(entry.getKey(), entry.getKey(), NO_DESCR, entry.getValue()));
}
addTagProperty(sheetSet, tags);
} else {
sheetSet.put(new NodeProperty<>(Bundle.VirtualDirectoryNode_createSheet_type_name(),
Bundle.VirtualDirectoryNode_createSheet_type_displayName(),

View File

@ -57,6 +57,7 @@ import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
@ -149,12 +150,14 @@ final public class Accounts implements AutopsyVisitableItem {
* Returns the clause to filter artifacts by data source.
*
* @return A clause that will or will not filter artifacts by datasource
* based on the UserPreferences groupItemsInTreeByDatasource setting
* based on the CasePreferences groupItemsInTreeByDataSource setting
*/
private String getFilterByDataSourceClause() {
return (UserPreferences.groupItemsInTreeByDatasource()) ?
" AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId + " "
: " ";
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
return " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId + " ";
}
return " ";
}
/**
@ -164,6 +167,7 @@ final public class Accounts implements AutopsyVisitableItem {
* @return An Action that will toggle whether rejected artifacts are shown
* in the tree rooted by this Accounts instance.
*/
@Deprecated
public Action newToggleShowRejectedAction() {
return new ToggleShowRejected();
}
@ -1686,6 +1690,7 @@ final public class Accounts implements AutopsyVisitableItem {
}
@Deprecated
private final class ToggleShowRejected extends AbstractAction {
@NbBundle.Messages("ToggleShowRejected.name=Show Rejected Results")
@ -1700,6 +1705,16 @@ final public class Accounts implements AutopsyVisitableItem {
}
}
/**
* Update the user interface to show or hide rejected artifacts.
*
* @param showRejected Show rejected artifacts? Yes if true; otherwise no.
*/
public void setShowRejected(boolean showRejected) {
this.showRejected = showRejected;
reviewStatusBus.post(new ReviewStatusChangeEvent(Collections.emptySet(), null));
}
private abstract class ReviewStatusAction extends AbstractAction {
private final BlackboardArtifact.ReviewStatus newStatus;

View File

@ -0,0 +1,171 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 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.deletedFiles;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Properties;
import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
/**
* Class to store settings related to the display of deleted files.
*/
public class DeletedFilePreferences {
private static final String SETTINGS_FILE = "DeletedFilePreferences.properties"; //NON-NLS
private static final String KEY_LIMIT_DELETED_FILES = "limitDeletedFiles"; //NON-NLS
private static final String KEY_LIMIT_VALUE = "limitValue";
private static final String VALUE_TRUE = "true"; //NON-NLS
private static final String VALUE_FALSE = "false"; //NON-NLS
private static final int DEFAULT_MAX_OBJECTS = 10001;
private static final Logger logger = Logger.getLogger(CasePreferences.class.getName());
private static DeletedFilePreferences defaultInstance;
private static boolean limitDeletedFiles = true;
private static int deletedFilesLimit = DEFAULT_MAX_OBJECTS;
/**
* Get the settings for the display of deleted files.
*
* @return defaultInstance with freshly loaded
*/
public static synchronized DeletedFilePreferences getDefault() {
if (defaultInstance == null) {
defaultInstance = new DeletedFilePreferences();
}
defaultInstance.loadFromStorage();
return defaultInstance;
}
/**
* Prevent instantiation.
*/
private DeletedFilePreferences() {
}
/**
* Get the 'limitDeletedFiles' value. This can be true or false. It will
* default to true if it was not saved correctly previously.s
*
* @return true if the number of deleted files displayed should be limied,
* false if it should not be limited.
*/
public boolean getShouldLimitDeletedFiles() {
return limitDeletedFiles;
}
/**
* Set the 'limitDeletedFiles' value to true or false.
*
* @param value true if the number of deleted files displayed should be
* limied, false if it should not be limited.
*/
public void setShouldLimitDeletedFiles(boolean value) {
limitDeletedFiles = value;
saveToStorage();
DirectoryTreeTopComponent.getDefault().refreshContentTreeSafe();
}
/**
* Get the 'limitValue' value. This is an interger value and will default to
* DEFAULT_MAX_OBJECTS if it was not previously saved correctly.
*
* @return an integer representing the max number of deleted files to display.
*/
public int getDeletedFilesLimit() {
return deletedFilesLimit;
}
/**
* Set the 'limitValue' for max number of deleted files to display.
*
* @param value an integer representing the max number of deleted files to display.
*/
public void setDeletedFilesLimit(int value) {
deletedFilesLimit = value;
saveToStorage();
DirectoryTreeTopComponent.getDefault().refreshContentTreeSafe();
}
/**
* Load deleted file preferences from the settings file.
*/
private void loadFromStorage() {
Path settingsFile = Paths.get(PlatformUtil.getUserConfigDirectory(), SETTINGS_FILE); //NON-NLS
if (settingsFile.toFile().exists()) {
// Read the settings
try (InputStream inputStream = Files.newInputStream(settingsFile)) {
Properties props = new Properties();
props.load(inputStream);
String limitDeletedFilesValue = props.getProperty(KEY_LIMIT_DELETED_FILES);
if (limitDeletedFilesValue != null) {
switch (limitDeletedFilesValue) {
case VALUE_TRUE:
limitDeletedFiles = true;
break;
case VALUE_FALSE:
limitDeletedFiles = false;
break;
default:
logger.log(Level.WARNING, String.format("Unexpected value '%s' for limit deleted files using value of true instead",
limitDeletedFilesValue));
limitDeletedFiles = true;
break;
}
}
String limitValue = props.getProperty(KEY_LIMIT_VALUE);
try {
if (limitValue != null) {
deletedFilesLimit = Integer.valueOf(limitValue);
}
} catch (NumberFormatException ex) {
logger.log(Level.INFO, String.format("Unexpected value '%s' for limit, expected an integer using default of 10,001 instead",
limitValue));
deletedFilesLimit = DEFAULT_MAX_OBJECTS;
}
} catch (IOException ex) {
logger.log(Level.SEVERE, "Error reading deletedFilesPreferences file", ex);
}
}
}
/**
* Store deleted file preferences in the settings file.
*/
private void saveToStorage() {
Path settingsFile = Paths.get(PlatformUtil.getUserConfigDirectory(), SETTINGS_FILE); //NON-NLS
Properties props = new Properties();
props.setProperty(KEY_LIMIT_DELETED_FILES, (limitDeletedFiles ? VALUE_TRUE : VALUE_FALSE));
props.setProperty(KEY_LIMIT_VALUE, String.valueOf(deletedFilesLimit));
try (OutputStream fos = Files.newOutputStream(settingsFile)) {
props.store(fos, ""); //NON-NLS
} catch (IOException ex) {
logger.log(Level.SEVERE, "Error writing deletedFilesPreferences file", ex);
}
}
}

View File

@ -59,7 +59,6 @@ DirectoryTreeFilterNode.action.collapseAll.text=Collapse All
DirectoryTreeFilterNode.action.openFileSrcByAttr.text=Open File Search by Attributes
DirectoryTreeFilterNode.action.runIngestMods.text=Run Ingest Modules
DirectoryTreeTopComponent.action.viewArtContent.text=View Artifact Content
DirectoryTreeTopComponent.showRejectedCheckBox.text=Show Rejected Results
ExplorerNodeActionVisitor.action.imgDetails.title=Image Details
ExplorerNodeActionVisitor.action.extUnallocToSingleFiles=Extract Unallocated Space to Single Files
ExplorerNodeActionVisitor.action.fileSystemDetails.title=File System Details
@ -119,10 +118,9 @@ AddExternalViewerRulePanel.browseButton.text=Browse
AddExternalViewerRulePanel.exePathTextField.text=
AddExternalViewerRulePanel.exePathLabel.text=Path of the program to use for files with this type or extension
AddExternalViewerRulePanel.extRadioButton.text=Extension
DirectoryTreeTopComponent.groupByDatasourceCheckBox.text=Group by Data Source
GroupDataSourcesDialog.dataSourceCountLabel.text=jLabel1
GroupDataSourcesDialog.queryLabel.text=Would you like to group by data source for faster loading?
GroupDataSourcesDialog.yesButton.text=Yes
GroupDataSourcesDialog.noButton.text=No
GroupDataSourcesDialog.title=Group by Data Source?
DirectoryTreeTopComponent.showOnlyCurrentUserTagsCheckbox.text=Hide Other User's Tags
DirectoryTreeTopComponent.openViewPreferencesButton.text=

View File

@ -140,18 +140,6 @@ public class DataResultFilterNode extends FilterNode {
this.sourceEm = em;
}
/**
* Refreshes the inner node. If the actual underlying node is an InstanceCountNode,
* refresh() that node, which refreshes the children.
*
*/
public void refresh() {
if (getOriginal() instanceof InstanceCountNode) {
InstanceCountNode innerNode = getLookup().lookup(InstanceCountNode.class);
innerNode.refresh();
}
}
/**
* Constructs a node used to wrap another node before passing it to the
* result viewers. The wrapper node defines the actions associated with the

View File

@ -1,6 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.4" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<NonVisualComponents>
<Container class="javax.swing.JPopupMenu" name="viewPreferencesPopupMenu">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout">
<Property name="useNullLayout" type="boolean" value="true"/>
</Layout>
</Container>
</NonVisualComponents>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
@ -16,18 +24,14 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="treeView" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="treeView" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="backButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="forwardButton" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="showOnlyCurrentUserTagsCheckbox" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="showRejectedCheckBox" min="-2" max="-2" attributes="0"/>
<Component id="groupByDatasourceCheckBox" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="140" max="32767" attributes="0"/>
<Component id="openViewPreferencesButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
@ -35,27 +39,14 @@
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="showRejectedCheckBox" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="showOnlyCurrentUserTagsCheckbox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="groupByDatasourceCheckBox" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="forwardButton" max="32767" attributes="1"/>
<Component id="backButton" min="-2" max="-2" attributes="1"/>
</Group>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="treeView" pref="843" max="32767" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="openViewPreferencesButton" min="-2" max="-2" attributes="0"/>
<Component id="backButton" min="-2" max="-2" attributes="1"/>
<Component id="forwardButton" min="-2" max="-2" attributes="1"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="treeView" pref="919" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -76,7 +67,7 @@
<Component class="javax.swing.JButton" name="backButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_back_large.png"/>
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_back.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="DirectoryTreeTopComponent.backButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
@ -84,7 +75,7 @@
<Property name="borderPainted" type="boolean" value="false"/>
<Property name="contentAreaFilled" type="boolean" value="false"/>
<Property name="disabledIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_back_disabled_large.png"/>
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_back_disabled.png"/>
</Property>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
<Insets value="[2, 0, 2, 0]"/>
@ -96,10 +87,10 @@
<Dimension value="[5, 5]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[32, 32]"/>
<Dimension value="[24, 24]"/>
</Property>
<Property name="rolloverIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_back_hover_large.png"/>
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_back_hover.png"/>
</Property>
</Properties>
<Events>
@ -109,7 +100,7 @@
<Component class="javax.swing.JButton" name="forwardButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_forward_large.png"/>
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_forward.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="DirectoryTreeTopComponent.forwardButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
@ -117,7 +108,7 @@
<Property name="borderPainted" type="boolean" value="false"/>
<Property name="contentAreaFilled" type="boolean" value="false"/>
<Property name="disabledIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_forward_disabled_large.png"/>
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_forward_disabled.png"/>
</Property>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
<Insets value="[2, 0, 2, 0]"/>
@ -129,41 +120,43 @@
<Dimension value="[5, 5]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[32, 32]"/>
<Dimension value="[24, 24]"/>
</Property>
<Property name="rolloverIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_forward_hover_large.png"/>
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_forward_hover.png"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="forwardButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="showRejectedCheckBox">
<Component class="javax.swing.JButton" name="openViewPreferencesButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="DirectoryTreeTopComponent.showRejectedCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/view-preferences-23.png"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="groupByDatasourceCheckBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="DirectoryTreeTopComponent.groupByDatasourceCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="DirectoryTreeTopComponent.openViewPreferencesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
<EmptyBorder/>
</Border>
</Property>
<Property name="borderPainted" type="boolean" value="false"/>
<Property name="contentAreaFilled" type="boolean" value="false"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[24, 24]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[24, 24]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[24, 24]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="groupByDatasourceCheckBoxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="showOnlyCurrentUserTagsCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="DirectoryTreeTopComponent.showOnlyCurrentUserTagsCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="showOnlyCurrentUserTagsCheckboxActionPerformed"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="openViewPreferencesButtonActionPerformed"/>
</Events>
</Component>
</SubComponents>

View File

@ -24,11 +24,6 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
@ -40,10 +35,11 @@ import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.prefs.PreferenceChangeEvent;
import java.util.prefs.PreferenceChangeListener;
import java.util.Properties;
import javax.swing.Action;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.tree.TreeSelectionModel;
import org.apache.commons.lang3.StringUtils;
import org.openide.explorer.ExplorerManager;
@ -60,6 +56,7 @@ import org.openide.util.NbBundle.Messages;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.RuntimeProperties;
import org.sleuthkit.autopsy.core.UserPreferences;
@ -67,6 +64,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.CoreComponentControl;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataExplorer;
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.corecomponents.ViewPreferencesPanel;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.datamodel.ArtifactNodeSelectionInfo;
@ -105,12 +103,15 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
private final transient ExplorerManager em = new ExplorerManager();
private static DirectoryTreeTopComponent instance;
private final DataResultTopComponent dataResult = new DataResultTopComponent(Bundle.DirectoryTreeTopComponent_resultsView_title());
private final ViewPreferencesPanel viewPreferencesPanel = new ViewPreferencesPanel(true);
private final LinkedList<String[]> backList;
private final LinkedList<String[]> forwardList;
private static final String PREFERRED_ID = "DirectoryTreeTopComponent"; //NON-NLS
private static final Logger LOGGER = Logger.getLogger(DirectoryTreeTopComponent.class.getName());
private AutopsyTreeChildFactory autopsyTreeChildFactory;
private Children autopsyTreeChildren;
private Accounts accounts;
private boolean showRejectedResults;
private static final long DEFAULT_DATASOURCE_GROUPING_THRESHOLD = 5; // Threshold for prompting the user about grouping by data source
private static final String GROUPING_THRESHOLD_NAME = "GroupDataSourceThreshold";
private static final String SETTINGS_FILE = "CasePreferences.properties"; //NON-NLS
@ -137,8 +138,24 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
backButton.setEnabled(false);
forwardButton.setEnabled(false);
groupByDatasourceCheckBox.setSelected(UserPreferences.groupItemsInTreeByDatasource());
showOnlyCurrentUserTagsCheckbox.setSelected(UserPreferences.showOnlyCurrentUserTags());
viewPreferencesPopupMenu.add(viewPreferencesPanel);
viewPreferencesPopupMenu.setSize(viewPreferencesPanel.getPreferredSize().width + 6, viewPreferencesPanel.getPreferredSize().height + 6);
viewPreferencesPopupMenu.addPopupMenuListener(new PopupMenuListener() {
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
openViewPreferencesButton.setSelected(true);
}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
openViewPreferencesButton.setSelected(false);
}
@Override
public void popupMenuCanceled(PopupMenuEvent e) {
openViewPreferencesButton.setSelected(false);
}
});
}
/**
@ -149,9 +166,11 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
@Override
public void preferenceChange(PreferenceChangeEvent evt) {
switch (evt.getKey()) {
case UserPreferences.DISPLAY_TIMES_IN_LOCAL_TIME:
case UserPreferences.HIDE_KNOWN_FILES_IN_DATA_SRCS_TREE:
case UserPreferences.HIDE_SLACK_FILES_IN_DATA_SRCS_TREE:
case UserPreferences.GROUP_ITEMS_IN_TREE_BY_DATASOURCE:
case UserPreferences.HIDE_CENTRAL_REPO_COMMENTS_AND_OCCURRENCES:
case UserPreferences.KEEP_PREFERRED_VIEWER:
refreshContentTreeSafe();
break;
case UserPreferences.SHOW_ONLY_CURRENT_USER_TAGS:
@ -159,7 +178,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
break;
case UserPreferences.HIDE_KNOWN_FILES_IN_VIEWS_TREE:
case UserPreferences.HIDE_SLACK_FILES_IN_VIEWS_TREE:
// TODO: Need a way to refresh the Views subtree
// TODO: Need a way to refresh the Views subtree alone.
refreshContentTreeSafe();
break;
}
}
@ -183,6 +203,28 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
return this.dataResult;
}
/**
* Show rejected results?
*
* @return True if showing rejected results; otherwise false.
*/
public boolean getShowRejectedResults() {
return showRejectedResults;
}
/**
* Setter to determine if rejected results should be shown or not.
*
* @param showRejectedResults True if showing rejected results; otherwise
* false.
*/
public void setShowRejectedResults(boolean showRejectedResults) {
this.showRejectedResults = showRejectedResults;
if (accounts != null) {
accounts.setShowRejected(showRejectedResults);
}
}
/**
* 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
@ -191,60 +233,57 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
viewPreferencesPopupMenu = new javax.swing.JPopupMenu();
treeView = new BeanTreeView();
backButton = new javax.swing.JButton();
forwardButton = new javax.swing.JButton();
showRejectedCheckBox = new javax.swing.JCheckBox();
groupByDatasourceCheckBox = new javax.swing.JCheckBox();
showOnlyCurrentUserTagsCheckbox = new javax.swing.JCheckBox();
openViewPreferencesButton = new javax.swing.JButton();
treeView.setBorder(null);
backButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_large.png"))); // NOI18N
backButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(backButton, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.backButton.text")); // NOI18N
backButton.setBorderPainted(false);
backButton.setContentAreaFilled(false);
backButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_disabled_large.png"))); // NOI18N
backButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_disabled.png"))); // NOI18N
backButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
backButton.setMaximumSize(new java.awt.Dimension(55, 100));
backButton.setMinimumSize(new java.awt.Dimension(5, 5));
backButton.setPreferredSize(new java.awt.Dimension(32, 32));
backButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_hover_large.png"))); // NOI18N
backButton.setPreferredSize(new java.awt.Dimension(24, 24));
backButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_hover.png"))); // NOI18N
backButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
backButtonActionPerformed(evt);
}
});
forwardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_large.png"))); // NOI18N
forwardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(forwardButton, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.forwardButton.text")); // NOI18N
forwardButton.setBorderPainted(false);
forwardButton.setContentAreaFilled(false);
forwardButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_disabled_large.png"))); // NOI18N
forwardButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_disabled.png"))); // NOI18N
forwardButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
forwardButton.setMaximumSize(new java.awt.Dimension(55, 100));
forwardButton.setMinimumSize(new java.awt.Dimension(5, 5));
forwardButton.setPreferredSize(new java.awt.Dimension(32, 32));
forwardButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_hover_large.png"))); // NOI18N
forwardButton.setPreferredSize(new java.awt.Dimension(24, 24));
forwardButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_hover.png"))); // NOI18N
forwardButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
forwardButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(showRejectedCheckBox, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.showRejectedCheckBox.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(groupByDatasourceCheckBox, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.groupByDatasourceCheckBox.text")); // NOI18N
groupByDatasourceCheckBox.addActionListener(new java.awt.event.ActionListener() {
openViewPreferencesButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/view-preferences-23.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(openViewPreferencesButton, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.openViewPreferencesButton.text")); // NOI18N
openViewPreferencesButton.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1));
openViewPreferencesButton.setBorderPainted(false);
openViewPreferencesButton.setContentAreaFilled(false);
openViewPreferencesButton.setMaximumSize(new java.awt.Dimension(24, 24));
openViewPreferencesButton.setMinimumSize(new java.awt.Dimension(24, 24));
openViewPreferencesButton.setPreferredSize(new java.awt.Dimension(24, 24));
openViewPreferencesButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
groupByDatasourceCheckBoxActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(showOnlyCurrentUserTagsCheckbox, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.showOnlyCurrentUserTagsCheckbox.text")); // NOI18N
showOnlyCurrentUserTagsCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
showOnlyCurrentUserTagsCheckboxActionPerformed(evt);
openViewPreferencesButtonActionPerformed(evt);
}
});
@ -254,36 +293,24 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(treeView)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(showOnlyCurrentUserTagsCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(showRejectedCheckBox)
.addComponent(groupByDatasourceCheckBox))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 140, Short.MAX_VALUE)
.addComponent(openViewPreferencesButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(0, 0, 0)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(5, 5, 5)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(showRejectedCheckBox)
.addComponent(showOnlyCurrentUserTagsCheckbox))
.addComponent(openViewPreferencesButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(groupByDatasourceCheckBox))
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(forwardButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(treeView, javax.swing.GroupLayout.DEFAULT_SIZE, 843, Short.MAX_VALUE)
.addGap(0, 0, 0))
.addComponent(treeView, javax.swing.GroupLayout.DEFAULT_SIZE, 919, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
@ -336,21 +363,17 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
this.setCursor(null);
}//GEN-LAST:event_forwardButtonActionPerformed
private void groupByDatasourceCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_groupByDatasourceCheckBoxActionPerformed
UserPreferences.setGroupItemsInTreeByDatasource(this.groupByDatasourceCheckBox.isSelected());
}//GEN-LAST:event_groupByDatasourceCheckBoxActionPerformed
private void showOnlyCurrentUserTagsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showOnlyCurrentUserTagsCheckboxActionPerformed
UserPreferences.setShowOnlyCurrentUserTags(this.showOnlyCurrentUserTagsCheckbox.isSelected());
}//GEN-LAST:event_showOnlyCurrentUserTagsCheckboxActionPerformed
private void openViewPreferencesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openViewPreferencesButtonActionPerformed
viewPreferencesPanel.load();
viewPreferencesPopupMenu.show(openViewPreferencesButton, 0, openViewPreferencesButton.getHeight() - 1);
}//GEN-LAST:event_openViewPreferencesButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton backButton;
private javax.swing.JButton forwardButton;
private javax.swing.JCheckBox groupByDatasourceCheckBox;
private javax.swing.JCheckBox showOnlyCurrentUserTagsCheckbox;
private javax.swing.JCheckBox showRejectedCheckBox;
private javax.swing.JButton openViewPreferencesButton;
private javax.swing.JScrollPane treeView;
private javax.swing.JPopupMenu viewPreferencesPopupMenu;
// End of variables declaration//GEN-END:variables
/**
@ -406,43 +429,17 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
* Ask the user if they want to group by data source when opening a large
* case.
*
* @param currentCase
* @param dataSourceCount
* @param dataSourceCount The number of data sources in the case.
*/
private void promptForDataSourceGrouping(Case currentCase, int dataSourceCount) {
Path settingsFile = Paths.get(currentCase.getConfigDirectory(), SETTINGS_FILE); //NON-NLS
if (settingsFile.toFile().exists()) {
// Read the setting
try (InputStream inputStream = Files.newInputStream(settingsFile)) {
Properties props = new Properties();
props.load(inputStream);
if (props.getProperty("groupByDataSource", "false").equals("true")) {
UserPreferences.setGroupItemsInTreeByDatasource(true);
groupByDatasourceCheckBox.setSelected(true);
}
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, "Error reading settings file", ex);
}
} else {
private void promptForDataSourceGrouping(int dataSourceCount) {
if (CasePreferences.getGroupItemsInTreeByDataSource() == null) {
GroupDataSourcesDialog dialog = new GroupDataSourcesDialog(dataSourceCount);
dialog.display();
if (dialog.groupByDataSourceSelected()) {
UserPreferences.setGroupItemsInTreeByDatasource(true);
groupByDatasourceCheckBox.setSelected(true);
}
// Save the response
Properties props = new Properties();
if (dialog.groupByDataSourceSelected()) {
props.setProperty("groupByDataSource", "true");
CasePreferences.setGroupItemsInTreeByDataSource(true);
refreshContentTreeSafe();
} else {
props.setProperty("groupByDataSource", "false");
}
try (OutputStream fos = Files.newOutputStream(settingsFile)) {
props.store(fos, ""); //NON-NLS
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, "Error writing settings file", ex);
CasePreferences.setGroupItemsInTreeByDataSource(false);
}
}
}
@ -488,9 +485,9 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
try {
int dataSourceCount = currentCase.getDataSources().size();
if (!UserPreferences.groupItemsInTreeByDatasource()
if (!Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
&& dataSourceCount > threshold) {
promptForDataSourceGrouping(currentCase, dataSourceCount);
promptForDataSourceGrouping(dataSourceCount);
}
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error loading data sources", ex);
@ -545,11 +542,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
Children resultsChildren = results.getChildren();
Arrays.stream(resultsChildren.getNodes()).forEach(tree::expandNode);
Accounts accounts = resultsChildren.findChild(Accounts.NAME).getLookup().lookup(Accounts.class);
if (!Objects.isNull(accounts)) {
showRejectedCheckBox.setAction(accounts.newToggleShowRejectedAction());
showRejectedCheckBox.setSelected(false);
}
accounts = resultsChildren.findChild(Accounts.NAME).getLookup().lookup(Accounts.class);
}
Node views = rootChildren.findChild(ViewsNode.NAME);
@ -917,8 +910,12 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
*/
private void refreshTagsTree() {
SwingUtilities.invokeLater(() -> {
// if no open case or has no data then there is no tree to rebuild
if (UserPreferences.groupItemsInTreeByDatasource()) {
// Ensure the component children have been created first.
if (autopsyTreeChildren == null) {
return;
}
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
for (Node dataSource : autopsyTreeChildren.getNodes()) {
Node tagsNode = dataSource.getChildren().findChild(Tags.getTagsDisplayName());
if (tagsNode != null) {

View File

@ -34,7 +34,7 @@ import org.openide.util.Lookup;
iconBase = "org/sleuthkit/autopsy/directorytree/external-viewer-rules-32x32.png",
keywords = "#OptionsCategory_Keywords_ExternalViewer",
keywordsCategory = "ExternalViewer",
position = 12
position = 13
)
public final class ExternalViewerOptionsPanelController extends OptionsPanelController {

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -35,6 +35,7 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
@ -138,9 +139,8 @@ public class ViewContextAction extends AbstractAction {
*/
DirectoryTreeTopComponent treeViewTopComponent = DirectoryTreeTopComponent.findInstance();
ExplorerManager treeViewExplorerMgr = treeViewTopComponent.getExplorerManager();
Node parentTreeViewNode;
if (UserPreferences.groupItemsInTreeByDatasource()) { // 'Group by Data Source' view
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) { // 'Group by Data Source' view
SleuthkitCase skCase;
String dsname;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 749 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 611 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 761 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 756 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 639 B

Some files were not shown because too many files have changed in this diff Show More