Merge branch 'develop' of github.com:sleuthkit/autopsy into 6345-64bitCarverOneInstaller

This commit is contained in:
Greg DiCristofaro
2020-06-18 08:22:29 -04:00
107 changed files with 7965 additions and 5755 deletions
@@ -107,7 +107,7 @@ import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.autopsy.events.AutopsyEventException;
import org.sleuthkit.autopsy.events.AutopsyEventPublisher;
import org.sleuthkit.autopsy.filequery.OpenFileDiscoveryAction;
import org.sleuthkit.autopsy.discovery.OpenDiscoveryAction;
import org.sleuthkit.autopsy.ingest.IngestJob;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.IngestServices;
@@ -1124,7 +1124,7 @@ public class Case {
CallableSystemAction.get(OpenCommVisualizationToolAction.class).setEnabled(true);
CallableSystemAction.get(CommonAttributeSearchAction.class).setEnabled(true);
CallableSystemAction.get(OpenOutputFolderAction.class).setEnabled(false);
CallableSystemAction.get(OpenFileDiscoveryAction.class).setEnabled(true);
CallableSystemAction.get(OpenDiscoveryAction.class).setEnabled(true);
/*
* Add the case to the recent cases tracker that supplies a list
@@ -1179,7 +1179,7 @@ public class Case {
CallableSystemAction.get(OpenCommVisualizationToolAction.class).setEnabled(false);
CallableSystemAction.get(OpenOutputFolderAction.class).setEnabled(false);
CallableSystemAction.get(CommonAttributeSearchAction.class).setEnabled(false);
CallableSystemAction.get(OpenFileDiscoveryAction.class).setEnabled(false);
CallableSystemAction.get(OpenDiscoveryAction.class).setEnabled(false);
/*
* Clear the notifications in the notfier component in the lower
@@ -310,6 +310,18 @@ public class Persona {
PersonaAccount.removePersonaAccount(account.getId());
}
/**
* Modifies the confidence / justification of the given PersonaAccount
*
* @param account account to modify
*
* @throws CentralRepoException If there is an error in querying the
* Personas table.
*/
public void modifyAccount(PersonaAccount account, Confidence confidence, String justification) throws CentralRepoException {
PersonaAccount.modifyPersonaAccount(account.getId(), confidence, justification);
}
/**
* Marks this persona as deleted
*/
@@ -459,7 +471,7 @@ public class Persona {
}
/**
* Removes the given alias
* Removes the given alias.
*
* @param alias alias to remove
*
@@ -469,6 +481,18 @@ public class Persona {
public void removeAlias(PersonaAlias alias) throws CentralRepoException {
PersonaAlias.removePersonaAlias(alias);
}
/**
* Modifies the given alias.
*
* @param alias alias to modify
*
* @throws CentralRepoException If there is an error in querying the
* Personas table.
*/
public void modifyAlias(PersonaAlias key, Confidence confidence, String justification) throws CentralRepoException {
PersonaAlias.modifyPersonaAlias(key, confidence, justification);
}
/**
* Gets all aliases for the persona.
@@ -497,7 +521,7 @@ public class Persona {
}
/**
* Removes the given metadata from this persona
* Removes the given metadata from this persona.
*
* @param metadata metadata to remove
*
@@ -507,6 +531,18 @@ public class Persona {
public void removeMetadata(PersonaMetadata metadata) throws CentralRepoException {
PersonaMetadata.removePersonaMetadata(metadata);
}
/**
* Modifies the given metadata.
*
* @param metadata metadata to modify
*
* @throws CentralRepoException If there is an error in querying the
* Personas table.
*/
public void modifyMetadata(PersonaMetadata key, Confidence confidence, String justification) throws CentralRepoException {
PersonaMetadata.modifyPersonaMetadata(key, confidence, justification);
}
/**
* Gets all metadata for the persona.
@@ -363,6 +363,25 @@ public class PersonaAccount {
String deleteClause = " DELETE FROM persona_accounts WHERE id = " + id;
cr.executeDeleteSQL(deleteClause);
}
/**
* Modifies the PersonaAccount row by the given id
*
* @param id row id for the account to be removed
*
* @throws CentralRepoException If there is an error in removing the
* account.
*/
static void modifyPersonaAccount(long id, Persona.Confidence confidence, String justification) throws CentralRepoException {
CentralRepository cr = CentralRepository.getInstance();
if (cr == null) {
throw new CentralRepoException("Failed to modify persona account, Central Repo is not enabled");
}
String updateClause = "UPDATE persona_accounts SET confidence_id = " + confidence.getLevelId() + ", justification = \"" + justification + "\" WHERE id = " + id;
cr.executeUpdateSQL(updateClause);
}
/**
* Callback to process a query that gets all accounts belonging to a
@@ -38,7 +38,7 @@ public class PersonaAlias {
"SELECT pa.id, pa.persona_id, pa.alias, pa.justification, pa.confidence_id, pa.date_added, pa.examiner_id, e.login_name, e.display_name "
+ "FROM persona_alias as pa "
+ "INNER JOIN examiners as e ON e.id = pa.examiner_id ";
private final long id;
private final long personaId;
private final String alias;
@@ -144,6 +144,25 @@ public class PersonaAlias {
CentralRepository.getInstance().executeDeleteSQL(deleteClause);
}
/**
* Modifies a PesronaAlias.
*
* @param alias Alias to modify.
*
* @throws CentralRepoException If there is an error in modifying the alias.
*/
static void modifyPersonaAlias(PersonaAlias alias, Persona.Confidence confidence, String justification) throws CentralRepoException {
CentralRepository cr = CentralRepository.getInstance();
if (cr == null) {
throw new CentralRepoException("Failed to modify persona alias, Central Repo is not enabled");
}
String updateClause = "UPDATE persona_alias SET confidence_id = " + confidence.getLevelId() + ", justification = \"" + justification + "\" WHERE id = " + alias.id;
cr.executeUpdateSQL(updateClause);
}
/**
* Callback to process a Persona aliases query.
*/
@@ -155,6 +155,24 @@ public class PersonaMetadata {
CentralRepository.getInstance().executeDeleteSQL(deleteClause);
}
/**
* Modifies the given PersonaMetadata
*
* @param metadata Metadata to modify.
*
* @throws CentralRepoException If there is an error in modifying the metadata.
*/
static void modifyPersonaMetadata(PersonaMetadata metadata, Persona.Confidence confidence, String justification) throws CentralRepoException {
CentralRepository cr = CentralRepository.getInstance();
if (cr == null) {
throw new CentralRepoException("Failed to modify persona metadata, Central Repo is not enabled");
}
String updateClause = "UPDATE persona_metadata SET confidence_id = " + confidence.getLevelId() + ", justification = \"" + justification + "\" WHERE id = " + metadata.id;
cr.executeUpdateSQL(updateClause);
}
/**
* Callback to process a Persona metadata query.
*/
@@ -70,3 +70,6 @@ PersonaMetadataDialog.nameTextField.text=
PersonaMetadataDialog.nameLbl.text=Name:
PersonaMetadataDialog.okBtn.text=OK
PersonaMetadataDialog.cancelBtn.text=Cancel
PersonaDetailsPanel.editAccountBtn.text=Edit
PersonaDetailsPanel.editMetadataBtn.text=Edit
PersonaDetailsPanel.editAliasBtn.text=Edit
@@ -1,6 +1,8 @@
AddMetadataDialog.title.text=Add Metadata
AddMetadataDialog_dup_msg=A metadata entry with this name has already been added to this persona
AddMetadataDialog_dup_msg=A metadata entry with this name has already been added to this persona.
AddMetadataDialog_dup_Title=Metadata add failure
AddMetadataDialog_empty_name_msg=A metadata entry cannot have an empty name or value.
AddMetadataDialog_empty_name_Title=Missing field(s)
CTL_OpenPersonaManager=Persona Manager
CTL_PersonaManagerTopComponentAction=Persona Manager
CTL_PersonaDetailsTopComponent=Persona Details
@@ -17,22 +19,24 @@ PersonaAccountDialog_search_empty_Title=Account not found
PersonaAccountDialog_search_failure_msg=Central Repository account search failed.
PersonaAccountDialog_search_failure_Title=Account add failure
PersonaAliasDialog.title.text=Add Alias
PersonaAliasDialog_dup_msg=This alias has already been added to this persona
PersonaAliasDialog_dup_msg=This alias has already been added to this persona.
PersonaAliasDialog_dup_Title=Alias add failure
PersonaAliasDialog_empty_msg=An alias cannot be empty.
PersonaAliasDialog_empty_Title=Empty alias
PersonaDetailsDialogCreateTitle=Create Persona
PersonaDetailsDialogEditTitle=Edit Persona
PersonaDetailsDialogViewTitle=View Persona
PersonaDetailsPanel_CentralRepoErr_msg=Failure to write to Central Repository
PersonaDetailsPanel_CentralRepoErr_msg=Failure to write to Central Repository.
PersonaDetailsPanel_CentralRepoErr_Title=Central Repository failure
PersonaDetailsPanel_empty_justification_msg=The justification field cannot be empty
PersonaDetailsPanel_empty_justification_Title=Empty justification
PersonaDetailsPanel_EmptyComment_msg=Persona comment cannot be empty
PersonaDetailsPanel_EmptyComment_msg=Persona comment cannot be empty.
PersonaDetailsPanel_EmptyComment_Title=Empty persona comment
PersonaDetailsPanel_EmptyName_msg=Persona name cannot be empty
PersonaDetailsPanel_EmptyName_msg=Persona name cannot be empty.
PersonaDetailsPanel_EmptyName_Title=Empty persona name
PersonaDetailsPanel_load_exception_msg=Failed to load persona
PersonaDetailsPanel_load_exception_msg=Failed to load persona.
PersonaDetailsPanel_load_exception_Title=Initialization failure
PersonaDetailsPanel_NotEnoughAccounts_msg=A persona needs at least one account
PersonaDetailsPanel_NotEnoughAccounts_msg=A persona needs at least one account.
PersonaDetailsPanel_NotEnoughAccounts_Title=Missing account
PersonaManagerTopComponent.createBtn.text=New Persona
PersonaManagerTopComponent.searchBtn.text=Search
@@ -103,6 +107,9 @@ PersonaMetadataDialog.nameTextField.text=
PersonaMetadataDialog.nameLbl.text=Name:
PersonaMetadataDialog.okBtn.text=OK
PersonaMetadataDialog.cancelBtn.text=Cancel
PersonaDetailsPanel.editAccountBtn.text=Edit
PersonaDetailsPanel.editMetadataBtn.text=Edit
PersonaDetailsPanel.editAliasBtn.text=Edit
PMTopComponent_delete_confirmation_msg=Are you sure you want to delete this persona?
PMTopComponent_delete_confirmation_Title=Are you sure?
PMTopComponent_delete_exception_msg=Failed to delete persona.
@@ -23,11 +23,11 @@ import java.io.Serializable;
import java.util.Collection;
import java.util.logging.Level;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.ListCellRenderer;
import javax.swing.SwingUtilities;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount;
@@ -46,27 +46,50 @@ public class PersonaAccountDialog extends JDialog {
private static final Logger logger = Logger.getLogger(PersonaAccountDialog.class.getName());
private static final long serialVersionUID = 1L;
private final TypeChoiceRenderer TYPE_CHOICE_RENDERER = new TypeChoiceRenderer();
private final PersonaDetailsPanel pdp;
private PersonaDetailsPanel.PAccount currentAccount = null;
/**
* Creates new add account dialog
*/
@Messages({"PersonaAccountDialog.title.text=Add Account",})
public PersonaAccountDialog(PersonaDetailsPanel pdp) {
super((JFrame) WindowManager.getDefault().getMainWindow(),
super(SwingUtilities.windowForComponent(pdp),
Bundle.PersonaAccountDialog_title_text(),
true);
ModalityType.APPLICATION_MODAL);
this.pdp = pdp;
initComponents();
typeComboBox.setRenderer(TYPE_CHOICE_RENDERER);
display();
}
PersonaAccountDialog(PersonaDetailsPanel pdp, PersonaDetailsPanel.PAccount acc) {
super(SwingUtilities.windowForComponent(pdp),
Bundle.PersonaAccountDialog_title_text(),
ModalityType.APPLICATION_MODAL);
this.pdp = pdp;
initComponents();
currentAccount = acc;
confidenceComboBox.setSelectedItem(acc.confidence);
justificationTextField.setText(acc.justification);
typeComboBox.setSelectedItem(acc.account.getAccountType());
identifierTextField.setText(acc.account.getIdentifier());
typeComboBox.setEnabled(false);
identifierTextField.setEnabled(false);
typeComboBox.setRenderer(TYPE_CHOICE_RENDERER);
display();
}
/**
* This class handles displaying and rendering drop down menu for account choices
* This class handles displaying and rendering drop down menu for account
* choices
*/
private class TypeChoiceRenderer extends JLabel implements ListCellRenderer<CentralRepoAccountType>, Serializable {
@@ -80,11 +103,10 @@ public class PersonaAccountDialog extends JDialog {
return this;
}
}
@Messages({
"PersonaAccountDialog_get_types_exception_Title=Central Repository failure",
"PersonaAccountDialog_get_types_exception_msg=Failed to access central repository.",
})
"PersonaAccountDialog_get_types_exception_msg=Failed to access central repository.",})
private CentralRepoAccountType[] getAllAccountTypes() {
Collection<CentralRepoAccountType> allAccountTypes;
try {
@@ -92,9 +114,9 @@ public class PersonaAccountDialog extends JDialog {
} catch (CentralRepoException e) {
logger.log(Level.SEVERE, "Failed to access central repository", e);
JOptionPane.showMessageDialog(this,
Bundle.PersonaAccountDialog_get_types_exception_Title(),
Bundle.PersonaAccountDialog_get_types_exception_msg(),
JOptionPane.ERROR_MESSAGE);
Bundle.PersonaAccountDialog_get_types_exception_Title(),
Bundle.PersonaAccountDialog_get_types_exception_msg(),
JOptionPane.ERROR_MESSAGE);
return new CentralRepoAccountType[0];
}
return allAccountTypes.toArray(new CentralRepoAccountType[0]);
@@ -303,17 +325,23 @@ public class PersonaAccountDialog extends JDialog {
JOptionPane.ERROR_MESSAGE);
return;
}
if (pdp.addAccount(
result,
justificationTextField.getText(),
(Persona.Confidence) confidenceComboBox.getSelectedItem())) {
Persona.Confidence confidence = (Persona.Confidence) confidenceComboBox.getSelectedItem();
String justification = justificationTextField.getText();
if (currentAccount != null) {
currentAccount.confidence = confidence;
currentAccount.justification = justification;
dispose();
} else {
JOptionPane.showMessageDialog(this,
Bundle.PersonaAccountDialog_dup_msg(),
Bundle.PersonaAccountDialog_dup_Title(),
JOptionPane.ERROR_MESSAGE);
if (pdp.addAccount(result, justification, confidence)) {
dispose();
} else {
JOptionPane.showMessageDialog(this,
Bundle.PersonaAccountDialog_dup_msg(),
Bundle.PersonaAccountDialog_dup_Title(),
JOptionPane.ERROR_MESSAGE);
}
}
}//GEN-LAST:event_okBtnActionPerformed
@@ -324,7 +352,7 @@ public class PersonaAccountDialog extends JDialog {
private void identifierTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_identifierTextFieldActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_identifierTextFieldActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton cancelBtn;
private javax.swing.JComboBox<org.sleuthkit.autopsy.centralrepository.datamodel.Persona.Confidence> confidenceComboBox;
@@ -19,8 +19,8 @@
package org.sleuthkit.autopsy.centralrepository.persona;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.centralrepository.datamodel.Persona;
@@ -35,20 +35,39 @@ public class PersonaAliasDialog extends JDialog {
private final PersonaDetailsPanel pdp;
private PersonaDetailsPanel.PAlias currentAlias = null;
/**
* Creates new add alias dialog
*/
@Messages({"PersonaAliasDialog.title.text=Add Alias",})
public PersonaAliasDialog(PersonaDetailsPanel pdp) {
super((JFrame) WindowManager.getDefault().getMainWindow(),
super(SwingUtilities.windowForComponent(pdp),
Bundle.PersonaAliasDialog_title_text(),
true);
ModalityType.APPLICATION_MODAL);
this.pdp = pdp;
initComponents();
display();
}
PersonaAliasDialog(PersonaDetailsPanel pdp, PersonaDetailsPanel.PAlias pa) {
super(SwingUtilities.windowForComponent(pdp),
Bundle.PersonaAliasDialog_title_text(),
ModalityType.APPLICATION_MODAL);
this.pdp = pdp;
initComponents();
currentAlias = pa;
confidenceComboBox.setSelectedItem(pa.confidence);
justificationTextField.setText(pa.justification);
aliasTextField.setText(pa.alias);
aliasTextField.setEnabled(false);
display();
}
/**
* 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
@@ -176,9 +195,18 @@ public class PersonaAliasDialog extends JDialog {
}
@Messages({
"PersonaAliasDialog_empty_Title=Empty alias",
"PersonaAliasDialog_empty_msg=An alias cannot be empty.",
"PersonaAliasDialog_dup_Title=Alias add failure",
"PersonaAliasDialog_dup_msg=This alias has already been added to this persona",})
"PersonaAliasDialog_dup_msg=This alias has already been added to this persona.",})
private void okBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okBtnActionPerformed
if (aliasTextField.getText().isEmpty()) {
JOptionPane.showMessageDialog(this,
Bundle.PersonaAliasDialog_empty_msg(),
Bundle.PersonaAliasDialog_empty_Title(),
JOptionPane.ERROR_MESSAGE);
return;
}
if (justificationTextField.getText().isEmpty()) {
JOptionPane.showMessageDialog(this,
Bundle.PersonaDetailsPanel_empty_justification_msg(),
@@ -186,16 +214,23 @@ public class PersonaAliasDialog extends JDialog {
JOptionPane.ERROR_MESSAGE);
return;
}
if (pdp.addAlias(
aliasTextField.getText(),
justificationTextField.getText(),
(Persona.Confidence) confidenceComboBox.getSelectedItem())) {
Persona.Confidence confidence = (Persona.Confidence) confidenceComboBox.getSelectedItem();
String justification = justificationTextField.getText();
if (currentAlias != null) {
currentAlias.confidence = confidence;
currentAlias.justification = justification;
dispose();
} else {
JOptionPane.showMessageDialog(this,
if (pdp.addAlias(aliasTextField.getText(), justification, confidence)) {
dispose();
} else {
JOptionPane.showMessageDialog(this,
Bundle.PersonaAliasDialog_dup_msg(),
Bundle.PersonaAliasDialog_dup_Title(),
JOptionPane.ERROR_MESSAGE);
}
}
}//GEN-LAST:event_okBtnActionPerformed
@@ -84,19 +84,25 @@
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="addAccountBtn" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="editAccountBtn" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="deleteAccountBtn" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="addMetadataBtn" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="editMetadataBtn" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="deleteMetadataBtn" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="addAliasBtn" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="editAliasBtn" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="deleteAliasBtn" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
@@ -144,24 +150,27 @@
<Group type="103" groupAlignment="3" attributes="0">
<Component id="addAccountBtn" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="deleteAccountBtn" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="editAccountBtn" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="metadataLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="metadataTablePane" min="-2" pref="66" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="deleteMetadataBtn" min="-2" max="-2" attributes="0"/>
<Component id="addMetadataBtn" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="addMetadataBtn" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="deleteMetadataBtn" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="editMetadataBtn" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="aliasesLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="aliasesTablePane" min="-2" pref="74" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="deleteAliasBtn" min="-2" max="-2" attributes="0"/>
<Component id="addAliasBtn" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="addAliasBtn" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="deleteAliasBtn" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="editAliasBtn" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="casesLbl" min="-2" max="-2" attributes="0"/>
@@ -264,6 +273,14 @@
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="editAccountBtn">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonaDetailsPanel.editAccountBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="deleteAccountBtn">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
@@ -303,6 +320,14 @@
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="editMetadataBtn">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonaDetailsPanel.editMetadataBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="deleteMetadataBtn">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
@@ -342,6 +367,14 @@
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="editAliasBtn">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonaDetailsPanel.editAliasBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="deleteAliasBtn">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
@@ -23,8 +23,10 @@ import java.awt.event.ActionEvent;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import javax.swing.JButton;
import javax.swing.JOptionPane;
@@ -69,6 +71,10 @@ public final class PersonaDetailsPanel extends javax.swing.JPanel {
private final List<PersonaMetadata> metadataToRemove = new ArrayList<>();
private final List<PersonaAlias> aliasesToRemove = new ArrayList<>();
private final Map<PersonaAccount, PAccount> accountsToEdit = new HashMap<>();
private final Map<PersonaMetadata, PMetadata> metadataToEdit = new HashMap<>();
private final Map<PersonaAlias, PAlias> aliasesToEdit = new HashMap<>();
private Persona currentPersona;
private List<PersonaAccount> currentAccounts = new ArrayList<>();
private List<PersonaMetadata> currentMetadata = new ArrayList<>();
@@ -91,6 +97,19 @@ public final class PersonaDetailsPanel extends javax.swing.JPanel {
addAccountBtn.addActionListener((ActionEvent e) -> {
new PersonaAccountDialog(this);
});
editAccountBtn.addActionListener((ActionEvent e) -> {
int selectedRow = accountsTable.getSelectedRow();
if (selectedRow != -1) {
if (selectedRow >= currentAccounts.size()) {
PAccount acc = accountsToAdd.get(selectedRow - currentAccounts.size());
new PersonaAccountDialog(this, acc);
} else {
PersonaAccount personaAccount = currentAccounts.get(selectedRow);
accountsToEdit.putIfAbsent(personaAccount, new PAccount(personaAccount.getAccount(), personaAccount.getJustification(), personaAccount.getConfidence()));
new PersonaAccountDialog(this, accountsToEdit.get(personaAccount));
}
}
});
deleteAccountBtn.addActionListener((ActionEvent e) -> {
int selectedRow = accountsTable.getSelectedRow();
if (selectedRow != -1) {
@@ -98,21 +117,36 @@ public final class PersonaDetailsPanel extends javax.swing.JPanel {
if (selectedRow >= currentAccounts.size()) {
accountsToAdd.remove(selectedRow - currentAccounts.size());
} else {
accountsToRemove.add(currentAccounts.get(selectedRow));
currentAccounts.remove(selectedRow);
PersonaAccount toRemove = currentAccounts.get(selectedRow);
accountsToEdit.remove(toRemove);
accountsToRemove.add(toRemove);
currentAccounts.remove(toRemove);
}
updateAccountsTable();
}
});
accountsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
accountsTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> {
handleSelectionChange(e, deleteAccountBtn, accountsTable);
handleSelectionChange(e, editAccountBtn, deleteAccountBtn, accountsTable);
});
// Metadata
addMetadataBtn.addActionListener((ActionEvent e) -> {
new PersonaMetadataDialog(this);
});
editMetadataBtn.addActionListener((ActionEvent e) -> {
int selectedRow = metadataTable.getSelectedRow();
if (selectedRow != -1) {
if (selectedRow >= currentMetadata.size()) {
PMetadata md = metadataToAdd.get(selectedRow - currentMetadata.size());
new PersonaMetadataDialog(this, md);
} else {
PersonaMetadata personaMetadata = currentMetadata.get(selectedRow);
metadataToEdit.putIfAbsent(personaMetadata, new PMetadata(personaMetadata.getName(), personaMetadata.getValue(), personaMetadata.getJustification(), personaMetadata.getConfidence()));
new PersonaMetadataDialog(this, metadataToEdit.get(personaMetadata));
}
}
});
deleteMetadataBtn.addActionListener((ActionEvent e) -> {
int selectedRow = metadataTable.getSelectedRow();
if (selectedRow != -1) {
@@ -120,21 +154,36 @@ public final class PersonaDetailsPanel extends javax.swing.JPanel {
if (selectedRow >= currentMetadata.size()) {
metadataToAdd.remove(selectedRow - currentMetadata.size());
} else {
metadataToRemove.add(currentMetadata.get(selectedRow));
currentMetadata.remove(selectedRow);
PersonaMetadata toRemove = currentMetadata.get(selectedRow);
metadataToEdit.remove(toRemove);
metadataToRemove.add(toRemove);
currentMetadata.remove(toRemove);
}
updateMetadataTable();
}
});
metadataTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
metadataTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> {
handleSelectionChange(e, deleteMetadataBtn, metadataTable);
handleSelectionChange(e, editMetadataBtn, deleteMetadataBtn, metadataTable);
});
// Aliases
addAliasBtn.addActionListener((ActionEvent e) -> {
new PersonaAliasDialog(this);
});
editAliasBtn.addActionListener((ActionEvent e) -> {
int selectedRow = aliasesTable.getSelectedRow();
if (selectedRow != -1) {
if (selectedRow >= currentAliases.size()) {
PAlias pa = aliasesToAdd.get(selectedRow - currentAliases.size());
new PersonaAliasDialog(this, pa);
} else {
PersonaAlias personaAlias = currentAliases.get(selectedRow);
aliasesToEdit.putIfAbsent(personaAlias, new PAlias(personaAlias.getAlias(), personaAlias.getJustification(), personaAlias.getConfidence()));
new PersonaAliasDialog(this, aliasesToEdit.get(personaAlias));
}
}
});
deleteAliasBtn.addActionListener((ActionEvent e) -> {
int selectedRow = aliasesTable.getSelectedRow();
if (selectedRow != -1) {
@@ -142,33 +191,48 @@ public final class PersonaDetailsPanel extends javax.swing.JPanel {
if (selectedRow >= currentAliases.size()) {
aliasesToAdd.remove(selectedRow - currentAliases.size());
} else {
aliasesToRemove.add(currentAliases.get(selectedRow));
currentAliases.remove(selectedRow);
PersonaAlias toRemove = currentAliases.get(selectedRow);
aliasesToEdit.remove(toRemove);
aliasesToRemove.add(toRemove);
currentAliases.remove(toRemove);
}
updateAliasesTable();
}
});
aliasesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
aliasesTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> {
handleSelectionChange(e, deleteAliasBtn, aliasesTable);
handleSelectionChange(e, editAliasBtn, deleteAliasBtn, aliasesTable);
});
}
private void handleSelectionChange(ListSelectionEvent e, JButton btn, JTable table) {
private void handleSelectionChange(ListSelectionEvent e, JButton editBtn, JButton deleteBtn, JTable table) {
if (e.getValueIsAdjusting()) {
return;
}
btn.setEnabled(mode != PersonaDetailsMode.VIEW && table.getSelectedRow() != -1);
editBtn.setEnabled(mode != PersonaDetailsMode.VIEW && table.getSelectedRow() != -1);
deleteBtn.setEnabled(mode != PersonaDetailsMode.VIEW && table.getSelectedRow() != -1);
}
void addEditExistingAccount(PersonaAccount account, String justification, Persona.Confidence confidence) {
accountsToEdit.put(account, new PAccount(account.getAccount(), justification, confidence));
}
void addEditExistingMetadata(PersonaMetadata metadata, String justification, Persona.Confidence confidence) {
metadataToEdit.put(metadata, new PMetadata(metadata.getName(), metadata.getValue(), justification, confidence));
}
void addEditExistingAlias(PersonaAlias alias, String justification, Persona.Confidence confidence) {
aliasesToEdit.put(alias, new PAlias(alias.getAlias(), justification, confidence));
}
/**
* A data bucket class for yet-to-be-created PersonaAccount
*/
private class PAccount {
class PAccount {
private final CentralRepoAccount account;
private final String justification;
private final Persona.Confidence confidence;
CentralRepoAccount account;
String justification;
Persona.Confidence confidence;
PAccount(CentralRepoAccount account, String justification, Persona.Confidence confidence) {
this.account = account;
@@ -189,7 +253,7 @@ public final class PersonaDetailsPanel extends javax.swing.JPanel {
}
}
return false;
}
}
public boolean addAccount(CentralRepoAccount account, String justification, Persona.Confidence confidence) {
if (!accountExists(account)) {
@@ -203,12 +267,12 @@ public final class PersonaDetailsPanel extends javax.swing.JPanel {
/**
* A data bucket class for yet-to-be-created PersonaMetadata
*/
private class PMetadata {
class PMetadata {
private final String name;
private final String value;
private final String justification;
private final Persona.Confidence confidence;
String name;
String value;
String justification;
Persona.Confidence confidence;
PMetadata(String name, String value, String justification, Persona.Confidence confidence) {
this.name = name;
@@ -244,11 +308,11 @@ public final class PersonaDetailsPanel extends javax.swing.JPanel {
/**
* A data bucket class for yet-to-be-created PersonaAlias
*/
private class PAlias {
class PAlias {
private final String alias;
private final String justification;
private final Persona.Confidence confidence;
String alias;
String justification;
Persona.Confidence confidence;
PAlias(String alias, String justification, Persona.Confidence confidence) {
this.alias = alias;
@@ -301,16 +365,19 @@ public final class PersonaDetailsPanel extends javax.swing.JPanel {
accountsTablePane = new javax.swing.JScrollPane();
accountsTable = new javax.swing.JTable();
addAccountBtn = new javax.swing.JButton();
editAccountBtn = new javax.swing.JButton();
deleteAccountBtn = new javax.swing.JButton();
metadataLabel = new javax.swing.JLabel();
metadataTablePane = new javax.swing.JScrollPane();
metadataTable = new javax.swing.JTable();
addMetadataBtn = new javax.swing.JButton();
editMetadataBtn = new javax.swing.JButton();
deleteMetadataBtn = new javax.swing.JButton();
aliasesLabel = new javax.swing.JLabel();
aliasesTablePane = new javax.swing.JScrollPane();
aliasesTable = new javax.swing.JTable();
addAliasBtn = new javax.swing.JButton();
editAliasBtn = new javax.swing.JButton();
deleteAliasBtn = new javax.swing.JButton();
casesLbl = new javax.swing.JLabel();
casesTablePane = new javax.swing.JScrollPane();
@@ -354,6 +421,9 @@ public final class PersonaDetailsPanel extends javax.swing.JPanel {
org.openide.awt.Mnemonics.setLocalizedText(addAccountBtn, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.addAccountBtn.text")); // NOI18N
addAccountBtn.setEnabled(false);
org.openide.awt.Mnemonics.setLocalizedText(editAccountBtn, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.editAccountBtn.text")); // NOI18N
editAccountBtn.setEnabled(false);
org.openide.awt.Mnemonics.setLocalizedText(deleteAccountBtn, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.deleteAccountBtn.text")); // NOI18N
deleteAccountBtn.setEnabled(false);
@@ -375,6 +445,9 @@ public final class PersonaDetailsPanel extends javax.swing.JPanel {
org.openide.awt.Mnemonics.setLocalizedText(addMetadataBtn, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.addMetadataBtn.text")); // NOI18N
addMetadataBtn.setEnabled(false);
org.openide.awt.Mnemonics.setLocalizedText(editMetadataBtn, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.editMetadataBtn.text")); // NOI18N
editMetadataBtn.setEnabled(false);
org.openide.awt.Mnemonics.setLocalizedText(deleteMetadataBtn, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.deleteMetadataBtn.text")); // NOI18N
deleteMetadataBtn.setEnabled(false);
@@ -396,6 +469,9 @@ public final class PersonaDetailsPanel extends javax.swing.JPanel {
org.openide.awt.Mnemonics.setLocalizedText(addAliasBtn, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.addAliasBtn.text")); // NOI18N
addAliasBtn.setEnabled(false);
org.openide.awt.Mnemonics.setLocalizedText(editAliasBtn, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.editAliasBtn.text")); // NOI18N
editAliasBtn.setEnabled(false);
org.openide.awt.Mnemonics.setLocalizedText(deleteAliasBtn, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.deleteAliasBtn.text")); // NOI18N
deleteAliasBtn.setEnabled(false);
@@ -442,14 +518,20 @@ public final class PersonaDetailsPanel extends javax.swing.JPanel {
.addGroup(detailsPanelLayout.createSequentialGroup()
.addComponent(addAccountBtn)
.addGap(18, 18, 18)
.addComponent(editAccountBtn)
.addGap(18, 18, 18)
.addComponent(deleteAccountBtn))
.addGroup(detailsPanelLayout.createSequentialGroup()
.addComponent(addMetadataBtn)
.addGap(18, 18, 18)
.addComponent(editMetadataBtn)
.addGap(18, 18, 18)
.addComponent(deleteMetadataBtn))
.addGroup(detailsPanelLayout.createSequentialGroup()
.addComponent(addAliasBtn)
.addGap(18, 18, 18)
.addComponent(editAliasBtn)
.addGap(18, 18, 18)
.addComponent(deleteAliasBtn)))
.addGap(0, 0, Short.MAX_VALUE))
.addGroup(detailsPanelLayout.createSequentialGroup()
@@ -486,23 +568,26 @@ public final class PersonaDetailsPanel extends javax.swing.JPanel {
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(addAccountBtn)
.addComponent(deleteAccountBtn))
.addComponent(deleteAccountBtn)
.addComponent(editAccountBtn))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(metadataLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(metadataTablePane, javax.swing.GroupLayout.PREFERRED_SIZE, 66, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(addMetadataBtn)
.addComponent(deleteMetadataBtn)
.addComponent(addMetadataBtn))
.addComponent(editMetadataBtn))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(aliasesLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(aliasesTablePane, javax.swing.GroupLayout.PREFERRED_SIZE, 74, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(addAliasBtn)
.addComponent(deleteAliasBtn)
.addComponent(addAliasBtn))
.addComponent(editAliasBtn))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(casesLbl)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@@ -549,6 +634,9 @@ public final class PersonaDetailsPanel extends javax.swing.JPanel {
private javax.swing.JButton deleteAliasBtn;
private javax.swing.JButton deleteMetadataBtn;
private javax.swing.JPanel detailsPanel;
private javax.swing.JButton editAccountBtn;
private javax.swing.JButton editAliasBtn;
private javax.swing.JButton editMetadataBtn;
private javax.swing.JTextField examinerField;
private javax.swing.JLabel examinerLbl;
private javax.swing.JLabel metadataLabel;
@@ -560,7 +648,7 @@ public final class PersonaDetailsPanel extends javax.swing.JPanel {
@Messages({
"PersonaDetailsPanel_load_exception_Title=Initialization failure",
"PersonaDetailsPanel_load_exception_msg=Failed to load persona",})
"PersonaDetailsPanel_load_exception_msg=Failed to load persona.",})
private void loadPersona(Component parent, Persona persona) {
String examiner;
String creationDate;
@@ -626,6 +714,9 @@ public final class PersonaDetailsPanel extends javax.swing.JPanel {
deleteAccountBtn.setEnabled(false);
deleteMetadataBtn.setEnabled(false);
deleteAliasBtn.setEnabled(false);
editAccountBtn.setEnabled(false);
editMetadataBtn.setEnabled(false);
editAliasBtn.setEnabled(false);
}
/**
@@ -729,12 +820,15 @@ public final class PersonaDetailsPanel extends javax.swing.JPanel {
addAccountBtn.setEnabled(enabled);
addMetadataBtn.setEnabled(enabled);
addAliasBtn.setEnabled(enabled);
addAccountBtn.setVisible(enabled);
editAccountBtn.setVisible(enabled);
deleteAccountBtn.setVisible(enabled);
addMetadataBtn.setVisible(enabled);
editMetadataBtn.setVisible(enabled);
deleteMetadataBtn.setVisible(enabled);
addAliasBtn.setVisible(enabled);
editAliasBtn.setVisible(enabled);
deleteAliasBtn.setVisible(enabled);
}
@@ -780,13 +874,13 @@ public final class PersonaDetailsPanel extends javax.swing.JPanel {
}
@Messages({
"PersonaDetailsPanel_NotEnoughAccounts_msg=A persona needs at least one account",
"PersonaDetailsPanel_NotEnoughAccounts_msg=A persona needs at least one account.",
"PersonaDetailsPanel_NotEnoughAccounts_Title=Missing account",
"PersonaDetailsPanel_CentralRepoErr_msg=Failure to write to Central Repository",
"PersonaDetailsPanel_CentralRepoErr_msg=Failure to write to Central Repository.",
"PersonaDetailsPanel_CentralRepoErr_Title=Central Repository failure",
"PersonaDetailsPanel_EmptyName_msg=Persona name cannot be empty",
"PersonaDetailsPanel_EmptyName_msg=Persona name cannot be empty.",
"PersonaDetailsPanel_EmptyName_Title=Empty persona name",
"PersonaDetailsPanel_EmptyComment_msg=Persona comment cannot be empty",
"PersonaDetailsPanel_EmptyComment_msg=Persona comment cannot be empty.",
"PersonaDetailsPanel_EmptyComment_Title=Empty persona comment",})
Persona okHandler() {
if (accountsToAdd.size() + currentAccounts.size() < 1) {
@@ -851,18 +945,27 @@ public final class PersonaDetailsPanel extends javax.swing.JPanel {
for (PersonaAccount acc : accountsToRemove) {
ret.removeAccount(acc);
}
for (HashMap.Entry<PersonaAccount, PAccount> entry : accountsToEdit.entrySet()) {
ret.modifyAccount(entry.getKey(), entry.getValue().confidence, entry.getValue().justification);
}
for (PMetadata md : metadataToAdd) {
ret.addMetadata(md.name, md.value, md.justification, md.confidence);
}
for (PersonaMetadata md : metadataToRemove) {
ret.removeMetadata(md);
}
for (HashMap.Entry<PersonaMetadata, PMetadata> entry : metadataToEdit.entrySet()) {
ret.modifyMetadata(entry.getKey(), entry.getValue().confidence, entry.getValue().justification);
}
for (PAlias pa : aliasesToAdd) {
ret.addAlias(pa.alias, pa.justification, pa.confidence);
}
for (PersonaAlias pa : aliasesToRemove) {
ret.removeAlias(pa);
}
for (HashMap.Entry<PersonaAlias, PAlias> entry : aliasesToEdit.entrySet()) {
ret.modifyAlias(entry.getKey(), entry.getValue().confidence, entry.getValue().justification);
}
} catch (CentralRepoException e) {
logger.log(Level.SEVERE, "Failed to access central repository", e);
JOptionPane.showMessageDialog(this,
@@ -873,20 +976,21 @@ public final class PersonaDetailsPanel extends javax.swing.JPanel {
}
break;
case VIEW:
ret = currentPersona;
break;
default:
logger.log(Level.SEVERE, "Unsupported mode: {0}", mode);
}
return ret;
}
/**
* Sets the persona name field.
*
*
* @param name Persona name.
*/
public void setPersonaName(String name) {
nameField.setText(name);
}
}
@@ -19,8 +19,8 @@
package org.sleuthkit.autopsy.centralrepository.persona;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.centralrepository.datamodel.Persona;
@@ -35,20 +35,41 @@ public class PersonaMetadataDialog extends JDialog {
private final PersonaDetailsPanel pdp;
private PersonaDetailsPanel.PMetadata currentMetadata;
/**
* Creates new add metadata dialog
*/
@Messages({"AddMetadataDialog.title.text=Add Metadata",})
public PersonaMetadataDialog(PersonaDetailsPanel pdp) {
super((JFrame) WindowManager.getDefault().getMainWindow(),
super(SwingUtilities.windowForComponent(pdp),
Bundle.AddMetadataDialog_title_text(),
true);
ModalityType.APPLICATION_MODAL);
this.pdp = pdp;
initComponents();
display();
}
PersonaMetadataDialog(PersonaDetailsPanel pdp, PersonaDetailsPanel.PMetadata md) {
super(SwingUtilities.windowForComponent(pdp),
Bundle.AddMetadataDialog_title_text(),
ModalityType.APPLICATION_MODAL);
this.pdp = pdp;
initComponents();
currentMetadata = md;
confidenceComboBox.setSelectedItem(md.confidence);
justificationTextField.setText(md.justification);
nameTextField.setText(md.name);
valueTextField.setText(md.value);
nameTextField.setEnabled(false);
valueTextField.setEnabled(false);
display();
}
/**
* 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,8 +212,17 @@ public class PersonaMetadataDialog extends JDialog {
@Messages({
"AddMetadataDialog_dup_Title=Metadata add failure",
"AddMetadataDialog_dup_msg=A metadata entry with this name has already been added to this persona",})
"AddMetadataDialog_dup_msg=A metadata entry with this name has already been added to this persona.",
"AddMetadataDialog_empty_name_Title=Missing field(s)",
"AddMetadataDialog_empty_name_msg=A metadata entry cannot have an empty name or value.",})
private void okBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okBtnActionPerformed
if (nameTextField.getText().isEmpty() || valueTextField.getText().isEmpty()) {
JOptionPane.showMessageDialog(this,
Bundle.AddMetadataDialog_empty_name_msg(),
Bundle.AddMetadataDialog_empty_name_Title(),
JOptionPane.ERROR_MESSAGE);
return;
}
if (justificationTextField.getText().isEmpty()) {
JOptionPane.showMessageDialog(this,
Bundle.PersonaDetailsPanel_empty_justification_msg(),
@@ -200,17 +230,23 @@ public class PersonaMetadataDialog extends JDialog {
JOptionPane.ERROR_MESSAGE);
return;
}
if (pdp.addMetadata(
nameTextField.getText(),
valueTextField.getText(),
justificationTextField.getText(),
(Persona.Confidence) confidenceComboBox.getSelectedItem())) {
Persona.Confidence confidence = (Persona.Confidence) confidenceComboBox.getSelectedItem();
String justification = justificationTextField.getText();
if (currentMetadata != null) {
currentMetadata.confidence = confidence;
currentMetadata.justification = justification;
dispose();
} else {
JOptionPane.showMessageDialog(this,
if (pdp.addMetadata(nameTextField.getText(), valueTextField.getText(), justification, confidence)) {
dispose();
} else {
JOptionPane.showMessageDialog(this,
Bundle.AddMetadataDialog_dup_msg(),
Bundle.AddMetadataDialog_dup_Title(),
JOptionPane.ERROR_MESSAGE);
}
}
}//GEN-LAST:event_okBtnActionPerformed
@@ -0,0 +1,76 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 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 javax.swing.JButton;
import javax.swing.JLabel;
/**
* A data bag for the persona searching thread. It wraps the account id to
* search for, and the UI label and button to update once the search completes.
*/
class AccountPersonaSearcherData {
// Account identifier to search personas for.
private final String accountIdentifer;
// Persona name label to be updated when the search is complete.
private final JLabel personaNameLabel;
// Persona action button to be updated when the search is complete
private final JButton personaActionButton;
/**
* Constructor.
*
* @param accountIdentifer Account identifier.
* @param personaNameLabel Persona name label.
* @param personaActionButton Persona button.
*/
AccountPersonaSearcherData(String accountIdentifer, JLabel personaNameLabel, JButton personaActionButton) {
this.accountIdentifer = accountIdentifer;
this.personaNameLabel = personaNameLabel;
this.personaActionButton = personaActionButton;
}
/**
* Gets the account identifier.
*
* @return Account identifier.
*/
public String getAccountIdentifer() {
return accountIdentifer;
}
/**
* Gets the persona name label.
*
* @return Persona name label.
*/
public JLabel getPersonaNameLabel() {
return personaNameLabel;
}
/**
* Gets the persona button.
*
* @return Persona button.
*/
public JButton getPersonaActionButton() {
return personaActionButton;
}
}
@@ -976,7 +976,9 @@ MessageArtifactViewer.rtfbodyScrollPane.TabConstraints.tabTitle=RTF
MessageArtifactViewer.toText.text=to list goes here
MessageArtifactViewer.toLabel.text=To:
MessageArtifactViewer.htmlPane.TabConstraints.tabTitle=HTML
CallLogArtifactViewer.localAccountPersonaLabel.text=Persona:
CallLogArtifactViewer.localAccountPersonaLabel.text=Persona
CallLogArtifactViewer.localAccountPersonaNameLabel.text=jLabel1
CallLogArtifactViewer.localAccountPersonaButton.text=jButton1
ContactArtifactViewer.personasLabel.text=Personas
MessageArtifactViewer.accountsTab.TabConstraints.tabTitle=Accounts
ContactArtifactViewer.contactImage.text=
@@ -35,6 +35,8 @@ AnnotationsContentViewer.title=Annotations
AnnotationsContentViewer.toolTip=Displays tags and comments associated with the selected content.
ApplicationContentViewer.title=Application
ApplicationContentViewer.toolTip=Displays file contents.
CallLogArtifactViewer_crdisbaled_persona_button_text=Create
CallLogArtifactViewer_crdisbaled_persona_label=Unknown
CallLogArtifactViewer_number_from=From
CallLogArtifactViewer_number_to=To
CallLogArtifactViewer_persona_button_new=Create
@@ -49,6 +51,7 @@ ContactArtifactViewer_persona_button_view=View
ContactArtifactViewer_persona_label=Persona
ContactArtifactViewer_persona_searching=\ Searching...
ContactArtifactViewer_persona_text_none=None found
ContactArtifactViewer_persona_unknown=Unknown
DataContentViewerArtifact.failedToGetAttributes.message=Failed to get some or all attributes from case database
DataContentViewerArtifact.failedToGetSourcePath.message=Failed to get source file path from case database
DefaultArtifactContentViewer.attrsTableHeader.sources=Source(s)
@@ -104,6 +107,10 @@ MediaViewVideoPanel.progressLabel.text=00:00
MediaViewVideoPanel.infoLabel.text=info
MediaViewImagePanel.imgFileTooLarge.msg=Could not load image file (too large): {0}
MessageAccountPanel_button_create_label=Create
MessageAccountPanel_button_view_label=View
MessageAccountPanel_persona_label=Persona:
MessageAccountPanel_unknown_label=Unknown
MessageArtifactViewer.AttachmentPanel.title=Attachments
Metadata.nodeText.none=None
Metadata.nodeText.truncated=(results truncated)
@@ -1084,7 +1091,9 @@ MessageArtifactViewer.rtfbodyScrollPane.TabConstraints.tabTitle=RTF
MessageArtifactViewer.toText.text=to list goes here
MessageArtifactViewer.toLabel.text=To:
MessageArtifactViewer.htmlPane.TabConstraints.tabTitle=HTML
CallLogArtifactViewer.localAccountPersonaLabel.text=Persona:
CallLogArtifactViewer.localAccountPersonaLabel.text=Persona
CallLogArtifactViewer.localAccountPersonaNameLabel.text=jLabel1
CallLogArtifactViewer.localAccountPersonaButton.text=jButton1
ContactArtifactViewer.personasLabel.text=Personas
MessageArtifactViewer.accountsTab.TabConstraints.tabTitle=Accounts
ContactArtifactViewer.contactImage.text=
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<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"/>
@@ -11,391 +11,8 @@
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="topPanel" min="-2" pref="860" max="-2" attributes="0"/>
<Component id="bottomPanel" min="-2" max="-2" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="topPanel" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="bottomPanel" min="-2" pref="297" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="topPanel">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="callDetailsPanel">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[400, 150]"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="Center"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="25" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="callDetailsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="25" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="directionLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="callLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="onLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="dateTimeLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="durationLabel" min="-2" pref="88" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<Component id="participantsListPanel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="485" 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="-2" attributes="0"/>
<Component id="callDetailsLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="participantsListPanel" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="directionLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="callLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="onLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="dateTimeLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="durationLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="directionLabel">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true">
<Font component="directionLabel" property="font" relativeSize="true" size="0"/>
</FontInfo>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="CallLogArtifactViewer.directionLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="dateTimeLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="CallLogArtifactViewer.dateTimeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="durationLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="CallLogArtifactViewer.durationLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="callDetailsLabel">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true">
<Font bold="true" component="callDetailsLabel" property="font" relativeSize="true" size="0"/>
</FontInfo>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="CallLogArtifactViewer.callDetailsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="onLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="CallLogArtifactViewer.onLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="callLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="CallLogArtifactViewer.callLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JPanel" name="participantsListPanel">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="350" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="58" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="otherAttributesPanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="Last"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="otherAttributesListPanel" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="25" max="-2" attributes="0"/>
<Component id="otherInfoLabel" min="-2" pref="372" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" pref="24" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="otherInfoLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="otherAttributesListPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="otherInfoLabel">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true">
<Font bold="true" component="otherInfoLabel" property="font" relativeSize="true" size="0"/>
</FontInfo>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="CallLogArtifactViewer.otherInfoLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JPanel" name="otherAttributesListPanel">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="413" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="88" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="bottomPanel">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="localAccountInfoPanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="North"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="50" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="localAccountLabel" min="-2" max="-2" attributes="0"/>
<Component id="jLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="jLabel4" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="24" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="deviceIdLabel" alignment="0" pref="437" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="dataSourceNameLabel" min="-2" pref="130" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="localAccountIdLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="localAccountPersonaLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="localAccountPersonaNameLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="localAccountPersonaButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="25" max="-2" attributes="0"/>
<Component id="sourceSectionLabel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace pref="243" 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="-2" attributes="0"/>
<Component id="sourceSectionLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="localAccountLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="localAccountIdLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="localAccountPersonaLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="localAccountPersonaNameLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="localAccountPersonaButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jLabel4" alignment="3" min="-2" pref="16" max="-2" attributes="0"/>
<Component id="dataSourceNameLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="deviceIdLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="22" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="jLabel4">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="CallLogArtifactViewer.jLabel4.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="dataSourceNameLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="CallLogArtifactViewer.dataSourceNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jLabel2">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="CallLogArtifactViewer.jLabel2.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="deviceIdLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="CallLogArtifactViewer.deviceIdLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="localAccountLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="CallLogArtifactViewer.localAccountLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="localAccountIdLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="CallLogArtifactViewer.localAccountIdLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="sourceSectionLabel">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true">
<Font bold="true" component="sourceSectionLabel" property="font" relativeSize="true" size="0"/>
</FontInfo>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="CallLogArtifactViewer.sourceSectionLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="localAccountPersonaLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="CallLogArtifactViewer.localAccountPersonaLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="localAccountPersonaNameLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="CallLogArtifactViewer.localAccountPersonaNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="localAccountPersonaButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="CallLogArtifactViewer.localAccountPersonaButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
</Form>
File diff suppressed because it is too large Load Diff
@@ -29,50 +29,61 @@ import java.util.Map;
*/
final class CallLogViewData {
// primary to/from number/adddress/accountId
private String number;
private String numberTypeDesignator; // to for from designator
private String name = null;
private String fromAccount = null;
private String toAccount = null;
// account identifier of the device owner, if known.
// will be one of the to or from account.
private String localAccountId = null;
private String direction;
private String dateTimeStr = null;
private String duration = null;
private Collection<String> otherRecipients = new ArrayList<>();
private String dataSourceName = null;
private String dataSourceDeviceId = null;
private String localAccountId = null; // number/accountId of device owner, may not be always known
// Account identifers of other parties in the call.
private Collection<String> otherParties = new ArrayList<>();
private Map<String, String> otherAttributes = new HashMap<>();
CallLogViewData(String number) {
this(number, null);
private String dataSourceName = null;
/**
* Constructor.
*
* @param fromAccount From account identifier, may be null;
* @param toAccount To account identifier, may be null;
*/
CallLogViewData(String fromAccount, String toAccount) {
this(fromAccount, toAccount, null);
}
CallLogViewData(String number, String direction) {
this.number = number;
/**
* Constructor.
*
* @param fromAccount From account identifier, may be null;
* @param toAccount To account identifier, may be null;
* @param direction Direction, may be null.
*/
CallLogViewData(String fromAccount, String toAccount, String direction) {
this.fromAccount = fromAccount;
this.toAccount = toAccount;
this.direction = direction;
}
String getNumber() {
return number;
String getFromAccount() {
return fromAccount;
}
void setNumber(String number) {
this.number = number;
void setFromAccount(String fromAccount) {
this.fromAccount = fromAccount;
}
public String getNumberDesignator() {
return numberTypeDesignator;
String getToAccount() {
return toAccount;
}
public void setNumberDesignator(String numberDesignator) {
this.numberTypeDesignator = numberDesignator;
}
String getName() {
return name;
}
void setName(String name) {
this.name = name;
void setToAccount(String toAccount) {
this.toAccount = toAccount;
}
String getDirection() {
@@ -91,14 +102,6 @@ final class CallLogViewData {
this.dataSourceName = dataSourceName;
}
String getDataSourceDeviceId() {
return dataSourceDeviceId;
}
void setDataSourceDeviceId(String dataSourceDeviceId) {
this.dataSourceDeviceId = dataSourceDeviceId;
}
String getDateTimeStr() {
return dateTimeStr;
}
@@ -115,13 +118,13 @@ final class CallLogViewData {
this.duration = duration;
}
Collection<String> getOtherRecipients() {
return Collections.unmodifiableCollection(otherRecipients);
Collection<String> getOtherParties() {
return Collections.unmodifiableCollection(otherParties);
}
void setOtherRecipients(Collection<String> otherParticipants) {
void setOtherParties(Collection<String> otherParticipants) {
if (otherParticipants != null) {
this.otherRecipients = new ArrayList<>(otherParticipants);
this.otherParties = new ArrayList<>(otherParticipants);
}
}
@@ -130,7 +133,7 @@ final class CallLogViewData {
}
public void setOtherAttributes(Map<String, String> otherAttributes) {
if (otherRecipients != null) {
if (otherAttributes != null) {
this.otherAttributes = new HashMap<>(otherAttributes);
}
}
@@ -0,0 +1,342 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 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.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import java.util.Optional;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
/**
*
* A class to help display a communication artifact in a panel using a
* gridbaglayout.
*/
public final class CommunicationArtifactViewerHelper {
// Number of columns in the gridbag layout.
private final static int MAX_COLS = 4;
private final static int LEFT_INDENT = 12;
/**
* Empty private constructor
*/
private CommunicationArtifactViewerHelper() {
}
/**
* Adds a new heading to the panel.
*
* @param panel Panel to update.
* @param gridbagLayout Layout to use.
* @param constraints Constrains to use.
* @param headerString Heading string to display.
*/
static void addHeader(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String headerString) {
// add a blank line before the start of new section, unless it's
// the first section
if (constraints.gridy != 0) {
addBlankLine(panel, gridbagLayout, constraints);
}
constraints.gridy++;
constraints.gridx = 0;
// let the header span all of the row
constraints.gridwidth = MAX_COLS;
// create label for heading
javax.swing.JLabel headingLabel = new javax.swing.JLabel();
headingLabel.setText(headerString);
// make it large and bold
headingLabel.setFont(headingLabel.getFont().deriveFont(Font.BOLD, headingLabel.getFont().getSize() + 2));
// add to panel
gridbagLayout.setConstraints(headingLabel, constraints);
panel.add(headingLabel);
// reset constraints to normal
constraints.gridwidth = 1;
// add line end glue
addLineEndGlue(panel, gridbagLayout, constraints);
}
/**
* Adds a filler/glue at the end of the line to keep the other columns
* aligned, in case the panel is resized.
*
* @param panel Panel to update.
* @param gridbagLayout Layout to use.
* @param constraints Constrains to use.
*/
private static void addLineEndGlue(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints) {
// Place the filler just past the last column.
constraints.gridx = MAX_COLS;
double savedWeightX = constraints.weightx;
int savedFill = constraints.fill;
constraints.weightx = 1.0; // take up all the horizontal space
constraints.fill = GridBagConstraints.BOTH;
javax.swing.Box.Filler horizontalFiller = new javax.swing.Box.Filler(new Dimension(0, 0), new Dimension(0, 0), new Dimension(32767, 0));
gridbagLayout.setConstraints(horizontalFiller, constraints);
panel.add(horizontalFiller);
// restore fill & weight
constraints.fill = savedFill;
constraints.weightx = savedWeightX;
}
/**
* Adds a filler/glue at the bottom of the panel to keep the data rows
* aligned, in case the panel is resized.
*
* @param panel Panel to update.
* @param gridbagLayout Layout to use.
* @param constraints Constrains to use.
*/
static void addPageEndGlue(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints) {
constraints.gridx = 0;
double savedWeighty = constraints.weighty;
int savedFill = constraints.fill;
constraints.weighty = 1.0; // take up all the vertical space
constraints.fill = GridBagConstraints.VERTICAL;
javax.swing.Box.Filler vertFiller = new javax.swing.Box.Filler(new Dimension(0, 0), new Dimension(0, 0), new Dimension(0, 32767));
gridbagLayout.setConstraints(vertFiller, constraints);
panel.add(vertFiller, constraints);
//Resore weight & fill
constraints.weighty = savedWeighty;
constraints.fill = savedFill;
}
/**
* Adds a blank line to the panel.
*
* @param panel Panel to update.
* @param gridbagLayout Layout to use.
* @param constraints Constrains to use.
*/
private static void addBlankLine(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints) {
constraints.gridy++;
constraints.gridx = 0;
javax.swing.JLabel filler = new javax.swing.JLabel(" ");
gridbagLayout.setConstraints(filler, constraints);
panel.add(filler);
addLineEndGlue(panel, gridbagLayout, constraints);
}
/**
* Adds a label/key to the panel.
*
* @param panel Panel to update.
* @param gridbagLayout Layout to use.
* @param constraints Constrains to use.
* @param keyString Key name to display.
*/
static void addKey(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String keyString) {
constraints.gridy++;
constraints.gridx = 0;
Insets savedInsets = constraints.insets;
// Set inset to indent in
constraints.insets = new java.awt.Insets(0, LEFT_INDENT, 0, 0);
// create label,
javax.swing.JLabel keyLabel = new javax.swing.JLabel();
keyLabel.setText(keyString + ": ");
// add to panel
gridbagLayout.setConstraints(keyLabel, constraints);
panel.add(keyLabel);
// restore inset
constraints.insets = savedInsets;
}
/**
* Adds a value string to the panel.
*
* @param panel Panel to update.
* @param gridbagLayout Layout to use.
* @param constraints Constrains to use.
* @param keyString Value string to display.
*/
static void addValue(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String valueString) {
constraints.gridx = 1;
int savedGridwidth = constraints.gridwidth;
// let the value span 2 cols
constraints.gridwidth = 2;
// create label,
javax.swing.JLabel valueField = new javax.swing.JLabel();
valueField.setText(valueString);
// attach a right click menu with Copy option
valueField.addMouseListener(new java.awt.event.MouseAdapter() {
@Override
public void mouseClicked(java.awt.event.MouseEvent evt) {
valueLabelMouseClicked(evt, valueField);
}
});
// add label to panel
gridbagLayout.setConstraints(valueField, constraints);
panel.add(valueField);
// restore constraints
constraints.gridwidth = savedGridwidth;
// end the line
addLineEndGlue(panel, gridbagLayout, constraints);
}
/**
* Adds a Persona row to the panel.
*
* Adds a persona name label and a button to the panel. Kicks off a
* background task to search for persona for the given account. Updates the
* persona name and button when the task is done.
*
* If CentralRepostory is disabled, just displays 'Unknown' persona name.
*
* @param panel Panel to update.
* @param gridbagLayout Layout to use.
* @param constraints Constrains to use.
* @param accountIdentifier Account identifier to search the persona.
*
* @return Optional PersonaSearchAndDisplayTask started to search for
* persona.
*/
@NbBundle.Messages({
"CommunicationArtifactViewerHelper_persona_label=Persona: ",
"CommunicationArtifactViewerHelper_persona_searching=Searching...",
"CommunicationArtifactViewerHelper_persona_unknown=Unknown",
"CommunicationArtifactViewerHelper_persona_button_view=View",
"CommunicationArtifactViewerHelper_persona_button_create=Create"
})
static Optional<PersonaSearchAndDisplayTask> addPersonaRow(JPanel panel, GridBagLayout gridbagLayout, GridBagConstraints constraints, String accountIdentifier) {
PersonaSearchAndDisplayTask personaTask = null;
constraints.gridy++;
constraints.gridx = 1;
Insets savedInsets = constraints.insets;
// Indent in
constraints.insets = new java.awt.Insets(0, LEFT_INDENT, 0, 0);
// create label
javax.swing.JLabel personaLabel = new javax.swing.JLabel();
String personaLabelText = Bundle.CommunicationArtifactViewerHelper_persona_label();
personaLabelText = personaLabelText.concat(CentralRepository.isEnabled()
? Bundle.CommunicationArtifactViewerHelper_persona_searching()
: Bundle.CommunicationArtifactViewerHelper_persona_unknown());
personaLabel.setText(personaLabelText);
// add to panel
gridbagLayout.setConstraints(personaLabel, constraints);
panel.add(personaLabel);
// restore constraint
constraints.insets = savedInsets;
constraints.gridx++;
// Place a button as place holder. It will be enabled when persona is available.
javax.swing.JButton personaButton = new javax.swing.JButton();
personaButton.setText(Bundle.CommunicationArtifactViewerHelper_persona_button_view());
personaButton.setEnabled(false);
gridbagLayout.setConstraints(personaButton, constraints);
panel.add(personaButton);
if (CentralRepository.isEnabled()) {
// kick off a task to find the persona for this account
personaTask = new PersonaSearchAndDisplayTask(panel, new AccountPersonaSearcherData(accountIdentifier, personaLabel, personaButton));
personaTask.execute();
} else {
personaLabel.setEnabled(false);
}
addLineEndGlue(panel, gridbagLayout, constraints);
return Optional.ofNullable(personaTask);
}
/**
* Event handler for mouse click event. Attaches a 'Copy' menu item to right
* click.
*
* @param evt Event to check.
* @param valueLabel Label to attach the menu item to.
*/
@NbBundle.Messages({
"CommunicationArtifactViewerHelper_menuitem_copy=Copy"
})
private static void valueLabelMouseClicked(java.awt.event.MouseEvent evt, JLabel valueLabel) {
if (SwingUtilities.isRightMouseButton(evt)) {
JPopupMenu popup = new JPopupMenu();
JMenuItem copyMenu = new JMenuItem(Bundle.CommunicationArtifactViewerHelper_menuitem_copy()); // NON-NLS
copyMenu.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(valueLabel.getText()), null);
}
});
popup.add(copyMenu);
popup.show(valueLabel, evt.getX(), evt.getY());
}
}
}
@@ -19,30 +19,11 @@
<Container class="javax.swing.JPanel" name="namePanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="0" gridWidth="4" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
<GridBagConstraints gridX="0" gridY="1" gridWidth="5" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
<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="contactNameLabel" min="-2" pref="240" 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="-2" attributes="0"/>
<Component id="contactNameLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="contactNameLabel">
<Properties>
@@ -55,6 +36,11 @@
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="ContactArtifactViewer.contactNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="111" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
@@ -71,14 +57,14 @@
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="1" gridWidth="3" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
<GridBagConstraints gridX="0" gridY="2" gridWidth="3" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Container class="javax.swing.JPanel" name="phoneNumbersPanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="2" gridWidth="4" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
<GridBagConstraints gridX="0" gridY="3" gridWidth="4" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
@@ -97,14 +83,14 @@
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="3" gridWidth="2" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
<GridBagConstraints gridX="0" gridY="4" gridWidth="2" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Container class="javax.swing.JPanel" name="emailsPanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="4" gridWidth="4" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
<GridBagConstraints gridX="0" gridY="5" gridWidth="4" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
@@ -123,14 +109,14 @@
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="5" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
<GridBagConstraints gridX="0" gridY="6" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Container class="javax.swing.JPanel" name="otherAttrsPanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="6" gridWidth="4" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
<GridBagConstraints gridX="0" gridY="7" gridWidth="4" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
@@ -149,7 +135,7 @@
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="7" gridWidth="1" gridHeight="2" fill="3" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.1"/>
<GridBagConstraints gridX="0" gridY="8" gridWidth="1" gridHeight="2" fill="3" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.1"/>
</Constraint>
</Constraints>
</Component>
@@ -175,14 +161,14 @@
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="8" gridWidth="3" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
<GridBagConstraints gridX="0" gridY="9" gridWidth="3" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Container class="javax.swing.JPanel" name="personasPanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="9" gridWidth="4" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
<GridBagConstraints gridX="0" gridY="10" gridWidth="4" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
@@ -201,7 +187,7 @@
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="10" gridWidth="4" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="1.0"/>
<GridBagConstraints gridX="0" gridY="11" gridWidth="4" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="1.0"/>
</Constraint>
</Constraints>
</Component>
@@ -218,7 +204,22 @@
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="4" gridY="0" gridWidth="1" gridHeight="8" fill="1" ipadX="2" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
<GridBagConstraints gridX="4" gridY="3" gridWidth="1" gridHeight="8" fill="1" ipadX="2" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="contactImage">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/defaultContact.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="ContactArtifactViewer.contactImage.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="19" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
@@ -23,6 +23,9 @@ import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -33,6 +36,8 @@ import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.stream.Collectors;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
@@ -42,6 +47,7 @@ import javax.swing.SwingWorker;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import org.sleuthkit.autopsy.centralrepository.datamodel.Persona;
import org.sleuthkit.autopsy.centralrepository.datamodel.PersonaAccount;
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsDialog;
@@ -49,8 +55,10 @@ import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsDialogCallb
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsMode;
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsPanel;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
/**
@@ -75,11 +83,16 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
// account identifier attributes of the Contact artifact.
private final Map<Persona, ArrayList<CentralRepoAccount>> contactUniquePersonasMap = new HashMap<>();
private final static String DEFAULT_IMAGE_PATH = "/org/sleuthkit/autopsy/images/defaultContact.png";
private final ImageIcon defaultImage;
/**
* Creates new form for ContactArtifactViewer
*/
public ContactArtifactViewer() {
initComponents();
defaultImage = new ImageIcon(ContactArtifactViewer.class.getResource(DEFAULT_IMAGE_PATH));
}
/**
@@ -105,41 +118,38 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
personasPanel = new javax.swing.JPanel();
javax.swing.Box.Filler bottomFiller = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767));
javax.swing.Box.Filler rightFiller = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0));
contactImage = new javax.swing.JLabel();
setLayout(new java.awt.GridBagLayout());
namePanel.setLayout(new java.awt.GridBagLayout());
contactNameLabel.setFont(contactNameLabel.getFont().deriveFont((contactNameLabel.getFont().getStyle() | java.awt.Font.ITALIC) | java.awt.Font.BOLD, contactNameLabel.getFont().getSize()+6));
org.openide.awt.Mnemonics.setLocalizedText(contactNameLabel, org.openide.util.NbBundle.getMessage(ContactArtifactViewer.class, "ContactArtifactViewer.contactNameLabel.text")); // NOI18N
javax.swing.GroupLayout namePanelLayout = new javax.swing.GroupLayout(namePanel);
namePanel.setLayout(namePanelLayout);
namePanelLayout.setHorizontalGroup(
namePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(namePanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(contactNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 240, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
namePanelLayout.setVerticalGroup(
namePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(namePanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(contactNameLabel)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridwidth = 4;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.ipadx = 111;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
namePanel.add(contactNameLabel, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.gridwidth = 5;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0);
add(namePanel, gridBagConstraints);
phonesLabel.setFont(phonesLabel.getFont().deriveFont(phonesLabel.getFont().getStyle() | java.awt.Font.BOLD, phonesLabel.getFont().getSize()+2));
org.openide.awt.Mnemonics.setLocalizedText(phonesLabel, org.openide.util.NbBundle.getMessage(ContactArtifactViewer.class, "ContactArtifactViewer.phonesLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.gridy = 2;
gridBagConstraints.gridwidth = 3;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0);
@@ -148,7 +158,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
phoneNumbersPanel.setLayout(new java.awt.GridBagLayout());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.gridy = 3;
gridBagConstraints.gridwidth = 4;
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
@@ -159,7 +169,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
org.openide.awt.Mnemonics.setLocalizedText(emailsLabel, org.openide.util.NbBundle.getMessage(ContactArtifactViewer.class, "ContactArtifactViewer.emailsLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.gridy = 4;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0);
@@ -168,7 +178,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
emailsPanel.setLayout(new java.awt.GridBagLayout());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 4;
gridBagConstraints.gridy = 5;
gridBagConstraints.gridwidth = 4;
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
@@ -179,7 +189,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
org.openide.awt.Mnemonics.setLocalizedText(othersLabel, org.openide.util.NbBundle.getMessage(ContactArtifactViewer.class, "ContactArtifactViewer.othersLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 5;
gridBagConstraints.gridy = 6;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0);
add(othersLabel, gridBagConstraints);
@@ -187,7 +197,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
otherAttrsPanel.setLayout(new java.awt.GridBagLayout());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 6;
gridBagConstraints.gridy = 7;
gridBagConstraints.gridwidth = 4;
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
@@ -195,7 +205,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
add(otherAttrsPanel, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 7;
gridBagConstraints.gridy = 8;
gridBagConstraints.gridheight = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
gridBagConstraints.weighty = 0.1;
@@ -208,7 +218,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
personasLabel.setPreferredSize(new java.awt.Dimension(90, 19));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 8;
gridBagConstraints.gridy = 9;
gridBagConstraints.gridwidth = 3;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0);
@@ -217,7 +227,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
personasPanel.setLayout(new java.awt.GridBagLayout());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 9;
gridBagConstraints.gridy = 10;
gridBagConstraints.gridwidth = 4;
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
@@ -225,19 +235,27 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
add(personasPanel, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 10;
gridBagConstraints.gridy = 11;
gridBagConstraints.gridwidth = 4;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weighty = 1.0;
add(bottomFiller, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 4;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.gridheight = 8;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.ipadx = 2;
gridBagConstraints.weightx = 1.0;
add(rightFiller, gridBagConstraints);
contactImage.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/defaultContact.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(contactImage, org.openide.util.NbBundle.getMessage(ContactArtifactViewer.class, "ContactArtifactViewer.contactImage.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.insets = new java.awt.Insets(6, 19, 0, 0);
add(contactImage, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents
@Override
@@ -291,6 +309,8 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
logger.log(Level.SEVERE, String.format("Error getting Personas for Contact artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex);
}
contactImage.setIcon(getImageFromArtifact(artifact));
// repaint
this.revalidate();
this.repaint();
@@ -333,6 +353,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
contactName = null;
contactUniqueAccountsList.clear();
contactUniquePersonasMap.clear();
contactImage.setIcon(defaultImage);
}
/**
@@ -424,12 +445,17 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
* @throws CentralRepoException
*/
@NbBundle.Messages({
"ContactArtifactViewer_persona_searching= Searching..."
"ContactArtifactViewer_persona_searching= Searching...",
"ContactArtifactViewer_persona_unknown=Unknown"
})
private void initiatePersonasSearch(List<BlackboardAttribute> accountAttributesList) throws CentralRepoException {
personasLabel.setVisible(true);
String personaStatusLabelText = CentralRepository.isEnabled()
? Bundle.ContactArtifactViewer_persona_searching()
: Bundle.ContactArtifactViewer_persona_unknown();
// create a gridbag layout to show each participant on one line
GridBagLayout gridBagLayout = new GridBagLayout();
GridBagConstraints constraints = new GridBagConstraints();
@@ -451,19 +477,27 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
personasPanel.add(personaLabel);
constraints.gridy++;
javax.swing.JLabel primaryPersonaNameLabel = new javax.swing.JLabel();
primaryPersonaNameLabel.setText(Bundle.ContactArtifactViewer_persona_searching());
gridBagLayout.setConstraints(primaryPersonaNameLabel, constraints);
personasPanel.add(primaryPersonaNameLabel);
javax.swing.JLabel personaStatusLabel = new javax.swing.JLabel();
personaStatusLabel.setText(personaStatusLabelText);
gridBagLayout.setConstraints(personaStatusLabel, constraints);
personasPanel.add(personaStatusLabel);
if (CentralRepository.isEnabled() ) {
personasLabel.setEnabled(true);
// Kick off a background task to serach for personas for the contact
ContactPersonaSearcherTask personaSearchTask = new ContactPersonaSearcherTask(accountAttributesList);
personaSearchTask.execute();
} else {
personasLabel.setEnabled(false);
personaLabel.setEnabled(false);
personaStatusLabel.setEnabled(false);
}
personasPanel.setLayout(gridBagLayout);
personasPanel.revalidate();
personasPanel.repaint();
// Kick off a background task to serach for personas for the contact
ContactPersonaSearcherTask personaSearchTask = new ContactPersonaSearcherTask(accountAttributesList);
personaSearchTask.execute();
}
/**
@@ -602,6 +636,49 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
}
}
/**
* Gets an image from a TSK_CONTACT artifact.
*
* @param artifact
*
* @return Image from a TSK_CONTACT artifact or default image if none was
* found or the artifact is not a TSK_CONTACT
*/
private ImageIcon getImageFromArtifact(BlackboardArtifact artifact) {
ImageIcon imageIcon = defaultImage;
if (artifact == null) {
return imageIcon;
}
BlackboardArtifact.ARTIFACT_TYPE artifactType = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
if (artifactType != BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT) {
return imageIcon;
}
try {
for (Content content : artifact.getChildren()) {
if (content instanceof AbstractFile) {
AbstractFile file = (AbstractFile) content;
try {
BufferedImage image = ImageIO.read(new File(file.getLocalAbsPath()));
imageIcon = new ImageIcon(image);
break;
} catch (IOException ex) {
// ImageIO.read will through an IOException if file is not an image
// therefore we don't need to report this exception just try
// the next file.
}
}
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, String.format("Unable to load image for contact: %d", artifact.getId()), ex);
}
return imageIcon;
}
/**
* Thread to search for a personas for all account identifier attributes for
* a contact.
@@ -850,6 +927,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel contactImage;
private javax.swing.JLabel contactNameLabel;
private javax.swing.JLabel emailsLabel;
private javax.swing.JPanel emailsPanel;
@@ -0,0 +1,422 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 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.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.GroupLayout.ParallelGroup;
import javax.swing.GroupLayout.SequentialGroup;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.centralrepository.datamodel.Persona;
import org.sleuthkit.autopsy.centralrepository.datamodel.PersonaAccount;
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsDialog;
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsDialogCallback;
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsMode;
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsPanel;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.CommunicationsManager;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Panel for displaying accounts and their persona information.
*
*/
final class MessageAccountPanel extends JPanel {
private static final long serialVersionUID = 1L;
private final static Logger logger = Logger.getLogger(MessageAccountPanel.class.getName());
private AccountFetcher currentFetcher = null;
/**
* Set the new artifact for the panel.
*
* @param artifact
*
* @throws TskCoreException
*/
void setArtifact(BlackboardArtifact artifact) {
removeAll();
setLayout(null);
repaint();
if (artifact == null) {
return;
}
if (currentFetcher != null && !currentFetcher.isDone()) {
currentFetcher.cancel(true);
}
currentFetcher = new AccountFetcher(artifact);
currentFetcher.execute();
}
/**
* Swingworker that fetches the accounts for a given artifact
*/
class AccountFetcher extends SwingWorker<List<AccountContainer>, Void> {
private final BlackboardArtifact artifact;
/**
* Construct a new AccountFetcher.
*
* @param artifact The artifact to get accounts for.
*/
AccountFetcher(BlackboardArtifact artifact) {
this.artifact = artifact;
}
@Override
protected List<AccountContainer> doInBackground() throws Exception {
List<AccountContainer> dataList = new ArrayList<>();
CommunicationsManager commManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager();
List<Account> accountList = commManager.getAccountsRelatedToArtifact(artifact);
for (Account account : accountList) {
if (isCancelled()) {
return new ArrayList<>();
}
Collection<PersonaAccount> personAccounts = PersonaAccount.getPersonaAccountsForAccount(account);
if (personAccounts != null && !personAccounts.isEmpty()) {
for (PersonaAccount personaAccount : PersonaAccount.getPersonaAccountsForAccount(account)) {
dataList.add(new AccountContainer(account, personaAccount));
}
} else {
dataList.add(new AccountContainer(account, null));
}
}
return dataList;
}
@Override
protected void done() {
try {
List<AccountContainer> dataList = get();
dataList.forEach(container -> {
container.initalizeSwingControls();
});
GroupLayout layout = new GroupLayout(MessageAccountPanel.this);
layout.setHorizontalGroup(
layout.createParallelGroup(Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(getMainHorizontalGroup(layout, dataList))
.addContainerGap(158, Short.MAX_VALUE)));
layout.setVerticalGroup(getMainVerticalGroup(layout, dataList));
setLayout(layout);
repaint();
} catch (CancellationException ex) {
logger.log(Level.INFO, "MessageAccoutPanel thread cancelled", ex);
} catch (InterruptedException | ExecutionException ex) {
logger.log(Level.WARNING, "Failed to get account list for MessageAccountPanel", ex);
}
}
/**
* Create the main horizontal ParalleGroup the encompasses all of the
* controls.
*
* @return A ParallelGroup object
*/
private ParallelGroup getMainHorizontalGroup(GroupLayout layout, List<AccountContainer> data) {
ParallelGroup group = layout.createParallelGroup(Alignment.LEADING);
for (AccountContainer o : data) {
group.addComponent(o.getAccountLabel());
}
group.addGroup(getPersonaHorizontalGroup(layout, data));
return group;
}
/**
* Creates the main Vertical Group for the account controls.
*
* @return The vertical group object
*/
private ParallelGroup getMainVerticalGroup(GroupLayout layout, List<AccountContainer> data) {
SequentialGroup group = layout.createSequentialGroup();
for (AccountContainer o : data) {
group.addGap(5)
.addComponent(o.getAccountLabel())
.addGroup(o.getPersonLineVerticalGroup(layout));
}
group.addContainerGap(83, Short.MAX_VALUE);
return layout.createParallelGroup().addGroup(group);
}
/**
* To line up the Persona buttons they need to be in their own
* ParalletGroup.
*
* @return
*/
private ParallelGroup getButtonGroup(GroupLayout layout, List<AccountContainer> data) {
ParallelGroup group = layout.createParallelGroup(Alignment.LEADING);
for (AccountContainer o : data) {
group.addComponent(o.getButton());
}
return group;
}
/**
* Creates the group with just the persona header and the person value.
*
* @return
*/
private SequentialGroup getPersonaHorizontalGroup(GroupLayout layout, List<AccountContainer> data) {
SequentialGroup group = layout.createSequentialGroup();
ParallelGroup pgroup = layout.createParallelGroup(Alignment.LEADING);
group.addGap(10);
for (AccountContainer o : data) {
pgroup.addGroup(o.getPersonaSequentialGroup(layout));
}
group.addGap(10)
.addGroup(pgroup)
.addPreferredGap(ComponentPlacement.RELATED)
.addGroup(getButtonGroup(layout, data));
return group;
}
}
/**
* Container for each account entry in the panel. This class holds both the
* account objects and the ui components.
*/
private class AccountContainer {
private final Account account;
private Persona persona = null;
private JLabel accountLabel;
private JLabel personaHeader;
private JLabel personaDisplayName;
private JButton button;
/**
* Construct a new AccountContainer
*
* @param account
* @param personaAccount
*/
AccountContainer(Account account, PersonaAccount personaAccount) {
this.account = account;
this.persona = personaAccount != null ? personaAccount.getPersona() : null;
}
@Messages({
"MessageAccountPanel_persona_label=Persona:",
"MessageAccountPanel_unknown_label=Unknown",
"MessageAccountPanel_button_view_label=View",
"MessageAccountPanel_button_create_label=Create"
})
/**
* Swing components will not be initialized until this method is called.
*/
private void initalizeSwingControls() {
accountLabel = new JLabel();
personaHeader = new JLabel(Bundle.MessageAccountPanel_persona_label());
personaDisplayName = new JLabel();
button = new JButton();
button.addActionListener(new PersonaButtonListener(this));
accountLabel.setText(account.getTypeSpecificID());
personaDisplayName.setText(persona != null ? persona.getName() : Bundle.MessageAccountPanel_unknown_label());
button.setText(persona != null ? Bundle.MessageAccountPanel_button_view_label() : Bundle.MessageAccountPanel_button_create_label());
}
/**
* Sets a new persona for this object and update the controls.
*
* @param persona
*/
private void setPersona(Persona persona) {
this.persona = persona;
// Make sure this runs in EDT
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
personaDisplayName.setText(persona != null ? persona.getName() : Bundle.MessageAccountPanel_unknown_label());
button.setText(persona != null ? Bundle.MessageAccountPanel_button_view_label() : Bundle.MessageAccountPanel_button_create_label());
revalidate();
repaint();
}
});
}
/**
* Return the account object for this container.
*
* @return Account object.
*/
private Account getAccount() {
return account;
}
/**
* Returns the PersonaAccount object for this container. Maybe null;
*
* @return PersonaAccount object or null if one was not set.
*/
private Persona getPersona() {
return persona;
}
/**
* Returns the JLabel for that contains the Account type specific id.
*
* @return JLabel object
*/
private JLabel getAccountLabel() {
return accountLabel;
}
/**
* Returns the Persona Buttons for this container.
*
* @return The persona button.
*/
private JButton getButton() {
return button;
}
/**
* Generates the horizontal layout code for the person line.
*
* @param layout Instance of GroupLayout to update.
*
* @return A group for the personal controls.
*/
private SequentialGroup getPersonaSequentialGroup(GroupLayout layout) {
SequentialGroup group = layout.createSequentialGroup();
group
.addComponent(personaHeader)
.addPreferredGap(ComponentPlacement.RELATED)
.addComponent(personaDisplayName);
return group;
}
/**
* Generates the vertical layout code for the persona line.
*
* @param layout Instance of GroupLayout to update.
*
* @return A group for the personal controls.
*/
private ParallelGroup getPersonLineVerticalGroup(GroupLayout layout) {
return layout.createParallelGroup(Alignment.BASELINE)
.addComponent(personaHeader)
.addComponent(personaDisplayName)
.addComponent(button);
}
}
/**
* ActionListner for the persona buttons.
*/
private class PersonaButtonListener implements ActionListener {
private final AccountContainer accountContainer;
/**
* Constructs the listener.
*
* @param accountContainer The account that does with list Listner.
*/
PersonaButtonListener(AccountContainer accountContainer) {
this.accountContainer = accountContainer;
}
@Override
public void actionPerformed(ActionEvent e) {
Persona persona = accountContainer.getPersona();
if (persona == null) {
PersonaDetailsDialog createPersonaDialog = new PersonaDetailsDialog(
MessageAccountPanel.this,
PersonaDetailsMode.CREATE,
null,
new PersonaDialogCallbackImpl(accountContainer),
false);
// Pre populate the persona name and accounts if we have them.
PersonaDetailsPanel personaPanel = createPersonaDialog.getDetailsPanel();
personaPanel.setPersonaName(accountContainer.getAccount().getTypeSpecificID());
// display the dialog now
createPersonaDialog.display();
} else {
new PersonaDetailsDialog(MessageAccountPanel.this,
PersonaDetailsMode.VIEW, persona, new PersonaDialogCallbackImpl(accountContainer));
}
}
}
/**
* Call back for use by the PersonaDetailsDialog.
*/
private class PersonaDialogCallbackImpl implements PersonaDetailsDialogCallback {
private final AccountContainer accountContainer;
PersonaDialogCallbackImpl(AccountContainer accountContainer) {
this.accountContainer = accountContainer;
}
@Override
public void callback(Persona persona) {
accountContainer.setPersona(persona);
}
}
}
@@ -320,6 +320,30 @@
</Component>
<Container class="javax.swing.JScrollPane" name="attachmentsScrollPane">
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
</Container>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="accountsTab">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
<JTabbedPaneConstraints tabName="Accounts">
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageArtifactViewer.accountsTab.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</JTabbedPaneConstraints>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="accountScrollPane">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="Center"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
</Container>
</SubComponents>
@@ -40,6 +40,7 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import org.sleuthkit.autopsy.contentviewers.TranslatablePanel.TranslatablePanelException;
import org.sleuthkit.autopsy.corecomponents.AutoWrappingJTextPane;
import org.sleuthkit.autopsy.corecomponents.DataResultPanel;
@@ -125,6 +126,7 @@ public class MessageArtifactViewer extends javax.swing.JPanel implements Artifac
private static final int HTML_TAB_INDEX = 2;
private static final int RTF_TAB_INDEX = 3;
private static final int ATTM_TAB_INDEX = 4;
private static final int ACCT_TAB_INDEX = 5;
private final List<JTextComponent> textAreas;
private final org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel();
@@ -135,6 +137,13 @@ public class MessageArtifactViewer extends javax.swing.JPanel implements Artifac
private BlackboardArtifact artifact;
private final DataResultPanel drp;
private ExplorerManager drpExplorerManager;
private MessageAccountPanel accountsPanel;
public MessageArtifactViewer(List<JTextComponent> textAreas, DataResultPanel drp) {
this.textAreas = textAreas;
this.drp = drp;
}
/**
* Creates new MessageContentViewer
@@ -142,6 +151,8 @@ public class MessageArtifactViewer extends javax.swing.JPanel implements Artifac
@NbBundle.Messages("MessageArtifactViewer.AttachmentPanel.title=Attachments")
public MessageArtifactViewer() {
initComponents();
accountsPanel = new MessageAccountPanel();
htmlPane.add(htmlPanel);
envelopePanel.setBackground(new Color(0, 0, 0, 38));
drp = DataResultPanel.createInstanceUninitialized(Bundle.MessageArtifactViewer_AttachmentPanel_title(), "", new TableFilterNode(Node.EMPTY, false), 0, null);
@@ -154,6 +165,9 @@ public class MessageArtifactViewer extends javax.swing.JPanel implements Artifac
TEXT_TAB_INDEX);
msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, true);
accountScrollPane.setViewportView(accountsPanel);
msgbodyTabbedPane.setEnabledAt(ACCT_TAB_INDEX, CentralRepository.isEnabled());
/*
* HTML tab uses the HtmlPanel instead of an internal text pane, so we
@@ -205,6 +219,8 @@ public class MessageArtifactViewer extends javax.swing.JPanel implements Artifac
attachmentsPanel = new javax.swing.JPanel();
viewInNewWindowButton = new javax.swing.JButton();
attachmentsScrollPane = new javax.swing.JScrollPane();
accountsTab = new javax.swing.JPanel();
accountScrollPane = new javax.swing.JScrollPane();
envelopePanel.setBackground(new java.awt.Color(204, 204, 204));
@@ -342,6 +358,11 @@ public class MessageArtifactViewer extends javax.swing.JPanel implements Artifac
msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageArtifactViewer.class, "MessageArtifactViewer.attachmentsPanel.TabConstraints.tabTitle"), attachmentsPanel); // NOI18N
accountsTab.setLayout(new java.awt.BorderLayout());
accountsTab.add(accountScrollPane, java.awt.BorderLayout.CENTER);
msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageArtifactViewer.class, "MessageArtifactViewer.accountsTab.TabConstraints.tabTitle"), accountsTab); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
@@ -370,6 +391,8 @@ public class MessageArtifactViewer extends javax.swing.JPanel implements Artifac
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JScrollPane accountScrollPane;
private javax.swing.JPanel accountsTab;
private javax.swing.JPanel attachmentsPanel;
private javax.swing.JScrollPane attachmentsScrollPane;
private javax.swing.JLabel ccLabel;
@@ -421,6 +444,11 @@ public class MessageArtifactViewer extends javax.swing.JPanel implements Artifac
} else {
resetComponent();
}
msgbodyTabbedPane.setEnabledAt(ACCT_TAB_INDEX, CentralRepository.isEnabled());
if(CentralRepository.isEnabled()) {
accountsPanel.setArtifact(artifact);
}
}
/**
@@ -655,7 +683,7 @@ public class MessageArtifactViewer extends javax.swing.JPanel implements Artifac
return doc.html();
}
/**
* Creates child nodes for message attachments.
*/
@@ -0,0 +1,220 @@
/**
* Autopsy Forensic Browser
*
* Copyright 2020 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.awt.Component;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.stream.Collectors;
import javax.swing.JButton;
import javax.swing.SwingWorker;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import org.sleuthkit.autopsy.centralrepository.datamodel.Persona;
import org.sleuthkit.autopsy.centralrepository.datamodel.PersonaAccount;
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsDialog;
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsDialogCallback;
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsMode;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Background task to search for a persona for a given account.
*
* When the search is complete, it updates the UI components
* for the persona appropriately.
*
*/
@NbBundle.Messages({
"# {0} - Persona count",
"PersonaDisplayTask_persona_count_suffix=(1 of {0})"
})
class PersonaSearchAndDisplayTask extends SwingWorker<Collection<Persona>, Void> {
private final static Logger logger = Logger.getLogger(PersonaSearchAndDisplayTask.class.getName());
private final Component parentComponent;
private final AccountPersonaSearcherData personaSearcherData;
PersonaSearchAndDisplayTask(Component parentComponent, AccountPersonaSearcherData personaSearcherData) {
this.parentComponent = parentComponent;
this.personaSearcherData = personaSearcherData;
}
@Override
protected Collection<Persona> doInBackground() throws Exception {
Collection<Persona> personas = new ArrayList<>();
if (CentralRepository.isEnabled()) {
Collection<CentralRepoAccount> accountCandidates
= CentralRepoAccount.getAccountsWithIdentifier(personaSearcherData.getAccountIdentifer());
if (accountCandidates.isEmpty() == false) {
CentralRepoAccount account = accountCandidates.iterator().next();
// get personas for the account
Collection<PersonaAccount> personaAccountsList = PersonaAccount.getPersonaAccountsForAccount(account.getId());
personas = personaAccountsList.stream().map(PersonaAccount::getPersona)
.collect(Collectors.toList());
}
}
return personas;
}
@Override
protected void done() {
Collection<Persona> personas;
try {
personas = super.get();
if (this.isCancelled()) {
return;
}
//Update the Persona label and button based on the search result
String personaLabelText = Bundle.CommunicationArtifactViewerHelper_persona_label();
String personaButtonText;
ActionListener buttonActionListener;
if (personas.isEmpty()) {
// No persona found
personaLabelText += Bundle.CommunicationArtifactViewerHelper_persona_unknown();
// show a 'Create' button
personaButtonText = Bundle.CommunicationArtifactViewerHelper_persona_button_create();
buttonActionListener = new CreatePersonaButtonListener(parentComponent, personaSearcherData);
} else {
Persona persona = personas.iterator().next();
personaLabelText += persona.getName();
if (personas.size() > 1) {
personaLabelText += Bundle.PersonaDisplayTask_persona_count_suffix(Integer.toString(personas.size()));
}
// Show a 'View' button
personaButtonText = Bundle.CommunicationArtifactViewerHelper_persona_button_view();
buttonActionListener = new ViewPersonaButtonListener(parentComponent, persona);
}
personaSearcherData.getPersonaNameLabel().setText(personaLabelText);
personaSearcherData.getPersonaActionButton().setText(personaButtonText);
personaSearcherData.getPersonaActionButton().setEnabled(true);
// set button action
personaSearcherData.getPersonaActionButton().addActionListener(buttonActionListener);
} catch (CancellationException ex) {
logger.log(Level.INFO, "Persona searching was canceled."); //NON-NLS
} catch (InterruptedException ex) {
logger.log(Level.INFO, "Persona searching was interrupted."); //NON-NLS
} catch (ExecutionException ex) {
logger.log(Level.SEVERE, "Fatal error during Persona search.", ex); //NON-NLS
}
}
/**
* Action listener for Create persona button.
*/
private class CreatePersonaButtonListener implements ActionListener {
private final Component parentComponent;
private final AccountPersonaSearcherData personaSearcherData;
CreatePersonaButtonListener(Component parentComponent, AccountPersonaSearcherData personaSearcherData) {
this.parentComponent = parentComponent;
this.personaSearcherData = personaSearcherData;
}
@Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
// Launch the Persona Create dialog
new PersonaDetailsDialog(parentComponent,
PersonaDetailsMode.CREATE, null, new PersonaCreateCallbackImpl(parentComponent, personaSearcherData));
}
}
/**
* Action listener for View persona button.
*/
private class ViewPersonaButtonListener implements ActionListener {
private final Component parentComponent;
private final Persona persona;
ViewPersonaButtonListener(Component parentComponent, Persona persona) {
this.parentComponent = parentComponent;
this.persona = persona;
}
@Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
new PersonaDetailsDialog(parentComponent,
PersonaDetailsMode.VIEW, persona, new PersonaViewCallbackImpl());
}
}
/**
* Callback method for the create mode of the PersonaDetailsDialog
*/
class PersonaCreateCallbackImpl implements PersonaDetailsDialogCallback {
private final Component parentComponent;
private final AccountPersonaSearcherData personaSearcherData;
PersonaCreateCallbackImpl(Component parentComponent, AccountPersonaSearcherData personaSearcherData) {
this.parentComponent = parentComponent;
this.personaSearcherData = personaSearcherData;
}
@Override
public void callback(Persona persona) {
JButton personaButton = personaSearcherData.getPersonaActionButton();
if (persona != null) {
// update the persona name label with newly created persona,
// and change the button to a "View" button
personaSearcherData.getPersonaNameLabel().setText(Bundle.CommunicationArtifactViewerHelper_persona_label() + persona.getName());
personaSearcherData.getPersonaActionButton().setText(Bundle.CommunicationArtifactViewerHelper_persona_button_view());
// replace action listener with a View button listener
for (ActionListener act : personaButton.getActionListeners()) {
personaButton.removeActionListener(act);
}
personaButton.addActionListener(new ViewPersonaButtonListener(parentComponent, persona));
}
personaButton.getParent().revalidate();
}
}
/**
* Callback method for the view mode of the PersonaDetailsDialog
*/
class PersonaViewCallbackImpl implements PersonaDetailsDialogCallback {
@Override
public void callback(Persona persona) {
// nothing to do
}
}
}
@@ -3,7 +3,7 @@
<name unique="discovery"/>
<kind type="editor"/>
<state type="separated"/>
<bounds x="76" y="68" width="1400" height="900"/>
<bounds x="76" y="68" width="1100" height="700"/>
<frame state="0"/>
<empty-behavior permanent="false"/>
@@ -75,6 +75,9 @@
<Component class="javax.swing.JTextArea" name="outputTextArea">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new Font(&quot;Monospaced&quot;, Font.PLAIN, 11)" type="code"/>
</Property>
<Property name="tabSize" type="int" value="0"/>
<Property name="inheritsPopupMenu" type="boolean" value="true"/>
</Properties>
@@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.corecomponents;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
@@ -130,6 +131,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
jScrollPane3.setPreferredSize(new java.awt.Dimension(300, 33));
outputTextArea.setEditable(false);
outputTextArea.setFont(new Font("Monospaced", Font.PLAIN, 11));
outputTextArea.setTabSize(0);
outputTextArea.setInheritsPopupMenu(true);
jScrollPane3.setViewportView(outputTextArea);
@@ -3,6 +3,5 @@ ExtractActionHelper.confDlg.destFileExist.msg=Destination file {0} already exist
ExtractActionHelper.confDlg.destFileExist.title=File Exists
ExtractActionHelper.msgDlg.cantOverwriteFile.msg=Could not overwrite existing file {0}
ExtractActionHelper.notifyDlg.noFileToExtr.msg=No file(s) to extract.
ExtractActionHelper.progress.extracting=Extracting
ExtractActionHelper.progress.cancellingExtraction={0} (Cancelling...)
ExtractActionHelper.done.notifyMsg.fileExtr.text=File(s) extracted.
@@ -4,6 +4,9 @@ ExtractActionHelper.confDlg.destFileExist.title=File Exists
ExtractActionHelper.msgDlg.cantOverwriteFile.msg=Could not overwrite existing file {0}
ExtractActionHelper.noOpenCase.errMsg=No open case available.
ExtractActionHelper.notifyDlg.noFileToExtr.msg=No file(s) to extract.
ExtractActionHelper.progress.extracting=Extracting
ExtractActionHelper.progress.cancellingExtraction={0} (Cancelling...)
ExtractActionHelper.done.notifyMsg.fileExtr.text=File(s) extracted.
# {0} - outputFolderName
ExtractActionHelper.progress.extracting=Extracting to {0}
# {0} - fileName
ExtractActionHelper.progress.fileExtracting=Extracting file: {0}
@@ -35,6 +35,7 @@ import javax.swing.SwingWorker;
import org.netbeans.api.progress.ProgressHandle;
import org.openide.util.Cancellable;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.FileUtil;
@@ -97,7 +98,7 @@ public class ExtractActionHelper {
ArrayList<FileExtractionTask> fileExtractionTasks = new ArrayList<>();
fileExtractionTasks.add(new FileExtractionTask(selectedFile, fileChooser.getSelectedFile()));
runExtractionTasks(event, fileExtractionTasks);
runExtractionTasks(event, fileExtractionTasks, fileChooser.getSelectedFile().getName());
}
}
@@ -147,7 +148,7 @@ public class ExtractActionHelper {
// If there is an attribute name, change the ":". Otherwise the extracted file will be hidden
fileExtractionTasks.add(new FileExtractionTask(source, new File(destinationFolder, source.getId() + "-" + FileUtil.escapeFileName(source.getName()))));
}
runExtractionTasks(event, fileExtractionTasks);
runExtractionTasks(event, fileExtractionTasks, destinationFolder.getName());
}
}
@@ -196,8 +197,10 @@ public class ExtractActionHelper {
* @param event ActionEvent whose source will be used for
* centering popup dialogs.
* @param fileExtractionTasks List of file extraction tasks.
* @param destName Name of the destination used for progress
* messages.
*/
private void runExtractionTasks(ActionEvent event, List<FileExtractionTask> fileExtractionTasks) {
private void runExtractionTasks(ActionEvent event, List<FileExtractionTask> fileExtractionTasks, String destName) {
// verify all of the sources and destinations are OK
for (Iterator<FileExtractionTask> it = fileExtractionTasks.iterator(); it.hasNext();) {
@@ -231,7 +234,7 @@ public class ExtractActionHelper {
// launch a thread to do the work
if (!fileExtractionTasks.isEmpty()) {
try {
FileExtracter extracter = new FileExtracter(fileExtractionTasks);
FileExtracter extracter = new FileExtracter(fileExtractionTasks, destName);
extracter.execute();
} catch (Exception ex) {
logger.log(Level.WARNING, "Unable to start background file extraction thread", ex); //NON-NLS
@@ -268,6 +271,7 @@ public class ExtractActionHelper {
private class FileExtracter extends SwingWorker<Object, Void> {
private final Logger logger = Logger.getLogger(FileExtracter.class.getName());
private final String destName;
private ProgressHandle progress;
private final List<FileExtractionTask> extractionTasks;
@@ -275,19 +279,28 @@ public class ExtractActionHelper {
* Create an instance of the FileExtracter.
*
* @param extractionTasks List of file extraction tasks.
* @param destName Name of the destination used for progress
* messages.
*/
FileExtracter(List<FileExtractionTask> extractionTasks) {
FileExtracter(List<FileExtractionTask> extractionTasks, String destName) {
this.extractionTasks = extractionTasks;
this.destName = destName;
}
@Override
@Messages({
"# {0} - outputFolderName",
"ExtractActionHelper.progress.extracting=Extracting to {0}",
"# {0} - fileName",
"ExtractActionHelper.progress.fileExtracting=Extracting file: {0}"
})
protected Object doInBackground() throws Exception {
if (extractionTasks.isEmpty()) {
return null;
}
// Setup progress bar.
final String displayName = NbBundle.getMessage(this.getClass(), "ExtractActionHelper.progress.extracting");
final String displayName = Bundle.ExtractActionHelper_progress_extracting(destName);
progress = ProgressHandle.createHandle(displayName, new Cancellable() {
@Override
public boolean cancel() {
@@ -301,15 +314,10 @@ public class ExtractActionHelper {
progress.start();
progress.switchToIndeterminate();
/*
* @@@ Add back in -> Causes exceptions int workUnits = 0; for
* (FileExtractionTask task : extractionTasks) { workUnits +=
* calculateProgressBarWorkUnits(task.source); }
* progress.switchToDeterminate(workUnits);
*/
// Do the extraction tasks.
for (FileExtractionTask task : this.extractionTasks) {
// @@@ Note, we are no longer passing in progress
progress.progress(Bundle.ExtractActionHelper_progress_fileExtracting(task.destination.getName()));
ContentUtils.ExtractFscContentVisitor.extract(task.source, task.destination, null, this);
}
@@ -0,0 +1,126 @@
/*
* Autopsy
*
* Copyright 2020 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.discovery;
import java.awt.event.ActionListener;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.event.ListSelectionListener;
/**
* Abstract class extending JPanel for filter controls.
*/
abstract class AbstractDiscoveryFilterPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
/**
* Setup the file filter settings.
*
* @param selected Boolean indicating if the filter should be
* selected.
* @param indicesSelected Array of integers indicating which list items are
* selected, null to indicate leaving selected items
* unchanged or that there are no items to select.
*/
abstract void configurePanel(boolean selected, int[] indicesSelected);
/**
* Get the checkbox which enables and disables this filter.
*
* @return The JCheckBox which enables and disables this filter.
*/
abstract JCheckBox getCheckbox();
/**
* Get the list of values associated with this filter if one exists. If one
* does not exist this should return null.
*
* @return The JList which contains the values available for selection for
* this filter.
*/
abstract JList<?> getList();
/**
* Get any additional text that should be displayed under the checkbox. If
* no text should be displayed this should return null.
*
* @return The JLabel to display under the JCheckBox.
*/
abstract JLabel getAdditionalLabel();
/**
* Check if this filter is configured to valid settings.
*
* @return If the settings are invalid returns the error that has occurred, otherwise returns empty string.
*/
abstract String checkForError();
/**
* Add listeners to the checkbox/list set if listeners have not already been
* added.
*
* @param actionlistener The listener for the checkbox selection events.
* @param listListener The listener for the list selection events.
*/
void addListeners(ActionListener actionListener, ListSelectionListener listListener) {
if (getCheckbox() != null) {
getCheckbox().addActionListener(actionListener);
}
if (getList() != null) {
getList().addListSelectionListener(listListener);
}
}
/**
* Get the FileFilter which is represented by this Panel.
*
* @return The FileFilter for the selected settings, null if the settings
* are not in use.
*/
abstract FileSearchFiltering.FileFilter getFilter();
/**
* Remove listeners from the checkbox and the list if they exist.
*/
void removeListeners() {
if (getCheckbox() != null) {
for (ActionListener listener : getCheckbox().getActionListeners()) {
getCheckbox().removeActionListener(listener);
}
}
if (getList() != null) {
for (ListSelectionListener listener : getList().getListSelectionListeners()) {
getList().removeListSelectionListener(listener);
}
}
}
/**
* Return whether or not this filter has a panel.
*
* @return True if there is a panel to display associated with this filter,
* return false if the filter only has a checkbox.
*/
boolean hasPanel() {
return true;
}
}
@@ -0,0 +1,268 @@
/*
* Autopsy
*
* Copyright 2020 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.discovery;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.apache.commons.lang3.StringUtils;
/**
* Abstract class extending JPanel for displaying all the filters associated
* with a type.
*/
abstract class AbstractFiltersPanel extends JPanel implements ActionListener, ListSelectionListener {
private boolean isInitialized = false;
private static final double LABEL_WEIGHT = 0;
private static final double PANEL_WEIGHT = .1;
private static final int LABEL_WIDTH = 1;
private static final int PANEL_WIDTH = 2;
private static final int LABEL_HEIGHT = 1;
private static final int PANEL_HEIGHT = 2;
private static final long serialVersionUID = 1L;
private final GridBagConstraints constraints = new GridBagConstraints();
private final List<AbstractDiscoveryFilterPanel> filters = new ArrayList<>();
private final JPanel firstColumnPanel = new JPanel();
private final JPanel secondColumnPanel = new JPanel();
private int firstColumnY = 0;
private int secondColumnY = 0;
/**
* Setup necessary for implementations of this abstract class.
*/
AbstractFiltersPanel() {
firstColumnPanel.setLayout(new GridBagLayout());
secondColumnPanel.setLayout(new GridBagLayout());
}
/**
* Get the type of results this filters panel is for.
*
* @return The type of results this panel filters.
*/
abstract FileSearchData.FileType getFileType();
/**
* Add a DiscoveryFilterPanel to the specified column with the specified
* settings.
*
* @param filterPanel The DiscoveryFilterPanel to add to this panel.
* @param isSelected True if the checkbox should be selected, false
* otherwise.
* @param indicesSelected The array of indices that are selected in the
* list, null if none are selected.
* @param column The column to add the DiscoveryFilterPanel to.
*/
final synchronized void addFilter(AbstractDiscoveryFilterPanel filterPanel, boolean isSelected, int[] indicesSelected, int column) {
if (!isInitialized) {
constraints.gridy = 0;
constraints.anchor = GridBagConstraints.FIRST_LINE_START;
constraints.insets = new Insets(8, 8, 8, 8);
isInitialized = true;
}
if (column == 0) {
constraints.gridy = firstColumnY;
} else {
constraints.gridy = secondColumnY;
}
constraints.gridx = 0;
filterPanel.configurePanel(isSelected, indicesSelected);
filterPanel.addListeners(this, this);
filters.add(filterPanel);
constraints.fill = GridBagConstraints.VERTICAL;
constraints.gridheight = LABEL_HEIGHT;
constraints.gridwidth = LABEL_WIDTH;
constraints.weightx = LABEL_WEIGHT;
constraints.weighty = LABEL_WEIGHT;
constraints.gridwidth = LABEL_WIDTH;
addToGridBagLayout(filterPanel.getCheckbox(), null, column);
if (filterPanel.hasPanel()) {
constraints.gridx += constraints.gridwidth;
constraints.fill = GridBagConstraints.BOTH;
constraints.gridheight = PANEL_HEIGHT;
constraints.weightx = PANEL_WEIGHT;
constraints.weighty = PANEL_WEIGHT;
constraints.gridwidth = PANEL_WIDTH;
addToGridBagLayout(filterPanel, null, column);
}
if (column == 0) {
firstColumnY += constraints.gridheight;
} else {
secondColumnY += constraints.gridheight;
}
}
/**
* Add the panels representing the two columns to the specified JSplitPane.
*
* @param splitPane The JSplitPane which the columns are added to.
*/
final void addPanelsToScrollPane(JSplitPane splitPane) {
splitPane.setLeftComponent(firstColumnPanel);
splitPane.setRightComponent(secondColumnPanel);
validate();
repaint();
}
/**
* Clear the filters from the panel
*/
final synchronized void clearFilters() {
for (AbstractDiscoveryFilterPanel filterPanel : filters) {
filterPanel.removeListeners();
}
filters.clear();
}
/**
* Update the constraints and add a component to one of the columns.
*
* @param componentToAdd The Component to add to the specified
* column.
* @param additionalComponentToAdd An additional Component which may appear
* below the componentToAdd in the specified
* column.
* @param columnIndex The column to add the Component to.
*/
private void addToGridBagLayout(Component componentToAdd, Component additionalComponentToAdd, int columnIndex) {
addToColumn(componentToAdd, columnIndex);
if (additionalComponentToAdd != null) {
constraints.gridy += constraints.gridheight;
addToColumn(additionalComponentToAdd, columnIndex);
constraints.gridy -= constraints.gridheight;
}
}
/**
* Add the Component to the specified column with the current constraints.
*
* @param component The Component to add.
* @param columnNumber The column to add the Component to.
*/
private void addToColumn(Component component, int columnNumber) {
if (columnNumber == 0) {
firstColumnPanel.add(component, constraints);
} else {
secondColumnPanel.add(component, constraints);
}
}
/**
* Check if the fields are valid, and fire a property change event to
* indicate any errors.
*/
synchronized void validateFields() {
String errorString = null;
for (AbstractDiscoveryFilterPanel filterPanel : filters) {
errorString = filterPanel.checkForError();
if (!StringUtils.isBlank(errorString)) {
break;
}
}
firePropertyChange("FilterError", null, errorString);
}
@Override
public void actionPerformed(ActionEvent e) {
validateFields();
validate();
repaint();
}
/**
* Is the Objects Detected Filter Supported.
*
* @return True if the ObjectsDetectedFilter is supported, false otherwise.
*/
boolean isObjectsFilterSupported() {
for (AbstractDiscoveryFilterPanel filter : filters) {
if (filter instanceof ObjectDetectedFilterPanel) {
return filter.getList().getModel().getSize() > 0;
}
}
return false;
}
/**
* Is the Hash Set Filter Supported.
*
* @return True if the HashSetFilter is supported, false otherwise.
*/
boolean isHashSetFilterSupported() {
for (AbstractDiscoveryFilterPanel filter : filters) {
if (filter instanceof HashSetFilterPanel) {
return filter.getList().getModel().getSize() > 0;
}
}
return false;
}
/**
* Is the Interesting Items Filter Supported.
*
* @return True if the InterestingItemsFilter is supported, false otherwise.
*/
boolean isInterestingItemsFilterSupported() {
for (AbstractDiscoveryFilterPanel filter : filters) {
if (filter instanceof InterestingItemsFilterPanel) {
return filter.getList().getModel().getSize() > 0;
}
}
return false;
}
/**
* Get a list of all filters selected by the user.
*
* @return The list of filters selected by the user.
*/
synchronized List<FileSearchFiltering.FileFilter> getFilters() {
List<FileSearchFiltering.FileFilter> filtersToUse = new ArrayList<>();
filtersToUse.add(new FileSearchFiltering.FileTypeFilter(getFileType()));
for (AbstractDiscoveryFilterPanel filterPanel : filters) {
if (filterPanel.getCheckbox().isSelected()) {
FileSearchFiltering.FileFilter filter = filterPanel.getFilter();
if (filter != null) {
filtersToUse.add(filter);
}
}
}
return filtersToUse;
}
@Override
public void valueChanged(ListSelectionEvent evt) {
if (!evt.getValueIsAdjusting()) {
validateFields();
validate();
repaint();
}
}
}
@@ -16,7 +16,6 @@ FileSearchDialog.orderSizeRadioButton.text=Group Size
FileSearchDialog.jLabel5.text=Order files by:
FileSearchDialog.parentCheckBox.text=Parent
FileSearchPanel.sortingPanel.border.title=Grouping
FileSearchPanel.searchButton.text=Show
FileSearchPanel.addButton.text=Add
FileSearchPanel.substringRadioButton.text=Substring
FileSearchPanel.fullRadioButton.text=Full
@@ -39,7 +38,6 @@ FileSearchDialog.objCheckBox.text=Objects
FileSearchDialog.exifCheckBox.text=Must contain EXIF data
FileSearchDialog.notableCheckBox.text=Must have been tagged as notable
FileSearchDialog.scoreCheckBox.text=Has score
FileSearchPanel.cancelButton.text=Cancel
FileSearchPanel.hashSetCheckbox.text=Hash Set:
FileSearchPanel.tagsCheckbox.text=Tag:
FileSearchPanel.interestingItemsCheckbox.text=Interesting Item:
@@ -50,20 +48,56 @@ ResultsPanel.currentPageLabel.text=Page: -
ResultsPanel.pageControlsLabel.text=Pages:
ResultsPanel.gotoPageLabel.text=Go to Page:
ResultsPanel.pageSizeLabel.text=Page Size:
ResultsPanel.instancesList.border.title=Instances
DiscoveryExtractAction.title.extractFiles.text=Extract File
FileSearchPanel.includeRadioButton.text=Include
FileSearchPanel.excludeRadioButton.text=Exclude
FileSearchPanel.knownFilesCheckbox.toolTipText=
FileSearchPanel.knownFilesCheckbox.text=Hide known files
GroupListPanel.groupKeyList.border.title=Groups
DiscoveryTopComponent.imagesButton.text=Images
DiscoveryTopComponent.videosButton.text=Videos
ResultsPanel.resultsSplitPane.toolTipText=
FileSearchPanel.stepThreeLabel.text=Step 3: Choose display settings
DiscoveryTopComponent.stepOneLabel.text=Step 1: Pick File Type
DiscoveryTopComponent.documentsButton.text=Documents
DocumentPanel.fileSizeLabel.toolTipText=
DocumentPanel.isDeletedLabel.toolTipText=
ImageThumbnailPanel.isDeletedLabel.toolTipText=
FileSearchPanel.userCreatedCheckbox.text=Possibly User Created
DiscoveryDialog.documentsButton.text=Documents
DiscoveryDialog.videosButton.text=Videos
DiscoveryDialog.imagesButton.text=Images
DiscoveryDialog.searchButton.text=Search
DetailsPanel.instancesList.border.title=Instances
SizeFilterPanel.sizeCheckbox.text=File Size:
DataSourceFilterPanel.dataSourceCheckbox.text=Data Source:
UserCreatedFilterPanel.userCreatedCheckbox.text=Possibly User Created
# To change this license header, choose License Headers in Project Properties.
# To change this template file, choose Tools | Templates
# and open the template in the editor.
HashSetFilterPanel.hashSetCheckbox.text=Hash Set:
InterestingItemFilterPanel.interestingItemsCheckbox.text=Interesting Item:
ParentFolderFilterPanel.parentCheckbox.text=Parent Folder:
ParentFolderFilterPanel.deleteButton.text=Delete
ParentFolderFilterPanel.excludeRadioButton.text=Exclude
ParentFolderFilterPanel.includeRadioButton.text=Include
ParentFolderFilterPanel.substringRadioButton.text=Substring
ParentFolderFilterPanel.fullRadioButton.text=Full
ParentFolderFilterPanel.parentLabel.text=(All will be used)
ParentFolderFilterPanel.addButton.text=Add
ParentFolderFilterPanel.parentCheckbox.text_1=Parent Folder:
ParentFolderFilterPanel.addButton.text_1=Add
ParentFolderFilterPanel.deleteButton.text_1=Delete
ParentFolderFilterPanel.excludeRadioButton.text_1=Exclude
ParentFolderFilterPanel.substringRadioButton.text_1=Substring
ParentFolderFilterPanel.includeRadioButton.text_1=Include
ParentFolderFilterPanel.fullRadioButton.text_1=Full
ParentFolderFilterPanel.parentLabel.text_1=(All will be used)
InterestingItemsFilterPanel.interestingItemsCheckbox.text=Interesting Item:
UserCreatedFilterPanel.userCreatedCheckbox.text_1=Possibly User Created
PastOccurrencesFilterPanel.pastOccurrencesCheckbox.text=Past Occurrences:
ObjectDetectedFilterPanel.text=Object Detected:
DiscoveryDialog.sortingPanel.border.title=Step 3: Choose display settings
DiscoveryDialog.groupByLabel.text=Group By:
DiscoveryDialog.orderByLabel.text=Order Within Groups By:
DiscoveryDialog.orderGroupsByLabel.text=Order Groups By:
ImageFilterPanel.imageFiltersSplitPane.toolTipText=
DocumentFilterPanel.documentsFiltersSplitPane.border.title=Step 2: Filter which documents to show
ImageFilterPanel.imageFiltersSplitPane.border.title=Step 2: Filter which images to show
VideoFilterPanel.videoFiltersSplitPane.border.title=Step 2: Filter which videos to show
DiscoveryDialog.step1Label.text=Step 1: Choose result type
@@ -1,11 +1,19 @@
CTL_OpenFileDiscoveryAction=File Discovery
CTL_OpenDiscoveryAction=Discovery
# {0} - dataSourceName
DataSourceModuleWrapper.exifModule.text=Exif Parser module was not run on data source: {0}\n
# {0} - dataSourceName
DataSourceModuleWrapper.fileTypeModule.text=File Type Identification module was not run on data source: {0}\n
# {0} - dataSourceName
DataSourceModuleWrapper.hashModule.text=Hash Lookup module was not run on data source: {0}\n
DiscoveryTopComponent.name=\ File Discovery
DiscoveryDialog.name.text=Discovery
DiscoveryTopComponent.cancelButton.text=Cancel Search
DiscoveryTopComponent.name=\ Discovery
DiscoveryTopComponent.newSearch.text=New Search
DiscoveryTopComponent.searchCancelled.text=Search has been cancelled.
# {0} - search
DiscoveryTopComponent.searchComplete.text=Results for {0}
# {0} - searchType
DiscoveryTopComponent.searchInProgress.text=Performing search for results of type {0}. Please wait.
DiscoveryUiUtility.bytes.text=bytes
DiscoveryUiUtility.gigaBytes.text=GB
DiscoveryUiUtility.kiloBytes.text=KB
@@ -137,13 +145,8 @@ FileSearchFiltering.SizeFilter.range=({0} to {1})
FileSearchFiltering.TagsFilter.desc=Files that have been tagged {0}
FileSearchFiltering.TagsFilter.or=\ or
FileSearchFiltering.UserCreatedFilter.desc=Files that contain EXIF data
FileSearchPanel.dialogTitle.text=Test file search
FileSearchPanel.sortingPanel.border.title=Grouping
FileSearchPanel.searchButton.text=Show
FileSearchPanel.addButton.text=Add
FileSearchPanel.steptwo.documents=Step 2: Filter which documents to show
FileSearchPanel.steptwo.images=Step 2: Filter which images to show
FileSearchPanel.steptwo.videos=Step 2: Filter which videos to show
FileSearchPanel.substringRadioButton.text=Substring
FileSearchPanel.fullRadioButton.text=Full
FileSearchPanel.parentCheckbox.text=Parent Folder:
@@ -165,7 +168,6 @@ FileSearchDialog.objCheckBox.text=Objects
FileSearchDialog.exifCheckBox.text=Must contain EXIF data
FileSearchDialog.notableCheckBox.text=Must have been tagged as notable
FileSearchDialog.scoreCheckBox.text=Has score
FileSearchPanel.cancelButton.text=Cancel
FileSearchPanel.hashSetCheckbox.text=Hash Set:
FileSearchPanel.tagsCheckbox.text=Tag:
FileSearchPanel.interestingItemsCheckbox.text=Interesting Item:
@@ -184,7 +186,7 @@ GroupsListPanel.noResults.title.text=No results found
ImageThumbnailPanel.isDeleted.text=All instances of file are deleted.
# {0} - otherInstanceCount
ImageThumbnailPanel.nameLabel.more.text=\ and {0} more
OpenFileDiscoveryAction.resultsIncomplete.text=Results may be incomplete
OpenDiscoveryAction.resultsIncomplete.text=Results may be incomplete
ResultFile.score.interestingResult.description=At least one instance of the file has an interesting result associated with it.
ResultFile.score.notableFile.description=At least one instance of the file was recognized as notable.
ResultFile.score.notableTaggedFile.description=At least one instance of the file is tagged with a notable tag.
@@ -202,25 +204,61 @@ ResultsPanel.openInExternalViewer.name=Open in External Viewer
ResultsPanel.pageControlsLabel.text=Pages:
ResultsPanel.gotoPageLabel.text=Go to Page:
ResultsPanel.pageSizeLabel.text=Page Size:
ResultsPanel.instancesList.border.title=Instances
DiscoveryExtractAction.title.extractFiles.text=Extract File
FileSearchPanel.includeRadioButton.text=Include
FileSearchPanel.excludeRadioButton.text=Exclude
FileSearchPanel.knownFilesCheckbox.toolTipText=
FileSearchPanel.knownFilesCheckbox.text=Hide known files
GroupListPanel.groupKeyList.border.title=Groups
DiscoveryTopComponent.imagesButton.text=Images
DiscoveryTopComponent.videosButton.text=Videos
ResultsPanel.resultsSplitPane.toolTipText=
FileSearchPanel.stepThreeLabel.text=Step 3: Choose display settings
DiscoveryTopComponent.stepOneLabel.text=Step 1: Pick File Type
DiscoveryTopComponent.documentsButton.text=Documents
DocumentPanel.fileSizeLabel.toolTipText=
DocumentPanel.isDeletedLabel.toolTipText=
ImageThumbnailPanel.isDeletedLabel.toolTipText=
FileSearchPanel.userCreatedCheckbox.text=Possibly User Created
DiscoveryDialog.documentsButton.text=Documents
DiscoveryDialog.videosButton.text=Videos
DiscoveryDialog.imagesButton.text=Images
DiscoveryDialog.searchButton.text=Search
DetailsPanel.instancesList.border.title=Instances
ResultsPanel.unableToCreate.text=Unable to create summary.
ResultsPanel.viewFileInDir.name=View File in Directory
SizeFilterPanel.sizeCheckbox.text=File Size:
DataSourceFilterPanel.dataSourceCheckbox.text=Data Source:
UserCreatedFilterPanel.userCreatedCheckbox.text=Possibly User Created
# To change this license header, choose License Headers in Project Properties.
# To change this template file, choose Tools | Templates
# and open the template in the editor.
HashSetFilterPanel.hashSetCheckbox.text=Hash Set:
InterestingItemFilterPanel.interestingItemsCheckbox.text=Interesting Item:
ParentFolderFilterPanel.parentCheckbox.text=Parent Folder:
ParentFolderFilterPanel.deleteButton.text=Delete
ParentFolderFilterPanel.excludeRadioButton.text=Exclude
ParentFolderFilterPanel.includeRadioButton.text=Include
ParentFolderFilterPanel.substringRadioButton.text=Substring
ParentFolderFilterPanel.fullRadioButton.text=Full
ParentFolderFilterPanel.parentLabel.text=(All will be used)
ParentFolderFilterPanel.addButton.text=Add
ParentFolderFilterPanel.parentCheckbox.text_1=Parent Folder:
ParentFolderFilterPanel.addButton.text_1=Add
ParentFolderFilterPanel.deleteButton.text_1=Delete
ParentFolderFilterPanel.excludeRadioButton.text_1=Exclude
ParentFolderFilterPanel.substringRadioButton.text_1=Substring
ParentFolderFilterPanel.includeRadioButton.text_1=Include
ParentFolderFilterPanel.fullRadioButton.text_1=Full
ParentFolderFilterPanel.parentLabel.text_1=(All will be used)
InterestingItemsFilterPanel.interestingItemsCheckbox.text=Interesting Item:
UserCreatedFilterPanel.userCreatedCheckbox.text_1=Possibly User Created
PastOccurrencesFilterPanel.pastOccurrencesCheckbox.text=Past Occurrences:
ObjectDetectedFilterPanel.text=Object Detected:
DiscoveryDialog.sortingPanel.border.title=Step 3: Choose display settings
DiscoveryDialog.groupByLabel.text=Group By:
DiscoveryDialog.orderByLabel.text=Order Within Groups By:
DiscoveryDialog.orderGroupsByLabel.text=Order Groups By:
ImageFilterPanel.imageFiltersSplitPane.toolTipText=
DocumentFilterPanel.documentsFiltersSplitPane.border.title=Step 2: Filter which documents to show
ImageFilterPanel.imageFiltersSplitPane.border.title=Step 2: Filter which images to show
VideoFilterPanel.videoFiltersSplitPane.border.title=Step 2: Filter which videos to show
DiscoveryDialog.step1Label.text=Step 1: Choose result type
VideoThumbnailPanel.bytes.text=bytes
VideoThumbnailPanel.deleted.text=All instances of file are deleted.
VideoThumbnailPanel.gigaBytes.text=GB
@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<NonVisualComponents>
<Component class="javax.swing.JCheckBox" name="dataSourceCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="DataSourceFilterPanel.dataSourceCheckbox.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="[150, 25]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[150, 25]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[150, 25]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="dataSourceCheckboxActionPerformed"/>
</Events>
</Component>
</NonVisualComponents>
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[250, 30]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[250, 30]"/>
</Property>
<Property name="requestFocusEnabled" type="boolean" value="false"/>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="dataSourceScrollPane" alignment="0" pref="300" 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="dataSourceScrollPane" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="dataSourceScrollPane">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[27, 27]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="dataSourceList">
<Properties>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new DefaultListModel&lt;DataSourceItem&gt;()" type="code"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="visibleRowCount" type="int" value="5"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;DataSourceItem&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>
@@ -0,0 +1,204 @@
/*
* Autopsy
*
* Copyright 2020 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.discovery;
import java.util.List;
import java.util.logging.Level;
import java.util.stream.Collectors;
import javax.swing.DefaultListModel;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JList;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.TskCoreException;
/**
* A panel which displays the controls for the Data Source Filter.
*/
final class DataSourceFilterPanel extends AbstractDiscoveryFilterPanel {
private static final long serialVersionUID = 1L;
private final static Logger logger = Logger.getLogger(DataSourceFilterPanel.class.getName());
/**
* Creates new form DataSourceFilterPanel.
*/
DataSourceFilterPanel() {
initComponents();
setUpDataSourceFilter();
}
/**
* 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() {
dataSourceCheckbox = new javax.swing.JCheckBox();
dataSourceScrollPane = new javax.swing.JScrollPane();
dataSourceList = new javax.swing.JList<>();
org.openide.awt.Mnemonics.setLocalizedText(dataSourceCheckbox, org.openide.util.NbBundle.getMessage(DataSourceFilterPanel.class, "DataSourceFilterPanel.dataSourceCheckbox.text")); // NOI18N
dataSourceCheckbox.setMaximumSize(new java.awt.Dimension(150, 25));
dataSourceCheckbox.setMinimumSize(new java.awt.Dimension(150, 25));
dataSourceCheckbox.setPreferredSize(new java.awt.Dimension(150, 25));
dataSourceCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
dataSourceCheckboxActionPerformed(evt);
}
});
setMinimumSize(new java.awt.Dimension(250, 30));
setPreferredSize(new java.awt.Dimension(250, 30));
setRequestFocusEnabled(false);
dataSourceScrollPane.setPreferredSize(new java.awt.Dimension(27, 27));
dataSourceList.setModel(new DefaultListModel<DataSourceItem>());
dataSourceList.setEnabled(false);
dataSourceList.setVisibleRowCount(5);
dataSourceScrollPane.setViewportView(dataSourceList);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(dataSourceScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(dataSourceScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGap(0, 0, 0))
);
}// </editor-fold>//GEN-END:initComponents
private void dataSourceCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dataSourceCheckboxActionPerformed
dataSourceList.setEnabled(dataSourceCheckbox.isSelected());
}//GEN-LAST:event_dataSourceCheckboxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JCheckBox dataSourceCheckbox;
private javax.swing.JList<DataSourceItem> dataSourceList;
private javax.swing.JScrollPane dataSourceScrollPane;
// End of variables declaration//GEN-END:variables
@Override
void configurePanel(boolean selected, int[] indicesSelected) {
dataSourceCheckbox.setSelected(selected);
if (dataSourceCheckbox.isEnabled() && dataSourceCheckbox.isSelected()) {
dataSourceScrollPane.setEnabled(true);
dataSourceList.setEnabled(true);
if (indicesSelected != null) {
dataSourceList.setSelectedIndices(indicesSelected);
}
} else {
dataSourceScrollPane.setEnabled(false);
dataSourceList.setEnabled(false);
}
}
@Override
JCheckBox getCheckbox() {
return dataSourceCheckbox;
}
@Override
JLabel getAdditionalLabel() {
return null;
}
/**
* Initialize the data source filter.
*/
private void setUpDataSourceFilter() {
int count = 0;
try {
DefaultListModel<DataSourceItem> dsListModel = (DefaultListModel<DataSourceItem>) dataSourceList.getModel();
dsListModel.removeAllElements();
for (DataSource ds : Case.getCurrentCase().getSleuthkitCase().getDataSources()) {
dsListModel.add(count, new DataSourceItem(ds));
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error loading data sources", ex);
dataSourceCheckbox.setEnabled(false);
dataSourceList.setEnabled(false);
}
}
@Override
JList<?> getList() {
return dataSourceList;
}
/**
* Utility class to allow us to display the data source ID along with the
* name
*/
private class DataSourceItem {
private final DataSource ds;
/**
* Construct a new DataSourceItem.
*
* @param ds The data source being wrapped.
*/
DataSourceItem(DataSource ds) {
this.ds = ds;
}
/**
* Get the data source represented by this data source item.
*
* @return The data source represented by this data source item.
*/
DataSource getDataSource() {
return ds;
}
@Override
public String toString() {
return ds.getName() + " (ID: " + ds.getId() + ")";
}
}
@Override
String checkForError() {
if (dataSourceCheckbox.isSelected() && dataSourceList.getSelectedValuesList().isEmpty()) {
return "At least one size must be selected";
}
return "";
}
@Override
FileSearchFiltering.FileFilter getFilter() {
if (dataSourceCheckbox.isSelected()) {
List<DataSource> dataSources = dataSourceList.getSelectedValuesList().stream().map(t -> t.getDataSource()).collect(Collectors.toList());
return new FileSearchFiltering.DataSourceFilter(dataSources);
}
return null;
}
}
@@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.modules.exif.ExifParserModuleFactory;
@@ -0,0 +1,133 @@
<?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">
<EmptySpace min="0" pref="777" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Component id="detailsSplitPane" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="402" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Component id="detailsSplitPane" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JSplitPane" name="detailsSplitPane">
<Properties>
<Property name="dividerLocation" type="int" value="80"/>
<Property name="orientation" type="int" value="0"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[200, 0]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[700, 500]"/>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="instancesPanel">
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 60]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[700, 80]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
<JSplitPaneConstraints position="top"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="775" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Component id="instancesScrollPane" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="79" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Component id="instancesScrollPane" pref="79" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="instancesScrollPane">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[775, 60]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="instancesList">
<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="Instances">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="DetailsPanel.instancesList.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="instancesListModel" type="code"/>
</Property>
<Property name="selectionMode" type="int" value="0"/>
<Property name="cellRenderer" type="javax.swing.ListCellRenderer" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new InstancesCellRenderer()" type="code"/>
</Property>
<Property name="visibleRowCount" type="int" value="2"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;AbstractFile&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>
@@ -0,0 +1,261 @@
/*
* Autopsy
*
* Copyright 2020 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.discovery;
import com.google.common.eventbus.Subscribe;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
import org.sleuthkit.autopsy.corecomponents.DataContentPanel;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
import org.sleuthkit.autopsy.modules.hashdatabase.AddContentToHashDbAction;
import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Panel to display the details of the selected result.
*/
final class DetailsPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private final DataContentPanel dataContentPanel;
private final DefaultListModel<AbstractFile> instancesListModel = new DefaultListModel<>();
private final ListSelectionListener listener;
/**
* Creates new form DetailsPanel.
*/
DetailsPanel() {
initComponents();
dataContentPanel = DataContentPanel.createInstance();
detailsSplitPane.setBottomComponent(dataContentPanel);
//Add the context menu when right clicking
instancesList.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
SwingUtilities.invokeLater(() -> {
instancesList.setSelectedIndex(instancesList.locationToIndex(e.getPoint()));
Set<AbstractFile> files = new HashSet<>();
files.add(instancesList.getSelectedValue());
JPopupMenu menu = new JPopupMenu();
menu.add(new ViewContextAction(Bundle.ResultsPanel_viewFileInDir_name(), instancesList.getSelectedValue()));
menu.add(new ExternalViewerAction(Bundle.ResultsPanel_openInExternalViewer_name(), new FileNode(instancesList.getSelectedValue())));
menu.add(ViewFileInTimelineAction.createViewFileAction(instancesList.getSelectedValue()));
menu.add(new DiscoveryExtractAction(files));
menu.add(AddContentTagAction.getInstance().getMenuForContent(files));
menu.add(DeleteFileContentTagAction.getInstance().getMenuForFiles(files));
menu.add(AddContentToHashDbAction.getInstance().getMenuForFiles(files));
menu.show(instancesList, e.getPoint().x, e.getPoint().y);
});
}
}
});
listener = new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
SwingUtilities.invokeLater(() -> {
AbstractFile file = getSelectedFile();
if (file != null) {
dataContentPanel.setNode(new TableFilterNode(new FileNode(file), false));
} else {
dataContentPanel.setNode(null);
}
});
}
}
};
instancesList.addListSelectionListener(listener);
}
/**
* Clears the instances list in response to the clear instance selection
* event.
*
* @param clearEvent The ClearInstanceSelectionEvent which has been
* received.
*/
@Subscribe
void handleClearSelectionListener(DiscoveryEventUtils.ClearInstanceSelectionEvent clearEvent) {
instancesList.clearSelection();
}
/**
* Populate the instances list.
*
* @param populateEvent The PopulateInstancesListEvent which indicates the
* instances list should be populated
*/
@Subscribe
synchronized void handlePopulateInstancesListEvent(DiscoveryEventUtils.PopulateInstancesListEvent populateEvent) {
SwingUtilities.invokeLater(() -> {
List<AbstractFile> files = populateEvent.getInstances();
if (files.isEmpty()) {
//if there are no files currently remove the current items without removing listener to cause content viewer to reset
instancesListModel.removeAllElements();
//send fade out event
DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.DetailsVisibleEvent(false));
} else {
//remove listener so content viewer node is not set multiple times
instancesList.removeListSelectionListener(listener);
instancesListModel.removeAllElements();
for (AbstractFile file : files) {
instancesListModel.addElement(file);
}
//add listener back to allow selection of first index to cause content viewer node to be set
instancesList.addListSelectionListener(listener);
if (!instancesListModel.isEmpty()) {
instancesList.setSelectedIndex(0);
}
//send fade in event
DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.DetailsVisibleEvent(true));
}
});
}
/**
* Get the AbstractFile for the item currently selected in the instances
* list.
*
* @return The AbstractFile which is currently selected.
*/
synchronized AbstractFile getSelectedFile() {
if (instancesList.getSelectedIndex() == -1) {
return null;
} else {
return instancesListModel.getElementAt(instancesList.getSelectedIndex());
}
}
/**
* 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() {
detailsSplitPane = new javax.swing.JSplitPane();
javax.swing.JPanel instancesPanel = new javax.swing.JPanel();
javax.swing.JScrollPane instancesScrollPane = new javax.swing.JScrollPane();
instancesList = new javax.swing.JList<>();
detailsSplitPane.setDividerLocation(80);
detailsSplitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
detailsSplitPane.setMinimumSize(new java.awt.Dimension(200, 0));
detailsSplitPane.setPreferredSize(new java.awt.Dimension(700, 500));
instancesPanel.setMinimumSize(new java.awt.Dimension(0, 60));
instancesPanel.setPreferredSize(new java.awt.Dimension(700, 80));
instancesScrollPane.setPreferredSize(new java.awt.Dimension(775, 60));
instancesList.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(DetailsPanel.class, "DetailsPanel.instancesList.border.title"))); // NOI18N
instancesList.setModel(instancesListModel);
instancesList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
instancesList.setCellRenderer(new InstancesCellRenderer());
instancesList.setVisibleRowCount(2);
instancesScrollPane.setViewportView(instancesList);
javax.swing.GroupLayout instancesPanelLayout = new javax.swing.GroupLayout(instancesPanel);
instancesPanel.setLayout(instancesPanelLayout);
instancesPanelLayout.setHorizontalGroup(
instancesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 775, Short.MAX_VALUE)
.addGroup(instancesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(instancesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
instancesPanelLayout.setVerticalGroup(
instancesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 79, Short.MAX_VALUE)
.addGroup(instancesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, instancesPanelLayout.createSequentialGroup()
.addGap(0, 0, 0)
.addComponent(instancesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 79, Short.MAX_VALUE)))
);
detailsSplitPane.setTopComponent(instancesPanel);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 777, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(detailsSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 402, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(detailsSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JSplitPane detailsSplitPane;
private javax.swing.JList<AbstractFile> instancesList;
// End of variables declaration//GEN-END:variables
/**
* Cell renderer for the instances list.
*/
private class InstancesCellRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = 1L;
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
String name = "";
if (value instanceof AbstractFile) {
AbstractFile file = (AbstractFile) value;
try {
name = file.getUniquePath();
} catch (TskCoreException ingored) {
name = file.getParentPath() + "/" + file.getName();
}
}
setText(name);
return this;
}
}
}
@@ -0,0 +1,379 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[600, 300]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[1000, 650]"/>
</Property>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,0,-35,0,0,2,-11"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="toolBarPanel">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="First"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace pref="196" max="32767" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="filler1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="step1Label" min="-2" pref="243" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="imagesButton" min="-2" pref="110" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="videosButton" min="-2" pref="110" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="documentsButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace pref="196" 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 min="-2" pref="8" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="filler1" min="-2" pref="10" max="-2" attributes="0"/>
<Component id="step1Label" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="videosButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="imagesButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="documentsButton" alignment="3" min="-2" pref="43" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="imagesButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/pictures-icon.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="DiscoveryDialog.imagesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="disabledIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/pictures-icon.png"/>
</Property>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalAlignment" type="int" value="2"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[90, 43]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[90, 43]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[90, 43]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="imagesButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="videosButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/video-icon.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="DiscoveryDialog.videosButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="disabledIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/video-icon.png"/>
</Property>
<Property name="disabledSelectedIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/video-icon.png"/>
</Property>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalAlignment" type="int" value="2"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[90, 43]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[90, 43]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[90, 43]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="videosButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="documentsButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/documents-icon.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="DiscoveryDialog.documentsButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="disabledIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/documents-icon.png"/>
</Property>
<Property name="disabledSelectedIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/documents-icon.png"/>
</Property>
<Property name="focusable" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="documentsButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="step1Label">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="DiscoveryDialog.step1Label.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.Box$Filler" name="filler1">
<Properties>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[104, 32767]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[104, 0]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[104, 0]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.HorizontalStrut"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="displaySettingsPanel">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="Last"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="sortingPanel" pref="741" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="errorLabel" pref="575" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="65" max="-2" attributes="0"/>
<Component id="searchButton" min="-2" pref="101" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
<Component id="sortingPanel" min="-2" pref="89" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="errorLabel" alignment="0" min="-2" pref="23" max="-2" attributes="0"/>
<Component id="searchButton" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="searchButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="DiscoveryDialog.searchButton.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="searchButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="errorLabel">
<Properties>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JPanel" name="sortingPanel">
<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="Step 3: Choose display settings">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="DiscoveryDialog.sortingPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[345, 112]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="orderGroupsByLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="groupByLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="groupSortingComboBox" max="32767" attributes="0"/>
<Component id="groupByCombobox" max="32767" attributes="0"/>
</Group>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Component id="orderByLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="orderByCombobox" 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">
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="groupByCombobox" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="groupByLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="orderByCombobox" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="orderByLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="groupSortingComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="orderGroupsByLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JComboBox" name="groupByCombobox">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;GroupingAttributeType&gt;"/>
</AuxValues>
</Component>
<Component class="javax.swing.JComboBox" name="orderByCombobox">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;SortingMethod&gt;"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="orderGroupsByLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="DiscoveryDialog.orderGroupsByLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="orderByLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="DiscoveryDialog.orderByLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="groupByLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="DiscoveryDialog.groupByLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JComboBox" name="groupSortingComboBox">
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;GroupSortingAlgorithm&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>
@@ -0,0 +1,584 @@
/*
* Autopsy
*
* Copyright 2020 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.discovery;
import static java.awt.BorderLayout.CENTER;
import java.awt.Color;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import org.apache.commons.lang.StringUtils;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.discovery.FileGroup.GroupSortingAlgorithm;
import org.sleuthkit.autopsy.discovery.FileSearch.GroupingAttributeType;
import org.sleuthkit.autopsy.discovery.FileSorter.SortingMethod;
/**
* Dialog for displaying the controls and filters for configuration of a
* Discovery search.
*/
final class DiscoveryDialog extends javax.swing.JDialog {
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.CURRENT_CASE,
Case.Events.DATA_SOURCE_ADDED, Case.Events.DATA_SOURCE_DELETED);
private static final long serialVersionUID = 1L;
private final static Logger logger = Logger.getLogger(DiscoveryDialog.class.getName());
private ImageFilterPanel imageFilterPanel = null;
private VideoFilterPanel videoFilterPanel = null;
private DocumentFilterPanel documentFilterPanel = null;
private static final Color SELECTED_COLOR = new Color(216, 230, 242);
private static final Color UNSELECTED_COLOR = new Color(240, 240, 240);
private SearchWorker searchWorker = null;
private static DiscoveryDialog discDialog;
private FileSearchData.FileType fileType = FileSearchData.FileType.IMAGE;
private final PropertyChangeListener listener;
/**
* Get the Discovery dialog instance.
*
* @return The instance of the Discovery Dialog.
*/
static synchronized DiscoveryDialog getDiscoveryDialogInstance() {
if (discDialog == null) {
discDialog = new DiscoveryDialog();
}
return discDialog;
}
/**
* Private constructor to construct a new DiscoveryDialog
*/
@Messages("DiscoveryDialog.name.text=Discovery")
private DiscoveryDialog() {
super(WindowManager.getDefault().getMainWindow(), Bundle.DiscoveryDialog_name_text(), true);
initComponents();
listener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("FilterError") && evt.getNewValue() != null) {
setValid(evt.getNewValue().toString());
}
}
};
for (GroupSortingAlgorithm groupSortAlgorithm : GroupSortingAlgorithm.values()) {
groupSortingComboBox.addItem(groupSortAlgorithm);
}
updateSearchSettings();
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, this.new CasePropertyChangeListener());
}
/**
* Update the search settings to a default state.
*/
void updateSearchSettings() {
removeAllPanels();
imageFilterPanel = null;
videoFilterPanel = null;
documentFilterPanel = null;
imageFilterPanel = new ImageFilterPanel();
videoFilterPanel = new VideoFilterPanel();
documentFilterPanel = new DocumentFilterPanel();
imagesButton.setSelected(true);
imagesButton.setEnabled(false);
imagesButton.setBackground(SELECTED_COLOR);
imagesButton.setForeground(Color.BLACK);
videosButton.setSelected(false);
videosButton.setEnabled(true);
videosButton.setBackground(UNSELECTED_COLOR);
documentsButton.setSelected(false);
documentsButton.setEnabled(true);
documentsButton.setBackground(UNSELECTED_COLOR);
fileType = FileSearchData.FileType.IMAGE;
add(imageFilterPanel, CENTER);
imageFilterPanel.addPropertyChangeListener(listener);
updateComboBoxes();
pack();
repaint();
}
/**
* Private helper method to perform update of comboboxes update.
*/
private void updateComboBoxes() {
groupByCombobox.removeAllItems();
// Set up the grouping attributes
for (FileSearch.GroupingAttributeType type : FileSearch.GroupingAttributeType.getOptionsForGrouping()) {
addTypeToGroupByComboBox(type);
}
orderByCombobox.removeAllItems();
// Set up the file order list
for (FileSorter.SortingMethod method : FileSorter.SortingMethod.getOptionsForOrdering()) {
if (method != SortingMethod.BY_FREQUENCY || CentralRepository.isEnabled()) {
orderByCombobox.addItem(method);
}
}
groupSortingComboBox.setSelectedIndex(0);
}
/**
* Private helper method to add GroupingAttributeType to the
* groupByCombobox.
*
* @param type The Type of GroupingAttribute to add.
*/
private void addTypeToGroupByComboBox(GroupingAttributeType type) {
switch (type) {
case FREQUENCY:
if (!CentralRepository.isEnabled()) {
return;
}
break;
case OBJECT_DETECTED:
if (!imageFilterPanel.isObjectsFilterSupported()) {
return;
}
break;
case INTERESTING_ITEM_SET:
if (!imageFilterPanel.isInterestingItemsFilterSupported()) {
return;
}
break;
case HASH_LIST_NAME:
if (!imageFilterPanel.isHashSetFilterSupported()) {
return;
}
break;
default:
break;
}
groupByCombobox.addItem(type);
}
/**
* Validate the current filter settings of the selected type.
*/
synchronized void validateDialog() {
switch (fileType) {
case IMAGE:
if (imageFilterPanel != null) {
imageFilterPanel.validateFields();
}
return;
case VIDEO:
if (videoFilterPanel != null) {
videoFilterPanel.validateFields();
}
return;
case DOCUMENTS:
if (documentFilterPanel != null) {
documentFilterPanel.validateFields();
}
break;
default:
break;
}
}
/**
* 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() {
javax.swing.JPanel toolBarPanel = new javax.swing.JPanel();
imagesButton = new javax.swing.JButton();
videosButton = new javax.swing.JButton();
documentsButton = new javax.swing.JButton();
javax.swing.JLabel step1Label = new javax.swing.JLabel();
javax.swing.Box.Filler filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(104, 0), new java.awt.Dimension(104, 0), new java.awt.Dimension(104, 32767));
javax.swing.JPanel displaySettingsPanel = new javax.swing.JPanel();
searchButton = new javax.swing.JButton();
errorLabel = new javax.swing.JLabel();
javax.swing.JPanel sortingPanel = new javax.swing.JPanel();
groupByCombobox = new javax.swing.JComboBox<>();
orderByCombobox = new javax.swing.JComboBox<>();
javax.swing.JLabel orderGroupsByLabel = new javax.swing.JLabel();
javax.swing.JLabel orderByLabel = new javax.swing.JLabel();
javax.swing.JLabel groupByLabel = new javax.swing.JLabel();
groupSortingComboBox = new javax.swing.JComboBox<>();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setMinimumSize(new java.awt.Dimension(600, 300));
setPreferredSize(new java.awt.Dimension(1000, 650));
imagesButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/pictures-icon.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(imagesButton, org.openide.util.NbBundle.getMessage(DiscoveryDialog.class, "DiscoveryDialog.imagesButton.text")); // NOI18N
imagesButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/pictures-icon.png"))); // NOI18N
imagesButton.setFocusable(false);
imagesButton.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
imagesButton.setMaximumSize(new java.awt.Dimension(90, 43));
imagesButton.setMinimumSize(new java.awt.Dimension(90, 43));
imagesButton.setPreferredSize(new java.awt.Dimension(90, 43));
imagesButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
imagesButtonActionPerformed(evt);
}
});
videosButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/video-icon.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(videosButton, org.openide.util.NbBundle.getMessage(DiscoveryDialog.class, "DiscoveryDialog.videosButton.text")); // NOI18N
videosButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/video-icon.png"))); // NOI18N
videosButton.setDisabledSelectedIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/video-icon.png"))); // NOI18N
videosButton.setFocusable(false);
videosButton.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
videosButton.setMaximumSize(new java.awt.Dimension(90, 43));
videosButton.setMinimumSize(new java.awt.Dimension(90, 43));
videosButton.setPreferredSize(new java.awt.Dimension(90, 43));
videosButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
videosButtonActionPerformed(evt);
}
});
documentsButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/documents-icon.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(documentsButton, org.openide.util.NbBundle.getMessage(DiscoveryDialog.class, "DiscoveryDialog.documentsButton.text")); // NOI18N
documentsButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/documents-icon.png"))); // NOI18N
documentsButton.setDisabledSelectedIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/documents-icon.png"))); // NOI18N
documentsButton.setFocusable(false);
documentsButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
documentsButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(step1Label, org.openide.util.NbBundle.getMessage(DiscoveryDialog.class, "DiscoveryDialog.step1Label.text")); // NOI18N
javax.swing.GroupLayout toolBarPanelLayout = new javax.swing.GroupLayout(toolBarPanel);
toolBarPanel.setLayout(toolBarPanelLayout);
toolBarPanelLayout.setHorizontalGroup(
toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(toolBarPanelLayout.createSequentialGroup()
.addContainerGap(196, Short.MAX_VALUE)
.addGroup(toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, toolBarPanelLayout.createSequentialGroup()
.addComponent(filler1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(step1Label, javax.swing.GroupLayout.PREFERRED_SIZE, 243, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(toolBarPanelLayout.createSequentialGroup()
.addComponent(imagesButton, javax.swing.GroupLayout.PREFERRED_SIZE, 110, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(videosButton, javax.swing.GroupLayout.PREFERRED_SIZE, 110, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(documentsButton)))
.addContainerGap(196, Short.MAX_VALUE))
);
toolBarPanelLayout.setVerticalGroup(
toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(toolBarPanelLayout.createSequentialGroup()
.addGap(8, 8, 8)
.addGroup(toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(filler1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(step1Label))
.addGap(8, 8, 8)
.addGroup(toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(videosButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(imagesButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(documentsButton, javax.swing.GroupLayout.PREFERRED_SIZE, 43, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(8, 8, 8))
);
getContentPane().add(toolBarPanel, java.awt.BorderLayout.PAGE_START);
org.openide.awt.Mnemonics.setLocalizedText(searchButton, org.openide.util.NbBundle.getMessage(DiscoveryDialog.class, "DiscoveryDialog.searchButton.text")); // NOI18N
searchButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
searchButtonActionPerformed(evt);
}
});
errorLabel.setForeground(new java.awt.Color(255, 0, 0));
sortingPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(DiscoveryDialog.class, "DiscoveryDialog.sortingPanel.border.title"))); // NOI18N
sortingPanel.setPreferredSize(new java.awt.Dimension(345, 112));
org.openide.awt.Mnemonics.setLocalizedText(orderGroupsByLabel, org.openide.util.NbBundle.getMessage(DiscoveryDialog.class, "DiscoveryDialog.orderGroupsByLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(orderByLabel, org.openide.util.NbBundle.getMessage(DiscoveryDialog.class, "DiscoveryDialog.orderByLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(groupByLabel, org.openide.util.NbBundle.getMessage(DiscoveryDialog.class, "DiscoveryDialog.groupByLabel.text")); // NOI18N
javax.swing.GroupLayout sortingPanelLayout = new javax.swing.GroupLayout(sortingPanel);
sortingPanel.setLayout(sortingPanelLayout);
sortingPanelLayout.setHorizontalGroup(
sortingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(sortingPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(sortingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(orderGroupsByLabel)
.addComponent(groupByLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(sortingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(groupSortingComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(groupByCombobox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(orderByLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(orderByCombobox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addContainerGap())
);
sortingPanelLayout.setVerticalGroup(
sortingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(sortingPanelLayout.createSequentialGroup()
.addGap(8, 8, 8)
.addGroup(sortingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(groupByCombobox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(groupByLabel)
.addComponent(orderByCombobox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(orderByLabel))
.addGap(8, 8, 8)
.addGroup(sortingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(groupSortingComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(orderGroupsByLabel))
.addGap(8, 8, 8))
);
javax.swing.GroupLayout displaySettingsPanelLayout = new javax.swing.GroupLayout(displaySettingsPanel);
displaySettingsPanel.setLayout(displaySettingsPanelLayout);
displaySettingsPanelLayout.setHorizontalGroup(
displaySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, displaySettingsPanelLayout.createSequentialGroup()
.addGap(8, 8, 8)
.addGroup(displaySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(sortingPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 741, Short.MAX_VALUE)
.addGroup(displaySettingsPanelLayout.createSequentialGroup()
.addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 575, Short.MAX_VALUE)
.addGap(65, 65, 65)
.addComponent(searchButton, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGap(8, 8, 8))
);
displaySettingsPanelLayout.setVerticalGroup(
displaySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, displaySettingsPanelLayout.createSequentialGroup()
.addGap(8, 8, 8)
.addComponent(sortingPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 89, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(8, 8, 8)
.addGroup(displaySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(errorLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(searchButton))
.addGap(8, 8, 8))
);
getContentPane().add(displaySettingsPanel, java.awt.BorderLayout.PAGE_END);
pack();
}// </editor-fold>//GEN-END:initComponents
private void imagesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_imagesButtonActionPerformed
removeAllPanels();
add(imageFilterPanel, CENTER);
imagesButton.setSelected(true);
imagesButton.setEnabled(false);
imagesButton.setBackground(SELECTED_COLOR);
imagesButton.setForeground(Color.BLACK);
videosButton.setSelected(false);
videosButton.setEnabled(true);
videosButton.setBackground(UNSELECTED_COLOR);
documentsButton.setSelected(false);
documentsButton.setEnabled(true);
documentsButton.setBackground(UNSELECTED_COLOR);
fileType = FileSearchData.FileType.IMAGE;
imageFilterPanel.addPropertyChangeListener(listener);
validateDialog();
pack();
repaint();
}//GEN-LAST:event_imagesButtonActionPerformed
private void videosButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_videosButtonActionPerformed
removeAllPanels();
add(videoFilterPanel, CENTER);
imagesButton.setSelected(false);
imagesButton.setEnabled(true);
imagesButton.setBackground(UNSELECTED_COLOR);
videosButton.setSelected(true);
videosButton.setEnabled(false);
videosButton.setBackground(SELECTED_COLOR);
videosButton.setForeground(Color.BLACK);
documentsButton.setSelected(false);
documentsButton.setEnabled(true);
documentsButton.setBackground(UNSELECTED_COLOR);
videoFilterPanel.addPropertyChangeListener(listener);
fileType = FileSearchData.FileType.VIDEO;
validateDialog();
pack();
repaint();
}//GEN-LAST:event_videosButtonActionPerformed
private void documentsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_documentsButtonActionPerformed
removeAllPanels();
add(documentFilterPanel, CENTER);
documentsButton.setSelected(true);
documentsButton.setEnabled(false);
documentsButton.setBackground(SELECTED_COLOR);
documentsButton.setForeground(Color.BLACK);
videosButton.setSelected(false);
videosButton.setEnabled(true);
videosButton.setBackground(UNSELECTED_COLOR);
imagesButton.setSelected(false);
imagesButton.setEnabled(true);
imagesButton.setBackground(UNSELECTED_COLOR);
fileType = FileSearchData.FileType.DOCUMENTS;
documentFilterPanel.addPropertyChangeListener(listener);
validateDialog();
pack();
repaint();
}//GEN-LAST:event_documentsButtonActionPerformed
/**
* Helper method to remove all filter panels and their listeners
*/
private void removeAllPanels() {
if (imageFilterPanel != null) {
remove(imageFilterPanel);
imageFilterPanel.removePropertyChangeListener(listener);
}
if (documentFilterPanel != null) {
remove(documentFilterPanel);
documentFilterPanel.removePropertyChangeListener(listener);
}
if (videoFilterPanel != null) {
remove(videoFilterPanel);
videoFilterPanel.removePropertyChangeListener(listener);
}
}
private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed
// Get the selected filters
final DiscoveryTopComponent tc = DiscoveryTopComponent.getTopComponent();
if (tc == null) {
setValid("No Top Component Found");
return;
}
if (tc.isOpened() == false) {
tc.open();
}
tc.resetTopComponent();
List<FileSearchFiltering.FileFilter> filters;
if (videosButton.isSelected()) {
filters = videoFilterPanel.getFilters();
} else if (documentsButton.isSelected()) {
filters = documentFilterPanel.getFilters();
} else {
filters = imageFilterPanel.getFilters();
}
DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.SearchStartedEvent(fileType));
// Get the grouping attribute and group sorting method
FileSearch.AttributeType groupingAttr = groupByCombobox.getItemAt(groupByCombobox.getSelectedIndex()).getAttributeType();
FileGroup.GroupSortingAlgorithm groupSortAlgorithm = groupSortingComboBox.getItemAt(groupSortingComboBox.getSelectedIndex());
// Get the file sorting method
FileSorter.SortingMethod fileSort = (FileSorter.SortingMethod) orderByCombobox.getSelectedItem();
CentralRepository centralRepoDb = null;
if (CentralRepository.isEnabled()) {
try {
centralRepoDb = CentralRepository.getInstance();
} catch (CentralRepoException ex) {
centralRepoDb = null;
logger.log(Level.SEVERE, "Error loading central repository database, no central repository options will be available for Discovery", ex);
}
}
searchWorker = new SearchWorker(centralRepoDb, filters, groupingAttr, groupSortAlgorithm, fileSort);
searchWorker.execute();
dispose();
tc.toFront();
tc.requestActive();
}//GEN-LAST:event_searchButtonActionPerformed
@Override
public void dispose() {
setVisible(false);
}
/**
* Cancel the searchWorker if it exists.
*/
void cancelSearch() {
if (searchWorker != null) {
searchWorker.cancel(true);
}
}
/**
* The adjust the controls to reflect whether the settings are valid based
* on the error.
*
* @param error The error message to display, empty string if there is no error.
*/
private void setValid(String error) {
if (StringUtils.isBlank(error)) {
errorLabel.setText("");
searchButton.setEnabled(true);
} else {
errorLabel.setText(error);
searchButton.setEnabled(false);
}
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton documentsButton;
private javax.swing.JLabel errorLabel;
private javax.swing.JComboBox<GroupingAttributeType> groupByCombobox;
private javax.swing.JComboBox<GroupSortingAlgorithm> groupSortingComboBox;
private javax.swing.JButton imagesButton;
private javax.swing.JComboBox<SortingMethod> orderByCombobox;
private javax.swing.JButton searchButton;
private javax.swing.JButton videosButton;
// End of variables declaration//GEN-END:variables
/**
* PropertyChangeListener to listen to case level events that may modify the
* filters available.
*/
private class CasePropertyChangeListener implements PropertyChangeListener {
@Override
@SuppressWarnings("fallthrough")
public void propertyChange(PropertyChangeEvent evt) {
switch (Case.Events.valueOf(evt.getPropertyName())) {
case CURRENT_CASE: {
if (evt.getNewValue() == null) {
//do not refresh when a case is closed only when it is opened.
break;
}
//else fallthrough
}
case DATA_SOURCE_ADDED:
//fallthrough
case DATA_SOURCE_DELETED:
updateSearchSettings();
break;
default:
//do nothing if the event is not one of the above events.
break;
}
}
}
}
@@ -1,7 +1,7 @@
/*
* Autopsy
*
* Copyright 2019 Basis Technology Corp.
* Copyright 2019-2020 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,32 +16,37 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import com.google.common.eventbus.EventBus;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.sleuthkit.autopsy.filequery.FileSearch.GroupKey;
import org.sleuthkit.autopsy.filequery.FileSearchData.FileType;
import org.sleuthkit.autopsy.discovery.FileSearch.GroupKey;
import org.sleuthkit.autopsy.discovery.FileSearchData.FileType;
import org.sleuthkit.datamodel.AbstractFile;
/**
* Class to handle event bus and events for file discovery tool.
* Class to handle event bus and events for discovery tool.
*/
final class DiscoveryEventUtils {
private final static EventBus discoveryEventBus = new EventBus();
/**
* Get the file discovery event bus.
* Get the discovery event bus.
*
* @return The file discovery event bus.
* @return The discovery event bus.
*/
static EventBus getDiscoveryEventBus() {
return discoveryEventBus;
}
/**
* Private no arg constructor for Utility class.
*/
private DiscoveryEventUtils() {
//Utility class private constructor intentionally left blank.
}
/**
@@ -70,6 +75,41 @@ final class DiscoveryEventUtils {
}
}
/**
* Event to signal that the Instances list should have selection cleared.
*/
static final class ClearInstanceSelectionEvent {
/**
* Construct a new ClearInstanceSelectionEvent.
*/
ClearInstanceSelectionEvent() {
//no arg constructor
}
}
/**
* Event to signal that the Instances list should be populated.
*/
static final class PopulateInstancesListEvent {
private final List<AbstractFile> instances;
/**
* Construct a new PopulateInstancesListEvent.
*/
PopulateInstancesListEvent(List<AbstractFile> files) {
instances = files;
}
/**
* @return the instances
*/
List<AbstractFile> getInstances() {
return Collections.unmodifiableList(instances);
}
}
/**
* Event to signal the completion of a search being performed.
*/
@@ -332,4 +372,32 @@ final class DiscoveryEventUtils {
}
}
/**
* Event to signal that the visibility of the Details area should change.
*/
static class DetailsVisibleEvent {
private final boolean showDetailsArea;
/**
* Construct a new DetailsVisibleEvent.
*
* @param isVisible True if the details area should be visible, false
* otherwise.
*/
DetailsVisibleEvent(boolean isVisible) {
showDetailsArea = isVisible;
}
/**
* Get the visibility of the Details area.
*
* @return True if the details area should be visible, false otherwise.
*/
boolean isShowDetailsArea() {
return showDetailsArea;
}
}
}
@@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import org.sleuthkit.autopsy.directorytree.actionhelpers.ExtractActionHelper;
import java.awt.event.ActionEvent;
@@ -29,7 +29,7 @@ import org.sleuthkit.datamodel.AbstractFile;
/**
* Extracts AbstractFiles to a location selected by the user.
*/
public final class DiscoveryExtractAction extends AbstractAction {
final class DiscoveryExtractAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private final Collection<AbstractFile> files = new HashSet<>();
@@ -40,7 +40,7 @@ public final class DiscoveryExtractAction extends AbstractAction {
*
* @param selectedFiles The files to extract from the current case.
*/
public DiscoveryExtractAction(Collection<AbstractFile> selectedFiles) {
DiscoveryExtractAction(Collection<AbstractFile> selectedFiles) {
super(NbBundle.getMessage(DiscoveryExtractAction.class, "DiscoveryExtractAction.title.extractFiles.text"));
files.addAll(selectedFiles);
}
@@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import java.util.Arrays;
import java.util.HashSet;
@@ -0,0 +1,158 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.4" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[199, 200]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[1100, 700]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<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,-68,0,0,4,76"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
<SubComponents>
<Container class="javax.swing.JSplitPane" name="mainSplitPane">
<Properties>
<Property name="dividerLocation" type="int" value="250"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[1100, 700]"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="Center"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JSplitPane" name="rightSplitPane">
<Properties>
<Property name="dividerSize" type="int" value="15"/>
<Property name="orientation" type="int" value="0"/>
<Property name="resizeWeight" type="double" value="1.0"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[800, 700]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new AnimatedSplitPane()"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
<JSplitPaneConstraints position="right"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
</Container>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="searchDetailsPanel">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="First"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="newSearchButton" min="-2" pref="110" max="-2" attributes="0"/>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Component id="progressMessageScrollPane" pref="954" 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" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
<Component id="progressMessageScrollPane" min="-2" pref="44" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="17" max="-2" attributes="0"/>
<Component id="newSearchButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="newSearchButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="FileSearchDialog.cancelButton.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="[110, 26]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[110, 26]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[110, 26]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="newSearchButtonActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="progressMessageScrollPane">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextArea" name="progressMessageTextArea">
<Properties>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="f0" green="f0" red="f0" type="rgb"/>
</Property>
<Property name="columns" type="int" value="20"/>
<Property name="lineWrap" type="boolean" value="true"/>
<Property name="rows" type="int" value="2"/>
<Property name="wrapStyleWord" type="boolean" value="true"/>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>
@@ -0,0 +1,341 @@
/*
* Autopsy
*
* Copyright 2019-2020 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.discovery;
import com.google.common.eventbus.Subscribe;
import java.awt.Color;
import java.awt.Graphics;
import java.util.List;
import java.util.stream.Collectors;
import javax.swing.JSplitPane;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.Mode;
import org.openide.windows.RetainLocation;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.discovery.FileSearchFiltering.FileFilter;
/**
* Create a dialog for displaying the Discovery results.
*/
@TopComponent.Description(preferredID = "DiscoveryTopComponent", persistenceType = TopComponent.PERSISTENCE_NEVER)
@TopComponent.Registration(mode = "discovery", openAtStartup = false)
@RetainLocation("discovery")
@NbBundle.Messages("DiscoveryTopComponent.name= Discovery")
public final class DiscoveryTopComponent extends TopComponent {
private static final long serialVersionUID = 1L;
private static final String PREFERRED_ID = "DiscoveryTopComponent"; // NON-NLS
private final GroupListPanel groupListPanel;
private final DetailsPanel detailsPanel;
private final ResultsPanel resultsPanel;
private int dividerLocation = -1;
private static final int ANIMATION_INCREMENT = 10;
private static final int RESULTS_AREA_SMALL_SIZE = 250;
private SwingAnimator animator = null;
/**
* Creates new form DiscoveryTopComponent.
*/
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
public DiscoveryTopComponent() {
initComponents();
setName(Bundle.DiscoveryTopComponent_name());
groupListPanel = new GroupListPanel();
resultsPanel = new ResultsPanel();
detailsPanel = new DetailsPanel();
mainSplitPane.setLeftComponent(groupListPanel);
rightSplitPane.setTopComponent(resultsPanel);
rightSplitPane.setBottomComponent(detailsPanel);
}
/**
* Get the current DiscoveryTopComponent if it is open.
*
* @return The open DiscoveryTopComponent or null if it has not been opened.
*/
public static DiscoveryTopComponent getTopComponent() {
return (DiscoveryTopComponent) WindowManager.getDefault().findTopComponent(PREFERRED_ID);
}
/**
* Reset the top component so it isn't displaying any results.
*/
public void resetTopComponent() {
resultsPanel.resetResultViewer();
groupListPanel.resetGroupList();
}
@Override
public void componentOpened() {
super.componentOpened();
WindowManager.getDefault().setTopComponentFloating(this, true);
DiscoveryEventUtils.getDiscoveryEventBus().register(this);
DiscoveryEventUtils.getDiscoveryEventBus().register(resultsPanel);
DiscoveryEventUtils.getDiscoveryEventBus().register(groupListPanel);
DiscoveryEventUtils.getDiscoveryEventBus().register(detailsPanel);
}
@Override
protected void componentClosed() {
DiscoveryDialog.getDiscoveryDialogInstance().cancelSearch();
DiscoveryEventUtils.getDiscoveryEventBus().unregister(this);
DiscoveryEventUtils.getDiscoveryEventBus().unregister(groupListPanel);
DiscoveryEventUtils.getDiscoveryEventBus().unregister(resultsPanel);
DiscoveryEventUtils.getDiscoveryEventBus().unregister(detailsPanel);
super.componentClosed();
}
/**
* 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() {
mainSplitPane = new javax.swing.JSplitPane();
rightSplitPane = new AnimatedSplitPane();
javax.swing.JPanel searchDetailsPanel = new javax.swing.JPanel();
newSearchButton = new javax.swing.JButton();
javax.swing.JScrollPane progressMessageScrollPane = new javax.swing.JScrollPane();
progressMessageTextArea = new javax.swing.JTextArea();
setMinimumSize(new java.awt.Dimension(199, 200));
setPreferredSize(new java.awt.Dimension(1100, 700));
setLayout(new java.awt.BorderLayout());
mainSplitPane.setDividerLocation(250);
mainSplitPane.setPreferredSize(new java.awt.Dimension(1100, 700));
rightSplitPane.setDividerSize(15);
rightSplitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
rightSplitPane.setResizeWeight(1.0);
rightSplitPane.setPreferredSize(new java.awt.Dimension(800, 700));
mainSplitPane.setRightComponent(rightSplitPane);
add(mainSplitPane, java.awt.BorderLayout.CENTER);
org.openide.awt.Mnemonics.setLocalizedText(newSearchButton, org.openide.util.NbBundle.getMessage(DiscoveryTopComponent.class, "FileSearchDialog.cancelButton.text")); // NOI18N
newSearchButton.setMaximumSize(new java.awt.Dimension(110, 26));
newSearchButton.setMinimumSize(new java.awt.Dimension(110, 26));
newSearchButton.setPreferredSize(new java.awt.Dimension(110, 26));
newSearchButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
newSearchButtonActionPerformed(evt);
}
});
progressMessageScrollPane.setBorder(null);
progressMessageTextArea.setBackground(new java.awt.Color(240, 240, 240));
progressMessageTextArea.setColumns(20);
progressMessageTextArea.setLineWrap(true);
progressMessageTextArea.setRows(2);
progressMessageTextArea.setWrapStyleWord(true);
progressMessageTextArea.setBorder(null);
progressMessageScrollPane.setViewportView(progressMessageTextArea);
javax.swing.GroupLayout searchDetailsPanelLayout = new javax.swing.GroupLayout(searchDetailsPanel);
searchDetailsPanel.setLayout(searchDetailsPanelLayout);
searchDetailsPanelLayout.setHorizontalGroup(
searchDetailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(searchDetailsPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(newSearchButton, javax.swing.GroupLayout.PREFERRED_SIZE, 110, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(progressMessageScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 954, Short.MAX_VALUE)
.addContainerGap())
);
searchDetailsPanelLayout.setVerticalGroup(
searchDetailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(searchDetailsPanelLayout.createSequentialGroup()
.addGroup(searchDetailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(searchDetailsPanelLayout.createSequentialGroup()
.addGap(8, 8, 8)
.addComponent(progressMessageScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 44, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(searchDetailsPanelLayout.createSequentialGroup()
.addGap(17, 17, 17)
.addComponent(newSearchButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addContainerGap())
);
add(searchDetailsPanel, java.awt.BorderLayout.PAGE_START);
}// </editor-fold>//GEN-END:initComponents
private void newSearchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newSearchButtonActionPerformed
close();
final DiscoveryDialog discDialog = DiscoveryDialog.getDiscoveryDialogInstance();
discDialog.cancelSearch();
discDialog.setVisible(true);
discDialog.validateDialog();
}//GEN-LAST:event_newSearchButtonActionPerformed
@Override
public List<Mode> availableModes(List<Mode> modes) {
/*
* This looks like the right thing to do, but online discussions seems
* to indicate this method is effectively deprecated. A break point
* placed here was never hit.
*/
return modes.stream().filter(mode -> mode.getName().equals("discovery"))
.collect(Collectors.toList());
}
/**
* Subscribe to the DetailsVisible event and animate the panel as it changes
* visibility.
*
* @param detailsVisibleEvent The DetailsVisibleEvent which indicates if the
* panel should be made visible or hidden.
*/
@Subscribe
void handleDetailsVisibleEvent(DiscoveryEventUtils.DetailsVisibleEvent detailsVisibleEvent) {
if (animator != null && animator.isRunning()) {
animator.stop();
}
dividerLocation = rightSplitPane.getDividerLocation();
if (detailsVisibleEvent.isShowDetailsArea()) {
animator = new SwingAnimator(new ShowDetailsAreaCallback());
} else {
animator = new SwingAnimator(new HideDetailsAreaCallback());
}
animator.start();
}
/**
* Subscribe to the SearchStartedEvent for updating the UI accordingly.
*
* @param searchStartedEvent The event which indicates the start of a
* search.
*/
@Messages({"DiscoveryTopComponent.cancelButton.text=Cancel Search",
"# {0} - searchType",
"DiscoveryTopComponent.searchInProgress.text=Performing search for results of type {0}. Please wait."})
@Subscribe
void handleSearchStartedEvent(DiscoveryEventUtils.SearchStartedEvent searchStartedEvent) {
newSearchButton.setText(Bundle.DiscoveryTopComponent_cancelButton_text());
progressMessageTextArea.setForeground(Color.red);
progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchInProgress_text(searchStartedEvent.getType().name()));
}
/**
* Subscribe to the SearchCompleteEvent for updating the UI accordingly.
*
* @param searchCompleteEvent The event which indicates the completion of a
* search.
*/
@Subscribe
@Messages({"DiscoveryTopComponent.newSearch.text=New Search",
"# {0} - search",
"DiscoveryTopComponent.searchComplete.text=Results for {0}"})
void handleSearchCompleteEvent(DiscoveryEventUtils.SearchCompleteEvent searchCompleteEvent) {
newSearchButton.setText(Bundle.DiscoveryTopComponent_newSearch_text());
progressMessageTextArea.setForeground(Color.black);
progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchComplete_text(searchCompleteEvent.getFilters().stream().map(FileFilter::getDesc).collect(Collectors.joining(", "))));
progressMessageTextArea.setCaretPosition(0);
}
/**
* Subscribe to the SearchCancelledEvent for updating the UI accordingly.
*
* @param searchCancelledEvent The event which indicates the cancellation of
* a search.
*/
@Messages({"DiscoveryTopComponent.searchCancelled.text=Search has been cancelled."})
@Subscribe
void handleSearchCancelledEvent(DiscoveryEventUtils.SearchCancelledEvent searchCancelledEvent) {
newSearchButton.setText(Bundle.DiscoveryTopComponent_newSearch_text());
progressMessageTextArea.setForeground(Color.red);
progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchCancelled_text());
}
/**
* Callback for animating the details area into a visible position.
*/
private final class ShowDetailsAreaCallback implements SwingAnimatorCallback {
@Override
public void callback(Object caller) {
dividerLocation -= ANIMATION_INCREMENT;
repaint();
}
@Override
public boolean hasTerminated() {
if (dividerLocation != JSplitPane.UNDEFINED_CONDITION && dividerLocation < RESULTS_AREA_SMALL_SIZE) {
dividerLocation = RESULTS_AREA_SMALL_SIZE;
return true;
}
return false;
}
}
/**
* Callback for animating the details area into a hidden position.
*/
private final class HideDetailsAreaCallback implements SwingAnimatorCallback {
@Override
public void callback(Object caller) {
dividerLocation += ANIMATION_INCREMENT;
repaint();
}
@Override
public boolean hasTerminated() {
if (dividerLocation > rightSplitPane.getHeight() || dividerLocation == JSplitPane.UNDEFINED_CONDITION) {
dividerLocation = rightSplitPane.getHeight();
return true;
}
return false;
}
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JSplitPane mainSplitPane;
private javax.swing.JButton newSearchButton;
private javax.swing.JTextArea progressMessageTextArea;
private javax.swing.JSplitPane rightSplitPane;
// End of variables declaration//GEN-END:variables
/**
* Class for the split pane which will be animated.
*/
private final class AnimatedSplitPane extends JSplitPane {
private static final long serialVersionUID = 1L;
@Override
public void paintComponent(Graphics g) {
if ((dividerLocation == JSplitPane.UNDEFINED_CONDITION) || (dividerLocation <= rightSplitPane.getHeight() && dividerLocation >= RESULTS_AREA_SMALL_SIZE)) {
rightSplitPane.setDividerLocation(dividerLocation);
}
super.paintComponent(g);
}
}
}
@@ -16,20 +16,37 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import java.awt.Component;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import org.openide.util.ImageUtilities;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.IngestJobInfo;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Utility class for the various user interface elements used by File Discovery.
* Utility class for the various user interface elements used by Discovery.
*/
final class DiscoveryUiUtils {
private final static Logger logger = Logger.getLogger(DiscoveryUiUtils.class.getName());
private static final int BYTE_UNIT_CONVERSION = 1000;
private static final int ICON_SIZE = 16;
private static final String RED_CIRCLE_ICON_PATH = "org/sleuthkit/autopsy/images/red-circle-exclamation.png";
@@ -95,6 +112,35 @@ final class DiscoveryUiUtils {
return UNSUPPORTED_DOCUMENT_THUMBNAIL;
}
/**
* Get the names of the sets which exist in the case database for the
* specified artifact and attribute types.
*
* @param artifactType The artifact type to get the list of sets for.
* @param setNameAttribute The attribute type which contains the set names.
*
* @return A list of set names which exist in the case for the specified
* artifact and attribute types.
*
* @throws TskCoreException
*/
static List<String> getSetNames(BlackboardArtifact.ARTIFACT_TYPE artifactType, BlackboardAttribute.ATTRIBUTE_TYPE setNameAttribute) throws TskCoreException {
List<BlackboardArtifact> arts = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifacts(artifactType);
List<String> setNames = new ArrayList<>();
for (BlackboardArtifact art : arts) {
for (BlackboardAttribute attr : art.getAttributes()) {
if (attr.getAttributeType().getTypeID() == setNameAttribute.getTypeID()) {
String setName = attr.getValueString();
if (!setNames.contains(setName)) {
setNames.add(setName);
}
}
}
}
Collections.sort(setNames);
return setNames;
}
/**
* Helper method to see if point is on the icon.
*
@@ -157,6 +203,35 @@ final class DiscoveryUiUtils {
return ICON_SIZE;
}
/**
* Helper method to display an error message when the results of the
* Discovery Top component may be incomplete.
*/
static void displayErrorMessage(DiscoveryDialog dialog) {
//check if modules run and assemble message
try {
SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
Map<Long, DataSourceModulesWrapper> dataSourceIngestModules = new HashMap<>();
for (DataSource dataSource : skCase.getDataSources()) {
dataSourceIngestModules.put(dataSource.getId(), new DataSourceModulesWrapper(dataSource.getName()));
}
for (IngestJobInfo jobInfo : skCase.getIngestJobs()) {
dataSourceIngestModules.get(jobInfo.getObjectId()).updateModulesRun(jobInfo);
}
String message = "";
for (DataSourceModulesWrapper dsmodulesWrapper : dataSourceIngestModules.values()) {
message += dsmodulesWrapper.getMessage();
}
if (!message.isEmpty()) {
JOptionPane.showMessageDialog(dialog, message, Bundle.OpenDiscoveryAction_resultsIncomplete_text(), JOptionPane.INFORMATION_MESSAGE);
}
} catch (NoCurrentCaseException | TskCoreException ex) {
logger.log(Level.WARNING, "Exception while determining which modules have been run for Discovery", ex);
}
dialog.validateDialog();
}
/**
* Private constructor for DiscoveryUiUtils utility class.
*/
@@ -0,0 +1,78 @@
<?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"/>
<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,0,102,0,0,1,56"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="documentFiltersScrollPane">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="Center"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="documentFiltersPanel">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
<Component id="documentsFiltersSplitPane" pref="294" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
<Component id="documentsFiltersSplitPane" pref="84" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JSplitPane" name="documentsFiltersSplitPane">
<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="Step 2: Filter which documents to show">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="DocumentFilterPanel.documentsFiltersSplitPane.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
<Property name="resizeWeight" type="double" value="0.5"/>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>
@@ -0,0 +1,100 @@
/*
* Autopsy
*
* Copyright 2020 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.discovery;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
/**
* Class which displays all filters available for the Documents search type.
*/
final class DocumentFilterPanel extends AbstractFiltersPanel {
private static final long serialVersionUID = 1L;
private static final FileSearchData.FileType FILE_TYPE = FileSearchData.FileType.DOCUMENTS;
/**
* Constructs a new DocumentFilterPanel.
*/
DocumentFilterPanel() {
super();
initComponents();
addFilter(new SizeFilterPanel(FileSearchData.FileType.DOCUMENTS), false, null, 0);
addFilter(new DataSourceFilterPanel(), false, null, 0);
int[] pastOccurrencesIndices;
if (!CentralRepository.isEnabled()) {
pastOccurrencesIndices = new int[]{0};
} else {
pastOccurrencesIndices = new int[]{1, 2, 3, 4, 5, 6, 7};
}
addFilter(new PastOccurrencesFilterPanel(), true, pastOccurrencesIndices, 0);
addFilter(new HashSetFilterPanel(), false, null, 1);
addFilter(new InterestingItemsFilterPanel(), false, null, 1);
addFilter(new ObjectDetectedFilterPanel(), false, null, 1);
addFilter(new ParentFolderFilterPanel(), false, null, 1);
addPanelsToScrollPane(documentsFiltersSplitPane);
}
/**
* 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() {
javax.swing.JScrollPane documentFiltersScrollPane = new javax.swing.JScrollPane();
javax.swing.JPanel documentFiltersPanel = new javax.swing.JPanel();
documentsFiltersSplitPane = new javax.swing.JSplitPane();
setLayout(new java.awt.BorderLayout());
documentsFiltersSplitPane.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(DocumentFilterPanel.class, "DocumentFilterPanel.documentsFiltersSplitPane.border.title"))); // NOI18N
documentsFiltersSplitPane.setResizeWeight(0.5);
javax.swing.GroupLayout documentFiltersPanelLayout = new javax.swing.GroupLayout(documentFiltersPanel);
documentFiltersPanel.setLayout(documentFiltersPanelLayout);
documentFiltersPanelLayout.setHorizontalGroup(
documentFiltersPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(documentFiltersPanelLayout.createSequentialGroup()
.addGap(8, 8, 8)
.addComponent(documentsFiltersSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 294, Short.MAX_VALUE)
.addGap(8, 8, 8))
);
documentFiltersPanelLayout.setVerticalGroup(
documentFiltersPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(documentFiltersPanelLayout.createSequentialGroup()
.addGap(8, 8, 8)
.addComponent(documentsFiltersSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 84, Short.MAX_VALUE)
.addGap(8, 8, 8))
);
documentFiltersScrollPane.setViewportView(documentFiltersPanel);
add(documentFiltersScrollPane, java.awt.BorderLayout.CENTER);
}// </editor-fold>//GEN-END:initComponents
@Override
FileSearchData.FileType getFileType() {
return FILE_TYPE;
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JSplitPane documentsFiltersSplitPane;
// End of variables declaration//GEN-END:variables
}
@@ -80,16 +80,16 @@
<Image iconType="3" name="/org/sleuthkit/autopsy/images/file-icon-deleted.png"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/filequery/Bundle.properties" key="DocumentPanel.isDeletedLabel.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="DocumentPanel.isDeletedLabel.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())" type="code"/>
<Connection code="new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())" type="code"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())" type="code"/>
<Connection code="new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())" type="code"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())" type="code"/>
<Connection code="new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())" type="code"/>
</Property>
</Properties>
</Component>
@@ -100,20 +100,20 @@
</Property>
<Property name="toolTipText" type="java.lang.String" value=""/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())" type="code"/>
<Connection code="new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())" type="code"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())" type="code"/>
<Connection code="new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())" type="code"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())" type="code"/>
<Connection code="new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())" type="code"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="fileSizeLabel">
<Properties>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/filequery/Bundle.properties" key="DocumentPanel.fileSizeLabel.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="DocumentPanel.fileSizeLabel.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
@@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import java.awt.Color;
import java.awt.Component;
@@ -33,16 +33,16 @@ import org.sleuthkit.autopsy.corecomponents.AutoWrappingJTextPane;
/**
* Class which displays a preview and details about a document.
*/
public class DocumentPanel extends javax.swing.JPanel implements ListCellRenderer<DocumentWrapper> {
class DocumentPanel extends javax.swing.JPanel implements ListCellRenderer<DocumentWrapper> {
private static final long serialVersionUID = 1L;
private static final Color SELECTION_COLOR = new Color(0, 120, 215);
private static final int MAX_NAME_STRING = 90;
/**
* Creates new form DocumentPanel
* Creates new form DocumentPanel.
*/
public DocumentPanel() {
DocumentPanel() {
initComponents();
}
@@ -67,15 +67,15 @@ public class DocumentPanel extends javax.swing.JPanel implements ListCellRendere
isDeletedLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/file-icon-deleted.png"))); // NOI18N
isDeletedLabel.setToolTipText(org.openide.util.NbBundle.getMessage(DocumentPanel.class, "DocumentPanel.isDeletedLabel.toolTipText")); // NOI18N
isDeletedLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize()));
isDeletedLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize()));
isDeletedLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize()));
isDeletedLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize()));
isDeletedLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize()));
isDeletedLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize()));
scoreLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/red-circle-exclamation.png"))); // NOI18N
scoreLabel.setToolTipText("");
scoreLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize()));
scoreLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize()));
scoreLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize()));
scoreLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize()));
scoreLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize()));
scoreLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize()));
fileSizeLabel.setToolTipText(org.openide.util.NbBundle.getMessage(DocumentPanel.class, "DocumentPanel.fileSizeLabel.toolTipText")); // NOI18N
@@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import java.util.ArrayList;
import java.util.List;
@@ -27,15 +27,15 @@ import org.sleuthkit.datamodel.AbstractFile;
/**
* A JPanel to display document previews.
*/
public class DocumentPreviewViewer extends javax.swing.JPanel {
final class DocumentPreviewViewer extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private final DefaultListModel<DocumentWrapper> documentListModel = new DefaultListModel<>();
/**
* Creates new form DocumentViewer
* Creates new form DocumentViewer.
*/
public DocumentPreviewViewer() {
DocumentPreviewViewer() {
initComponents();
}
@@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.textsummarizer.TextSummary;
@@ -25,7 +25,7 @@ import org.sleuthkit.autopsy.textsummarizer.TextSummary;
* Class to wrap all the information necessary for a document summary to be
* displayed.
*/
public class DocumentWrapper {
final class DocumentWrapper {
private TextSummary summary;
private final ResultFile resultFile;
@@ -16,13 +16,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.filequery.FileSearch.GroupKey;
import org.sleuthkit.autopsy.discovery.FileSearch.GroupKey;
/**
* Class for storing files that belong to a particular group.
@@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
@@ -66,9 +66,9 @@ import org.sleuthkit.autopsy.coreutils.ImageUtils;
import org.sleuthkit.autopsy.coreutils.Logger;
import static org.sleuthkit.autopsy.coreutils.VideoUtils.getVideoFileInTempDir;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.filequery.FileSearchData.FileSize;
import org.sleuthkit.autopsy.filequery.FileSearchData.FileType;
import org.sleuthkit.autopsy.filequery.FileSearchData.Frequency;
import org.sleuthkit.autopsy.discovery.FileSearchData.FileSize;
import org.sleuthkit.autopsy.discovery.FileSearchData.FileType;
import org.sleuthkit.autopsy.discovery.FileSearchData.Frequency;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
@@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
@@ -28,7 +28,7 @@ import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.FileTypeUtils;
/**
* Utility enums for FileSearch
* Utility enums for FileSearch.
*/
final class FileSearchData {
@@ -250,11 +250,12 @@ final class FileSearchData {
}
/**
* Get the list of enums that are valid for image sizes.
* Get the list of enums that are valid for most file sizes.
*
* @return enums that can be used to filter images by size.
* @return Enums that can be used to filter most file including images
* by size.
*/
static List<FileSize> getOptionsForImages() {
static List<FileSize> getDefaultSizeOptions() {
return Arrays.asList(XXLARGE_IMAGE, XLARGE_IMAGE, LARGE_IMAGE, MEDIUM_IMAGE, SMALL_IMAGE, XSMALL_IMAGE);
}
@@ -268,7 +269,7 @@ final class FileSearchData {
}
}
//File discovery uses a different list of document mime types than FileTypeUtils.FileTypeCategory.DOCUMENTS
//Discovery uses a different list of document mime types than FileTypeUtils.FileTypeCategory.DOCUMENTS
private static final ImmutableSet<String> DOCUMENT_MIME_TYPES
= new ImmutableSet.Builder<String>()
.add("text/html", //NON-NLS
@@ -291,14 +292,15 @@ final class FileSearchData {
"application/vnd.oasis.opendocument.text" //NON-NLS
).build();
private static final ImmutableSet<String> IMAGE_UNSUPPORTED_DOC_TYPES
private static final ImmutableSet<String> IMAGE_UNSUPPORTED_DOC_TYPES
= new ImmutableSet.Builder<String>()
.add("application/pdf", //NON-NLS
"application/xhtml+xml").build(); //NON-NLS
static Collection<String> getDocTypesWithoutImageExtraction(){
return Collections.unmodifiableCollection(IMAGE_UNSUPPORTED_DOC_TYPES);
}
"application/xhtml+xml").build(); //NON-NLS
static Collection<String> getDocTypesWithoutImageExtraction() {
return Collections.unmodifiableCollection(IMAGE_UNSUPPORTED_DOC_TYPES);
}
/**
* Enum representing the file type. We don't simply use
* FileTypeUtils.FileTypeCategory because: - Some file types categories
@@ -16,30 +16,31 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
/**
* Exception type used for FileSearch
* Exception type used for FileSearch.
*/
public class FileSearchException extends Exception {
final public class FileSearchException extends Exception {
private static final long serialVersionUID = 1L;
/**
* Create exception from a string
*
* @param message
* Create exception from a string.
*
* @param message The message to associate with this exception.
*/
public FileSearchException(String message) {
FileSearchException(String message) {
super(message);
}
/**
* Create exception for a string and cause
*
* @param message
* @param cause
* Create exception for a string and cause.
*
* @param message The message to associate with this exception.
* @param cause The Throwable cause of the exception.
*/
public FileSearchException(String message, Throwable cause) {
FileSearchException(String message, Throwable cause) {
super(message, cause);
}
}
@@ -16,15 +16,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
import org.sleuthkit.autopsy.filequery.FileSearchData.FileSize;
import org.sleuthkit.autopsy.filequery.FileSearchData.FileType;
import org.sleuthkit.autopsy.filequery.FileSearchData.Frequency;
import org.sleuthkit.autopsy.filequery.FileSearchData.Score;
import org.sleuthkit.autopsy.discovery.FileSearchData.FileSize;
import org.sleuthkit.autopsy.discovery.FileSearchData.FileType;
import org.sleuthkit.autopsy.discovery.FileSearchData.Frequency;
import org.sleuthkit.autopsy.discovery.FileSearchData.Score;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.SleuthkitCase;
@@ -842,7 +842,8 @@ class FileSearchFiltering {
}
/**
* A filter for specifying that the file must have user content suspected data.
* A filter for specifying that the file must have user content suspected
* data.
*/
static class UserCreatedFilter extends FileFilter {
@@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import java.util.ArrayList;
import java.util.Arrays;
@@ -46,7 +46,7 @@
<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="Groups">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/filequery/Bundle.properties" key="GroupListPanel.groupKeyList.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="GroupListPanel.groupKeyList.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
@@ -16,23 +16,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import com.google.common.eventbus.Subscribe;
import java.awt.Cursor;
import java.util.List;
import java.util.Map;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.filequery.FileSearch.GroupKey;
import org.sleuthkit.autopsy.filequery.FileSearchData.FileType;
import org.sleuthkit.autopsy.discovery.FileSearch.GroupKey;
import org.sleuthkit.autopsy.discovery.FileSearchData.FileType;
/**
* Panel to display the list of groups which are provided by a search
* Panel to display the list of groups which are provided by a search.
*/
class GroupListPanel extends javax.swing.JPanel {
final class GroupListPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private FileType resultType = null;
@@ -44,16 +46,16 @@ class GroupListPanel extends javax.swing.JPanel {
private GroupKey selectedGroupKey;
/**
* Creates new form GroupListPanel
* Creates new form GroupListPanel.
*/
GroupListPanel() {
initComponents();
}
/**
* Subscribe to and reset the panel in response to SearchStartedEvents
* Subscribe to and reset the panel in response to SearchStartedEvents.
*
* @param searchStartedEvent the SearchStartedEvent which was received
* @param searchStartedEvent The SearchStartedEvent which was received.
*/
@Subscribe
void handleSearchStartedEvent(DiscoveryEventUtils.SearchStartedEvent searchStartedEvent) {
@@ -65,9 +67,9 @@ class GroupListPanel extends javax.swing.JPanel {
"GroupsListPanel.noResults.title.text=No results found"})
/**
* Subscribe to and update list of groups in response to
* SearchCompleteEvents
* SearchCompleteEvents.
*
* @param searchCompleteEvent the SearchCompleteEvent which was received
* @param searchCompleteEvent The SearchCompleteEvent which was received.
*/
@Subscribe
void handleSearchCompleteEvent(DiscoveryEventUtils.SearchCompleteEvent searchCompleteEvent) {
@@ -77,14 +79,29 @@ class GroupListPanel extends javax.swing.JPanel {
groupSort = searchCompleteEvent.getGroupSort();
fileSortMethod = searchCompleteEvent.getFileSort();
groupKeyList.setListData(groupMap.keySet().toArray(new GroupKey[groupMap.keySet().size()]));
if (groupKeyList.getModel().getSize() > 0) {
groupKeyList.setSelectedIndex(0);
} else {
JOptionPane.showMessageDialog(DiscoveryTopComponent.getTopComponent(),
Bundle.GroupsListPanel_noResults_message_text(),
Bundle.GroupsListPanel_noResults_title_text(),
JOptionPane.INFORMATION_MESSAGE);
}
SwingUtilities.invokeLater(() -> {
if (groupKeyList.getModel().getSize() > 0) {
groupKeyList.setSelectedIndex(0);
} else {
JOptionPane.showMessageDialog(DiscoveryTopComponent.getTopComponent(),
Bundle.GroupsListPanel_noResults_message_text(),
Bundle.GroupsListPanel_noResults_title_text(),
JOptionPane.INFORMATION_MESSAGE);
}
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
});
}
/**
* Subscribe to SearchCancelledEvent and reset the panel in response to it.
*
* @param searchCancelledEvent The SearchCancelledEvent which was received.
*/
@Subscribe
void handleSearchCancelledEvent(DiscoveryEventUtils.SearchCancelledEvent searchCancelledEvent) {
SwingUtilities.invokeLater(() -> {
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
});
}
/**
@@ -130,6 +147,9 @@ class GroupListPanel extends javax.swing.JPanel {
* Reset the group list to be empty.
*/
void resetGroupList() {
SwingUtilities.invokeLater(() -> {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
});
groupKeyList.setListData(new GroupKey[0]);
}
@@ -152,6 +172,7 @@ class GroupListPanel extends javax.swing.JPanel {
}
} else {
DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.NoResultsEvent());
}
}
}//GEN-LAST:event_groupSelected
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<NonVisualComponents>
<Component class="javax.swing.JCheckBox" name="hashSetCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="HashSetFilterPanel.hashSetCheckbox.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="[150, 25]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[150, 25]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[150, 25]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="hashSetCheckboxActionPerformed"/>
</Events>
</Component>
</NonVisualComponents>
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[250, 30]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[250, 30]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="hashSetScrollPane" alignment="0" pref="300" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="hashSetScrollPane" alignment="0" pref="60" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="hashSetScrollPane">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="hashSetList">
<Properties>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new DefaultListModel&lt;String&gt;()" type="code"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="visibleRowCount" type="int" value="3"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>
@@ -0,0 +1,170 @@
/*
* Autopsy
*
* Copyright 2020 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.discovery;
import java.util.List;
import java.util.logging.Level;
import javax.swing.DefaultListModel;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JList;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Panel for displaying the Hash Set filter controls.
*/
final class HashSetFilterPanel extends AbstractDiscoveryFilterPanel {
private static final long serialVersionUID = 1L;
private final static Logger logger = Logger.getLogger(HashSetFilterPanel.class.getName());
/**
* Creates new form HashSetFilterPaenl.
*/
HashSetFilterPanel() {
initComponents();
setUpHashFilter();
}
/**
* Initialize the hash filter.
*/
private void setUpHashFilter() {
int count = 0;
try {
DefaultListModel<String> hashListModel = (DefaultListModel<String>) hashSetList.getModel();
hashListModel.removeAllElements();
List<String> setNames = DiscoveryUiUtils.getSetNames(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT,
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME);
for (String name : setNames) {
hashListModel.add(count, name);
count++;
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error loading hash set names", ex);
hashSetCheckbox.setEnabled(false);
hashSetList.setEnabled(false);
}
}
/**
* 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() {
hashSetCheckbox = new javax.swing.JCheckBox();
hashSetScrollPane = new javax.swing.JScrollPane();
hashSetList = new javax.swing.JList<>();
org.openide.awt.Mnemonics.setLocalizedText(hashSetCheckbox, org.openide.util.NbBundle.getMessage(HashSetFilterPanel.class, "HashSetFilterPanel.hashSetCheckbox.text")); // NOI18N
hashSetCheckbox.setMaximumSize(new java.awt.Dimension(150, 25));
hashSetCheckbox.setMinimumSize(new java.awt.Dimension(150, 25));
hashSetCheckbox.setPreferredSize(new java.awt.Dimension(150, 25));
hashSetCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
hashSetCheckboxActionPerformed(evt);
}
});
setMinimumSize(new java.awt.Dimension(250, 30));
setPreferredSize(new java.awt.Dimension(250, 30));
hashSetList.setModel(new DefaultListModel<String>());
hashSetList.setEnabled(false);
hashSetList.setVisibleRowCount(3);
hashSetScrollPane.setViewportView(hashSetList);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(hashSetScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(hashSetScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 60, Short.MAX_VALUE)
);
}// </editor-fold>//GEN-END:initComponents
private void hashSetCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hashSetCheckboxActionPerformed
hashSetList.setEnabled(hashSetCheckbox.isSelected());
}//GEN-LAST:event_hashSetCheckboxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JCheckBox hashSetCheckbox;
private javax.swing.JList<String> hashSetList;
private javax.swing.JScrollPane hashSetScrollPane;
// End of variables declaration//GEN-END:variables
@Override
void configurePanel(boolean selected, int[] indicesSelected) {
boolean hasHashSets = hashSetList.getModel().getSize() > 0;
hashSetCheckbox.setEnabled(hasHashSets);
hashSetCheckbox.setSelected(selected && hasHashSets);
if (hashSetCheckbox.isEnabled() && hashSetCheckbox.isSelected()) {
hashSetScrollPane.setEnabled(true);
hashSetList.setEnabled(true);
if (indicesSelected != null) {
hashSetList.setSelectedIndices(indicesSelected);
}
} else {
hashSetScrollPane.setEnabled(false);
hashSetList.setEnabled(false);
}
}
@Override
JCheckBox getCheckbox() {
return hashSetCheckbox;
}
@Override
JLabel getAdditionalLabel() {
return null;
}
@Override
String checkForError() {
if (hashSetCheckbox.isSelected() && hashSetList.getSelectedValuesList().isEmpty()) {
return "At least one hash set name must be selected";
}
return "";
}
@Override
JList<?> getList() {
return hashSetList;
}
@Override
FileSearchFiltering.FileFilter getFilter() {
if (hashSetCheckbox.isSelected()) {
return new FileSearchFiltering.HashSetFilter(hashSetList.getSelectedValuesList());
}
return null;
}
}
@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,0,68,0,0,0,-31"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="imageFiltersScrollPane">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="Center"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="imageFiltersPanel">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
<Component id="imageFiltersSplitPane" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
<Component id="imageFiltersSplitPane" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JSplitPane" name="imageFiltersSplitPane">
<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="Step 2: Filter which images to show">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="ImageFilterPanel.imageFiltersSplitPane.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
<Property name="resizeWeight" type="double" value="0.5"/>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="ImageFilterPanel.imageFiltersSplitPane.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>
@@ -0,0 +1,106 @@
/*
* Autopsy
*
* Copyright 2020 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.discovery;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
/**
* Panel for displaying all the filters associated with the Image type.
*/
final class ImageFilterPanel extends AbstractFiltersPanel {
private static final long serialVersionUID = 1L;
private static final FileSearchData.FileType FILE_TYPE = FileSearchData.FileType.IMAGE;
/**
* Creates new form ImageFilterPanel.
*/
ImageFilterPanel() {
super();
initComponents();
SizeFilterPanel sizeFilterPanel = new SizeFilterPanel(FILE_TYPE);
int[] sizeIndicesSelected = {1, 2, 3, 4, 5};
addFilter(sizeFilterPanel, true, sizeIndicesSelected, 0);
addFilter(new DataSourceFilterPanel(), false, null, 0);
int[] pastOccurrencesIndices;
if (!CentralRepository.isEnabled()) {
pastOccurrencesIndices = new int[]{0};
} else {
pastOccurrencesIndices = new int[]{1, 2, 3, 4, 5, 6, 7};
}
addFilter(new PastOccurrencesFilterPanel(), true, pastOccurrencesIndices, 0);
addFilter(new UserCreatedFilterPanel(), false, null, 1);
addFilter(new HashSetFilterPanel(), false, null, 1);
addFilter(new InterestingItemsFilterPanel(), false, null, 1);
addFilter(new ObjectDetectedFilterPanel(), false, null, 1);
addFilter(new ParentFolderFilterPanel(), false, null, 1);
addPanelsToScrollPane(imageFiltersSplitPane);
}
/**
* 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() {
javax.swing.JScrollPane imageFiltersScrollPane = new javax.swing.JScrollPane();
javax.swing.JPanel imageFiltersPanel = new javax.swing.JPanel();
imageFiltersSplitPane = new javax.swing.JSplitPane();
setLayout(new java.awt.BorderLayout());
imageFiltersSplitPane.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(ImageFilterPanel.class, "ImageFilterPanel.imageFiltersSplitPane.border.title"))); // NOI18N
imageFiltersSplitPane.setResizeWeight(0.5);
imageFiltersSplitPane.setToolTipText(org.openide.util.NbBundle.getMessage(ImageFilterPanel.class, "ImageFilterPanel.imageFiltersSplitPane.toolTipText")); // NOI18N
javax.swing.GroupLayout imageFiltersPanelLayout = new javax.swing.GroupLayout(imageFiltersPanel);
imageFiltersPanel.setLayout(imageFiltersPanelLayout);
imageFiltersPanelLayout.setHorizontalGroup(
imageFiltersPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(imageFiltersPanelLayout.createSequentialGroup()
.addGap(8, 8, 8)
.addComponent(imageFiltersSplitPane)
.addGap(8, 8, 8))
);
imageFiltersPanelLayout.setVerticalGroup(
imageFiltersPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(imageFiltersPanelLayout.createSequentialGroup()
.addGap(8, 8, 8)
.addComponent(imageFiltersSplitPane)
.addGap(8, 8, 8))
);
imageFiltersScrollPane.setViewportView(imageFiltersPanel);
add(imageFiltersScrollPane, java.awt.BorderLayout.CENTER);
}// </editor-fold>//GEN-END:initComponents
@Override
FileSearchData.FileType getFileType() {
return FILE_TYPE;
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JSplitPane imageFiltersSplitPane;
// End of variables declaration//GEN-END:variables
}
@@ -102,16 +102,16 @@
<Image iconType="3" name="/org/sleuthkit/autopsy/images/file-icon-deleted.png"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/filequery/Bundle.properties" key="ImageThumbnailPanel.isDeletedLabel.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="ImageThumbnailPanel.isDeletedLabel.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())" type="code"/>
<Connection code="new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())" type="code"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())" type="code"/>
<Connection code="new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())" type="code"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())" type="code"/>
<Connection code="new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())" type="code"/>
</Property>
</Properties>
</Component>
@@ -122,13 +122,13 @@
</Property>
<Property name="toolTipText" type="java.lang.String" value=""/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())" type="code"/>
<Connection code="new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())" type="code"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())" type="code"/>
<Connection code="new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())" type="code"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())" type="code"/>
<Connection code="new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())" type="code"/>
</Property>
</Properties>
</Component>
@@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import java.awt.Color;
import java.awt.Component;
@@ -32,7 +32,7 @@ import org.openide.util.NbBundle;
/**
* Class which displays a thumbnail and information for an image file.
*/
public class ImageThumbnailPanel extends javax.swing.JPanel implements ListCellRenderer<ImageThumbnailWrapper> {
final class ImageThumbnailPanel extends javax.swing.JPanel implements ListCellRenderer<ImageThumbnailWrapper> {
private static final long serialVersionUID = 1L;
private static final Color SELECTION_COLOR = new Color(0, 120, 215);
@@ -41,7 +41,7 @@ public class ImageThumbnailPanel extends javax.swing.JPanel implements ListCellR
/**
* Creates new form ImageThumbnailPanel
*/
public ImageThumbnailPanel() {
ImageThumbnailPanel() {
initComponents();
}
@@ -76,15 +76,15 @@ public class ImageThumbnailPanel extends javax.swing.JPanel implements ListCellR
isDeletedLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/file-icon-deleted.png"))); // NOI18N
isDeletedLabel.setToolTipText(org.openide.util.NbBundle.getMessage(ImageThumbnailPanel.class, "ImageThumbnailPanel.isDeletedLabel.toolTipText")); // NOI18N
isDeletedLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize()));
isDeletedLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize()));
isDeletedLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize()));
isDeletedLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize()));
isDeletedLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize()));
isDeletedLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize()));
scoreLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/red-circle-exclamation.png"))); // NOI18N
scoreLabel.setToolTipText("");
scoreLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize()));
scoreLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize()));
scoreLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize()));
scoreLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize()));
scoreLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize()));
scoreLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize()));
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
@@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import java.util.ArrayList;
import java.util.List;
@@ -28,16 +28,16 @@ import org.sleuthkit.datamodel.AbstractFile;
* A JPanel to display image thumbnails.
*
*/
public class ImageThumbnailViewer extends javax.swing.JPanel {
final class ImageThumbnailViewer extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private final DefaultListModel<ImageThumbnailWrapper> thumbnailListModel = new DefaultListModel<>();
/**
* Creates new form ImageThumbnailViewer
* Creates new form ImageThumbnailViewer.
*/
public ImageThumbnailViewer() {
ImageThumbnailViewer() {
initComponents();
}
@@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import java.awt.Image;
import org.sleuthkit.autopsy.coreutils.ImageUtils;
@@ -25,7 +25,7 @@ import org.sleuthkit.autopsy.coreutils.ImageUtils;
* Class to wrap all the information necessary for an image thumbnail to be
* displayed.
*/
public class ImageThumbnailWrapper {
final class ImageThumbnailWrapper {
private Image thumbnail;
private final ResultFile resultFile;
@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<NonVisualComponents>
<Component class="javax.swing.JCheckBox" name="interestingItemsCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="InterestingItemsFilterPanel.interestingItemsCheckbox.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="[150, 25]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[150, 25]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[150, 25]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="interestingItemsCheckboxActionPerformed"/>
</Events>
</Component>
</NonVisualComponents>
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[250, 30]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[250, 30]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="interestingItemsScrollPane" pref="300" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="interestingItemsScrollPane" alignment="0" pref="88" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="interestingItemsScrollPane">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[27, 27]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="interestingItemsList">
<Properties>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new DefaultListModel&lt;String&gt;()" type="code"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="visibleRowCount" type="int" value="2"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>
@@ -0,0 +1,172 @@
/*
* Autopsy
*
* Copyright 2020 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.discovery;
import java.util.List;
import java.util.logging.Level;
import javax.swing.DefaultListModel;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JList;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Class to allow configuration of the Interesting Items filter.
*/
final class InterestingItemsFilterPanel extends AbstractDiscoveryFilterPanel {
private static final long serialVersionUID = 1L;
private final static Logger logger = Logger.getLogger(InterestingItemsFilterPanel.class.getName());
/**
* Creates new form InterestingItemsFilterPanel.
*/
InterestingItemsFilterPanel() {
initComponents();
setUpInterestingItemsFilter();
}
/**
* Initialize the interesting items filter.
*/
private void setUpInterestingItemsFilter() {
int count = 0;
try {
DefaultListModel<String> intListModel = (DefaultListModel<String>) interestingItemsList.getModel();
intListModel.removeAllElements();
List<String> setNames = DiscoveryUiUtils.getSetNames(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT,
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME);
for (String name : setNames) {
intListModel.add(count, name);
count++;
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error loading interesting file set names", ex);
interestingItemsCheckbox.setEnabled(false);
interestingItemsList.setEnabled(false);
}
}
/**
* 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() {
interestingItemsCheckbox = new javax.swing.JCheckBox();
interestingItemsScrollPane = new javax.swing.JScrollPane();
interestingItemsList = new javax.swing.JList<>();
org.openide.awt.Mnemonics.setLocalizedText(interestingItemsCheckbox, org.openide.util.NbBundle.getMessage(InterestingItemsFilterPanel.class, "InterestingItemsFilterPanel.interestingItemsCheckbox.text")); // NOI18N
interestingItemsCheckbox.setMaximumSize(new java.awt.Dimension(150, 25));
interestingItemsCheckbox.setMinimumSize(new java.awt.Dimension(150, 25));
interestingItemsCheckbox.setPreferredSize(new java.awt.Dimension(150, 25));
interestingItemsCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
interestingItemsCheckboxActionPerformed(evt);
}
});
setMinimumSize(new java.awt.Dimension(250, 30));
setPreferredSize(new java.awt.Dimension(250, 30));
interestingItemsScrollPane.setPreferredSize(new java.awt.Dimension(27, 27));
interestingItemsList.setModel(new DefaultListModel<String>());
interestingItemsList.setEnabled(false);
interestingItemsList.setVisibleRowCount(2);
interestingItemsScrollPane.setViewportView(interestingItemsList);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(interestingItemsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(interestingItemsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 88, Short.MAX_VALUE)
);
}// </editor-fold>//GEN-END:initComponents
private void interestingItemsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_interestingItemsCheckboxActionPerformed
interestingItemsList.setEnabled(interestingItemsCheckbox.isSelected());
}//GEN-LAST:event_interestingItemsCheckboxActionPerformed
@Override
void configurePanel(boolean selected, int[] indicesSelected) {
boolean hasInterestingItems = interestingItemsList.getModel().getSize() > 0;
interestingItemsCheckbox.setEnabled(hasInterestingItems);
interestingItemsCheckbox.setSelected(selected && hasInterestingItems);
if (interestingItemsCheckbox.isEnabled() && interestingItemsCheckbox.isSelected()) {
interestingItemsScrollPane.setEnabled(true);
interestingItemsList.setEnabled(true);
if (indicesSelected != null) {
interestingItemsList.setSelectedIndices(indicesSelected);
}
} else {
interestingItemsScrollPane.setEnabled(false);
interestingItemsList.setEnabled(false);
}
}
@Override
JCheckBox getCheckbox() {
return interestingItemsCheckbox;
}
@Override
JLabel getAdditionalLabel() {
return null;
}
@Override
String checkForError() {
if (interestingItemsCheckbox.isSelected() && interestingItemsList.getSelectedValuesList().isEmpty()) {
return "At least one interesting file set name must be selected";
}
return "";
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JCheckBox interestingItemsCheckbox;
private javax.swing.JList<String> interestingItemsList;
private javax.swing.JScrollPane interestingItemsScrollPane;
// End of variables declaration//GEN-END:variables
@Override
JList<?> getList() {
return interestingItemsList;
}
@Override
FileSearchFiltering.FileFilter getFilter() {
if (interestingItemsCheckbox.isSelected()) {
return new FileSearchFiltering.InterestingFileSetFilter(interestingItemsList.getSelectedValuesList());
}
return null;
}
}
@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<NonVisualComponents>
<Component class="javax.swing.JCheckBox" name="objectsCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="ObjectDetectedFilterPanel.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="[150, 25]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[150, 25]"/>
</Property>
<Property name="name" type="java.lang.String" value="" noResource="true"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[150, 25]"/>
</Property>
<Property name="verticalAlignment" type="int" value="1"/>
<Property name="verticalTextPosition" type="int" value="1"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="objectsCheckboxActionPerformed"/>
</Events>
</Component>
</NonVisualComponents>
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[250, 30]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[250, 30]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="objectsScrollPane" alignment="0" pref="300" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="objectsScrollPane" pref="64" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="objectsScrollPane">
<Properties>
<Property name="name" type="java.lang.String" value="" noResource="true"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[27, 27]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="objectsList">
<Properties>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new DefaultListModel&lt;String&gt;()" type="code"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[32767, 32767]"/>
</Property>
<Property name="visibleRowCount" type="int" value="2"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>
@@ -0,0 +1,177 @@
/*
* Autopsy
*
* Copyright 2020 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.discovery;
import java.util.List;
import java.util.logging.Level;
import javax.swing.DefaultListModel;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JList;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Class to allow configuration of the Objects Detected filter.
*/
final class ObjectDetectedFilterPanel extends AbstractDiscoveryFilterPanel {
private static final long serialVersionUID = 1L;
private final static Logger logger = Logger.getLogger(ObjectDetectedFilterPanel.class.getName());
/**
* Creates new form ObjectDetectedFilter.
*/
ObjectDetectedFilterPanel() {
initComponents();
setUpObjectFilter();
}
/**
* Initialize the object filter.
*/
private void setUpObjectFilter() {
int count = 0;
try {
DefaultListModel<String> objListModel = (DefaultListModel<String>) objectsList.getModel();
objListModel.removeAllElements();
List<String> setNames = DiscoveryUiUtils.getSetNames(BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION);
for (String name : setNames) {
objListModel.add(count, name);
count++;
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error loading object detected set names", ex);
objectsCheckbox.setEnabled(false);
objectsList.setEnabled(false);
}
}
/**
* 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() {
objectsCheckbox = new javax.swing.JCheckBox();
objectsScrollPane = new javax.swing.JScrollPane();
objectsList = new javax.swing.JList<>();
org.openide.awt.Mnemonics.setLocalizedText(objectsCheckbox, org.openide.util.NbBundle.getMessage(ObjectDetectedFilterPanel.class, "ObjectDetectedFilterPanel.text")); // NOI18N
objectsCheckbox.setMaximumSize(new java.awt.Dimension(150, 25));
objectsCheckbox.setMinimumSize(new java.awt.Dimension(150, 25));
objectsCheckbox.setName(""); // NOI18N
objectsCheckbox.setPreferredSize(new java.awt.Dimension(150, 25));
objectsCheckbox.setVerticalAlignment(javax.swing.SwingConstants.TOP);
objectsCheckbox.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
objectsCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
objectsCheckboxActionPerformed(evt);
}
});
setMinimumSize(new java.awt.Dimension(250, 30));
setPreferredSize(new java.awt.Dimension(250, 30));
objectsScrollPane.setName(""); // NOI18N
objectsScrollPane.setPreferredSize(new java.awt.Dimension(27, 27));
objectsList.setModel(new DefaultListModel<String>());
objectsList.setEnabled(false);
objectsList.setMaximumSize(new java.awt.Dimension(32767, 32767));
objectsList.setVisibleRowCount(2);
objectsScrollPane.setViewportView(objectsList);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(objectsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(objectsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 64, Short.MAX_VALUE)
);
}// </editor-fold>//GEN-END:initComponents
private void objectsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_objectsCheckboxActionPerformed
objectsList.setEnabled(objectsCheckbox.isSelected());
}//GEN-LAST:event_objectsCheckboxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JCheckBox objectsCheckbox;
private javax.swing.JList<String> objectsList;
private javax.swing.JScrollPane objectsScrollPane;
// End of variables declaration//GEN-END:variables
@Override
void configurePanel(boolean selected, int[] indicesSelected) {
boolean hasObjects = objectsList.getModel().getSize() > 0;
objectsCheckbox.setEnabled(hasObjects);
objectsCheckbox.setSelected(selected && hasObjects);
if (objectsCheckbox.isEnabled() && objectsCheckbox.isSelected()) {
objectsScrollPane.setEnabled(true);
objectsList.setEnabled(true);
if (indicesSelected != null) {
objectsList.setSelectedIndices(indicesSelected);
}
} else {
objectsScrollPane.setEnabled(false);
objectsList.setEnabled(false);
}
}
@Override
JCheckBox getCheckbox() {
return objectsCheckbox;
}
@Override
JLabel getAdditionalLabel() {
return null;
}
@Override
String checkForError() {
if (objectsCheckbox.isSelected() && objectsList.getSelectedValuesList().isEmpty()) {
return "At least one object type name must be selected";
}
return "";
}
@Override
JList<?> getList() {
return objectsList;
}
@Override
FileSearchFiltering.FileFilter getFilter() {
if (objectsCheckbox.isSelected()) {
return new FileSearchFiltering.ObjectDetectionFilter(objectsList.getSelectedValuesList());
}
return null;
}
}
@@ -0,0 +1,112 @@
/*
* Autopsy
*
* Copyright 2019-2020 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.discovery;
import java.awt.Component;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionReferences;
import org.openide.awt.ActionRegistration;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.util.actions.CallableSystemAction;
import org.openide.util.actions.Presenter;
import org.sleuthkit.autopsy.casemodule.Case;
/**
* Class to open the Discovery dialog. Allows the user to run searches and see
* results in the DiscoveryTopComponent.
*/
@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.newpackage.OpenDiscoveryAction")
@ActionReferences(value = {
@ActionReference(path = "Menu/Tools", position = 103)
,
@ActionReference(path = "Toolbars/Case", position = 105)})
@ActionRegistration(displayName = "#CTL_OpenDiscoveryAction", lazy = false)
@NbBundle.Messages({"CTL_OpenDiscoveryAction=Discovery"})
public final class OpenDiscoveryAction extends CallableSystemAction implements Presenter.Toolbar {
private static final String DISPLAY_NAME = Bundle.CTL_OpenDiscoveryAction();
private static final long serialVersionUID = 1L;
private final JButton toolbarButton = new JButton();
/**
* Construct a new OpenDiscoveryAction.
*/
public OpenDiscoveryAction() {
toolbarButton.addActionListener(OpenDiscoveryAction.this::actionPerformed);
this.setEnabled(false);
}
@Override
public boolean isEnabled() {
return Case.isCaseOpen();
}
@NbBundle.Messages({"OpenDiscoveryAction.resultsIncomplete.text=Results may be incomplete"})
@Override
public void performAction() {
final DiscoveryDialog discDialog = DiscoveryDialog.getDiscoveryDialogInstance();
discDialog.cancelSearch();
discDialog.setVisible(true);
DiscoveryUiUtils.displayErrorMessage(discDialog);
}
/**
* Returns the toolbar component of this action.
*
* @return The toolbar button
*/
@Override
public Component getToolbarPresenter() {
ImageIcon icon = new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/discovery-icon-24.png")); //NON-NLS
toolbarButton.setIcon(icon);
toolbarButton.setText(this.getName());
return toolbarButton;
}
/**
* Set this action to be enabled/disabled
*
* @param value whether to enable this action or not
*/
@Override
public void setEnabled(boolean value) {
super.setEnabled(value);
toolbarButton.setEnabled(value);
}
@Override
public String getName() {
return DISPLAY_NAME;
}
@Override
public HelpCtx getHelpCtx() {
return HelpCtx.DEFAULT_HELP;
}
@Override
public boolean asynchronous() {
return false; // run on edt
}
}
@@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import java.util.List;
import java.util.ArrayList;
@@ -24,7 +24,7 @@ import java.util.logging.Level;
import javax.swing.SwingWorker;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.filequery.FileSearch.GroupKey;
import org.sleuthkit.autopsy.discovery.FileSearch.GroupKey;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
/**
@@ -0,0 +1,224 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<NonVisualComponents>
<Component class="javax.swing.JCheckBox" name="parentCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="ParentFolderFilterPanel.parentCheckbox.text_1" 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="[150, 25]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[150, 25]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[150, 25]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="parentCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="parentLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="ParentFolderFilterPanel.parentLabel.text_1" 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="[150, 25]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[150, 25]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[150, 25]"/>
</Property>
</Properties>
</Component>
</NonVisualComponents>
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[250, 120]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[250, 120]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="includeRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="fullRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="substringRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="excludeRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Group type="103" alignment="0" groupAlignment="1" attributes="0">
<Component id="parentScrollPane" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="parentTextField" max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="deleteButton" min="-2" max="-2" attributes="0"/>
<Component id="addButton" min="-2" 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">
<Component id="parentScrollPane" max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="fullRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="substringRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="includeRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="excludeRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="deleteButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="parentTextField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="addButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="parentScrollPane">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[27, 27]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="parentList">
<Properties>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new DefaultListModel&lt;ParentSearchTerm&gt;()" type="code"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="visibleRowCount" type="int" value="4"/>
</Properties>
<Events>
<EventHandler event="valueChanged" listener="javax.swing.event.ListSelectionListener" parameters="javax.swing.event.ListSelectionEvent" handler="parentListValueChanged"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;ParentSearchTerm&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JRadioButton" name="fullRadioButton">
<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/discovery/Bundle.properties" key="ParentFolderFilterPanel.fullRadioButton.text_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JRadioButton" name="includeRadioButton">
<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/discovery/Bundle.properties" key="ParentFolderFilterPanel.includeRadioButton.text_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JRadioButton" name="substringRadioButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="ParentFolderFilterPanel.substringRadioButton.text_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JRadioButton" name="excludeRadioButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="ParentFolderFilterPanel.excludeRadioButton.text_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="deleteButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="ParentFolderFilterPanel.deleteButton.text_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[70, 23]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[70, 23]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[70, 23]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="deleteButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="addButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="ParentFolderFilterPanel.addButton.text_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[70, 23]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[70, 23]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[70, 23]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="addButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JTextField" name="parentTextField">
<Properties>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
</SubComponents>
</Form>
@@ -0,0 +1,306 @@
/*
* Autopsy
*
* Copyright 2020 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.discovery;
import java.util.ArrayList;
import java.util.List;
import javax.swing.DefaultListModel;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JList;
import org.sleuthkit.autopsy.discovery.FileSearchFiltering.ParentSearchTerm;
/**
* Panel to allow configuration of the Parent Folder filter.
*/
final class ParentFolderFilterPanel extends AbstractDiscoveryFilterPanel {
private static final long serialVersionUID = 1L;
private DefaultListModel<FileSearchFiltering.ParentSearchTerm> parentListModel;
private static final String[] DEFAULT_IGNORED_PATHS = {"/Windows/", "/Program Files/"}; //NON-NLS
/**
* Creates new form ParentFolderFilterPanel.
*/
ParentFolderFilterPanel() {
initComponents();
setUpParentPathFilter();
}
/**
* Initialize the parent path filter.
*/
private void setUpParentPathFilter() {
fullRadioButton.setSelected(true);
includeRadioButton.setSelected(true);
parentListModel = (DefaultListModel<FileSearchFiltering.ParentSearchTerm>) parentList.getModel();
for (String ignorePath : DEFAULT_IGNORED_PATHS) {
parentListModel.add(parentListModel.size(), new ParentSearchTerm(ignorePath, false, false));
}
}
/**
* 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() {
parentCheckbox = new javax.swing.JCheckBox();
parentLabel = new javax.swing.JLabel();
parentScrollPane = new javax.swing.JScrollPane();
parentList = new javax.swing.JList<>();
fullRadioButton = new javax.swing.JRadioButton();
includeRadioButton = new javax.swing.JRadioButton();
substringRadioButton = new javax.swing.JRadioButton();
excludeRadioButton = new javax.swing.JRadioButton();
deleteButton = new javax.swing.JButton();
addButton = new javax.swing.JButton();
parentTextField = new javax.swing.JTextField();
org.openide.awt.Mnemonics.setLocalizedText(parentCheckbox, org.openide.util.NbBundle.getMessage(ParentFolderFilterPanel.class, "ParentFolderFilterPanel.parentCheckbox.text_1")); // NOI18N
parentCheckbox.setMaximumSize(new java.awt.Dimension(150, 25));
parentCheckbox.setMinimumSize(new java.awt.Dimension(150, 25));
parentCheckbox.setPreferredSize(new java.awt.Dimension(150, 25));
parentCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
parentCheckboxActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(parentLabel, org.openide.util.NbBundle.getMessage(ParentFolderFilterPanel.class, "ParentFolderFilterPanel.parentLabel.text_1")); // NOI18N
parentLabel.setMaximumSize(new java.awt.Dimension(150, 25));
parentLabel.setMinimumSize(new java.awt.Dimension(150, 25));
parentLabel.setPreferredSize(new java.awt.Dimension(150, 25));
setMinimumSize(new java.awt.Dimension(250, 120));
setPreferredSize(new java.awt.Dimension(250, 120));
parentScrollPane.setPreferredSize(new java.awt.Dimension(27, 27));
parentList.setModel(new DefaultListModel<ParentSearchTerm>());
parentList.setEnabled(false);
parentList.setVisibleRowCount(4);
parentList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
parentListValueChanged(evt);
}
});
parentScrollPane.setViewportView(parentList);
fullRadioButton.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(fullRadioButton, org.openide.util.NbBundle.getMessage(ParentFolderFilterPanel.class, "ParentFolderFilterPanel.fullRadioButton.text_1")); // NOI18N
fullRadioButton.setEnabled(false);
includeRadioButton.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(includeRadioButton, org.openide.util.NbBundle.getMessage(ParentFolderFilterPanel.class, "ParentFolderFilterPanel.includeRadioButton.text_1")); // NOI18N
includeRadioButton.setEnabled(false);
org.openide.awt.Mnemonics.setLocalizedText(substringRadioButton, org.openide.util.NbBundle.getMessage(ParentFolderFilterPanel.class, "ParentFolderFilterPanel.substringRadioButton.text_1")); // NOI18N
substringRadioButton.setEnabled(false);
org.openide.awt.Mnemonics.setLocalizedText(excludeRadioButton, org.openide.util.NbBundle.getMessage(ParentFolderFilterPanel.class, "ParentFolderFilterPanel.excludeRadioButton.text_1")); // NOI18N
excludeRadioButton.setEnabled(false);
org.openide.awt.Mnemonics.setLocalizedText(deleteButton, org.openide.util.NbBundle.getMessage(ParentFolderFilterPanel.class, "ParentFolderFilterPanel.deleteButton.text_1")); // NOI18N
deleteButton.setEnabled(false);
deleteButton.setMaximumSize(new java.awt.Dimension(70, 23));
deleteButton.setMinimumSize(new java.awt.Dimension(70, 23));
deleteButton.setPreferredSize(new java.awt.Dimension(70, 23));
deleteButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
deleteButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(addButton, org.openide.util.NbBundle.getMessage(ParentFolderFilterPanel.class, "ParentFolderFilterPanel.addButton.text_1")); // NOI18N
addButton.setEnabled(false);
addButton.setMaximumSize(new java.awt.Dimension(70, 23));
addButton.setMinimumSize(new java.awt.Dimension(70, 23));
addButton.setPreferredSize(new java.awt.Dimension(70, 23));
addButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
addButtonActionPerformed(evt);
}
});
parentTextField.setEnabled(false);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(8, 8, 8)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(includeRadioButton)
.addComponent(fullRadioButton))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(substringRadioButton)
.addComponent(excludeRadioButton)))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(parentScrollPane, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addComponent(parentTextField)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(deleteButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(addButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(parentScrollPane, 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.BASELINE)
.addComponent(fullRadioButton)
.addComponent(substringRadioButton))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(includeRadioButton)
.addComponent(excludeRadioButton)
.addComponent(deleteButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(parentTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(addButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(0, 0, 0))
);
}// </editor-fold>//GEN-END:initComponents
private void parentCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_parentCheckboxActionPerformed
// parentFilterSettings(true, true, parentCheckbox.isSelected(), null);
}//GEN-LAST:event_parentCheckboxActionPerformed
private void parentListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_parentListValueChanged
if (parentList.getSelectedValuesList().isEmpty()) {
deleteButton.setEnabled(false);
} else {
deleteButton.setEnabled(true);
}
}//GEN-LAST:event_parentListValueChanged
private void deleteButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteButtonActionPerformed
int index = parentList.getSelectedIndex();
if (index >= 0) {
parentListModel.remove(index);
}
}//GEN-LAST:event_deleteButtonActionPerformed
private void addButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addButtonActionPerformed
if (!parentTextField.getText().isEmpty()) {
ParentSearchTerm searchTerm;
searchTerm = new ParentSearchTerm(parentTextField.getText(), fullRadioButton.isSelected(), includeRadioButton.isSelected());
parentListModel.add(parentListModel.size(), searchTerm);
parentTextField.setText("");
}
}//GEN-LAST:event_addButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton addButton;
private javax.swing.JButton deleteButton;
private javax.swing.JRadioButton excludeRadioButton;
private javax.swing.JRadioButton fullRadioButton;
private javax.swing.JRadioButton includeRadioButton;
private javax.swing.JCheckBox parentCheckbox;
private javax.swing.JLabel parentLabel;
private javax.swing.JList<ParentSearchTerm> parentList;
private javax.swing.JScrollPane parentScrollPane;
private javax.swing.JTextField parentTextField;
private javax.swing.JRadioButton substringRadioButton;
// End of variables declaration//GEN-END:variables
@Override
void configurePanel(boolean selected, int[] indicesSelected) {
parentCheckbox.setSelected(selected);
if (parentCheckbox.isEnabled() && parentCheckbox.isSelected()) {
parentScrollPane.setEnabled(true);
includeRadioButton.setEnabled(true);
excludeRadioButton.setEnabled(true);
fullRadioButton.setEnabled(true);
substringRadioButton.setEnabled(true);
addButton.setEnabled(true);
deleteButton.setEnabled(!parentListModel.isEmpty());
parentList.setEnabled(true);
parentTextField.setEnabled(true);
if (indicesSelected != null) {
parentList.setSelectedIndices(indicesSelected);
}
} else {
parentScrollPane.setEnabled(false);
parentList.setEnabled(false);
includeRadioButton.setEnabled(false);
excludeRadioButton.setEnabled(false);
fullRadioButton.setEnabled(false);
substringRadioButton.setEnabled(false);
addButton.setEnabled(false);
deleteButton.setEnabled(false);
parentTextField.setEnabled(false);
}
}
@Override
JCheckBox getCheckbox() {
return parentCheckbox;
}
@Override
JLabel getAdditionalLabel() {
return parentLabel;
}
@Override
String checkForError() {
// Parent uses everything in the box
if (parentCheckbox.isSelected() && getParentPaths().isEmpty()) {
return "At least one parent path must be entered";
}
return "";
}
/**
* Utility method to get the parent path objects out of the JList.
*
* @return The list of entered ParentSearchTerm objects
*/
private List<FileSearchFiltering.ParentSearchTerm> getParentPaths() {
List<FileSearchFiltering.ParentSearchTerm> results = new ArrayList<>();
for (int i = 0; i < parentListModel.getSize(); i++) {
results.add(parentListModel.get(i));
}
return results;
}
@Override
JList<?> getList() {
return parentList;
}
@Override
FileSearchFiltering.FileFilter getFilter() {
if (parentCheckbox.isSelected()) {
return new FileSearchFiltering.ParentFilter(getParentPaths());
}
return null;
}
}
@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<NonVisualComponents>
<Component class="javax.swing.JCheckBox" name="pastOccurrencesCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="PastOccurrencesFilterPanel.pastOccurrencesCheckbox.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="[150, 25]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[150, 25]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[150, 25]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="pastOccurrencesCheckboxActionPerformed"/>
</Events>
</Component>
</NonVisualComponents>
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[250, 30]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[250, 30]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="crFrequencyScrollPane" pref="300" 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="crFrequencyScrollPane" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="crFrequencyScrollPane">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[27, 27]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="crFrequencyList">
<Properties>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new DefaultListModel&lt;Frequency&gt;()" type="code"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="visibleRowCount" type="int" value="5"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;Frequency&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>
@@ -0,0 +1,163 @@
/*
* Autopsy
*
* Copyright 2020 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.discovery;
import javax.swing.DefaultListModel;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JList;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import org.sleuthkit.autopsy.discovery.FileSearchData.Frequency;
/**
* Panel to allow configuration of the Past Occurrences filter.
*/
final class PastOccurrencesFilterPanel extends AbstractDiscoveryFilterPanel {
private static final long serialVersionUID = 1L;
/**
* Creates new form PastOccurrencesFilterPanel.
*/
PastOccurrencesFilterPanel() {
initComponents();
setUpFrequencyFilter();
}
/**
* 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() {
pastOccurrencesCheckbox = new javax.swing.JCheckBox();
crFrequencyScrollPane = new javax.swing.JScrollPane();
crFrequencyList = new javax.swing.JList<>();
org.openide.awt.Mnemonics.setLocalizedText(pastOccurrencesCheckbox, org.openide.util.NbBundle.getMessage(PastOccurrencesFilterPanel.class, "PastOccurrencesFilterPanel.pastOccurrencesCheckbox.text")); // NOI18N
pastOccurrencesCheckbox.setMaximumSize(new java.awt.Dimension(150, 25));
pastOccurrencesCheckbox.setMinimumSize(new java.awt.Dimension(150, 25));
pastOccurrencesCheckbox.setPreferredSize(new java.awt.Dimension(150, 25));
pastOccurrencesCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
pastOccurrencesCheckboxActionPerformed(evt);
}
});
setMinimumSize(new java.awt.Dimension(250, 30));
setPreferredSize(new java.awt.Dimension(250, 30));
crFrequencyScrollPane.setPreferredSize(new java.awt.Dimension(27, 27));
crFrequencyList.setModel(new DefaultListModel<Frequency>());
crFrequencyList.setEnabled(false);
crFrequencyList.setVisibleRowCount(5);
crFrequencyScrollPane.setViewportView(crFrequencyList);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(crFrequencyScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(crFrequencyScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGap(0, 0, 0))
);
}// </editor-fold>//GEN-END:initComponents
private void pastOccurrencesCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pastOccurrencesCheckboxActionPerformed
crFrequencyList.setEnabled(pastOccurrencesCheckbox.isSelected());
}//GEN-LAST:event_pastOccurrencesCheckboxActionPerformed
/**
* Initialize the frequency filter.
*/
private void setUpFrequencyFilter() {
int count = 0;
DefaultListModel<FileSearchData.Frequency> frequencyListModel = (DefaultListModel<FileSearchData.Frequency>) crFrequencyList.getModel();
frequencyListModel.removeAllElements();
if (!CentralRepository.isEnabled()) {
for (FileSearchData.Frequency freq : FileSearchData.Frequency.getOptionsForFilteringWithoutCr()) {
frequencyListModel.add(count, freq);
}
} else {
for (FileSearchData.Frequency freq : FileSearchData.Frequency.getOptionsForFilteringWithCr()) {
frequencyListModel.add(count, freq);
}
}
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JList<Frequency> crFrequencyList;
private javax.swing.JScrollPane crFrequencyScrollPane;
private javax.swing.JCheckBox pastOccurrencesCheckbox;
// End of variables declaration//GEN-END:variables
@Override
void configurePanel(boolean selected, int[] indicesSelected) {
pastOccurrencesCheckbox.setSelected(selected);
if (pastOccurrencesCheckbox.isEnabled() && pastOccurrencesCheckbox.isSelected()) {
crFrequencyScrollPane.setEnabled(true);
crFrequencyList.setEnabled(true);
if (indicesSelected != null) {
crFrequencyList.setSelectedIndices(indicesSelected);
}
} else {
crFrequencyScrollPane.setEnabled(false);
crFrequencyList.setEnabled(false);
}
}
@Override
JCheckBox getCheckbox() {
return pastOccurrencesCheckbox;
}
@Override
JLabel getAdditionalLabel() {
return null;
}
@Override
String checkForError() {
if (pastOccurrencesCheckbox.isSelected() && crFrequencyList.getSelectedValuesList().isEmpty()) {
return "At least one value in the past occurrence filter must be selected";
}
return "";
}
@Override
JList<?> getList() {
return crFrequencyList;
}
@Override
FileSearchFiltering.FileFilter getFilter() {
if (pastOccurrencesCheckbox.isSelected()) {
return new FileSearchFiltering.FrequencyFilter(crFrequencyList.getSelectedValuesList());
}
return null;
}
}
@@ -16,9 +16,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import org.sleuthkit.autopsy.filequery.FileSearchData.FileType;
import org.sleuthkit.autopsy.discovery.FileSearchData.FileType;
import org.sleuthkit.datamodel.AbstractFile;
import java.util.ArrayList;
import java.util.Collections;
@@ -37,7 +37,7 @@ import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/**
* Container for files that holds all necessary data for grouping and sorting
* Container for files that holds all necessary data for grouping and sorting.
*/
class ResultFile {
@@ -2,8 +2,11 @@
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[700, 200]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[777, 475]"/>
<Dimension value="[700, 700]"/>
</Property>
</Properties>
<AuxValues>
@@ -16,26 +19,10 @@
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="pagingPanel" pref="0" max="32767" attributes="0"/>
<Component id="resultsSplitPane" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Component id="pagingPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Component id="resultsSplitPane" pref="436" max="32767" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="pagingPanel">
<Properties>
@@ -44,11 +31,22 @@
<EtchetBorder/>
</Border>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[400, 39]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[700, 39]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="First"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
@@ -81,7 +79,7 @@
<Component class="javax.swing.JLabel" name="currentPageLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/filequery/Bundle.properties" key="ResultsPanel.currentPageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="ResultsPanel.currentPageLabel.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="[190, 23]"/>
@@ -129,7 +127,7 @@
<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/filequery/Bundle.properties" key="ResultsPanel.pageControlsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="ResultsPanel.pageControlsLabel.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="[133, 23]"/>
@@ -155,7 +153,7 @@
<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/filequery/Bundle.properties" key="ResultsPanel.gotoPageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="ResultsPanel.gotoPageLabel.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="[170, 23]"/>
@@ -180,6 +178,10 @@
<Component class="javax.swing.JTextField" name="gotoPageField">
<Properties>
<Property name="enabled" type="boolean" value="false"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[30, 22]"/>
</Property>
<Property name="name" type="java.lang.String" value="" noResource="true"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[26, 22]"/>
</Property>
@@ -197,7 +199,7 @@
<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/filequery/Bundle.properties" key="ResultsPanel.pageSizeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="ResultsPanel.pageSizeLabel.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="[160, 23]"/>
@@ -310,120 +312,22 @@
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JSplitPane" name="resultsSplitPane">
<Container class="javax.swing.JPanel" name="resultsViewerPanel">
<Properties>
<Property name="dividerLocation" type="int" value="380"/>
<Property name="orientation" type="int" value="0"/>
<Property name="resizeWeight" type="double" value="1.0"/>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/filequery/Bundle.properties" key="ResultsPanel.resultsSplitPane.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 160]"/>
</Property>
<Property name="lastDividerLocation" type="int" value="180"/>
<Property name="opaque" type="boolean" value="false"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[777, 440]"/>
<Dimension value="[700, 700]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="Center"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="instancesPanel">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[775, 68]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
<JSplitPaneConstraints position="right"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="779" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Component id="instancesScrollPane" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="68" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Component id="instancesScrollPane" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="instancesScrollPane">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[775, 60]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="instancesList">
<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="Instances">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/filequery/Bundle.properties" key="ResultsPanel.instancesList.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="instancesListModel" type="code"/>
</Property>
<Property name="selectionMode" type="int" value="0"/>
<Property name="cellRenderer" type="javax.swing.ListCellRenderer" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new InstancesCellRenderer()" type="code"/>
</Property>
<Property name="visibleRowCount" type="int" value="2"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;AbstractFile&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="resultsViewerPanel">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 380]"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
<JSplitPaneConstraints position="left"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
</Container>
</SubComponents>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
</Container>
</SubComponents>
</Form>
@@ -16,52 +16,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import com.google.common.eventbus.Subscribe;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Image;
import java.awt.event.ItemEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.event.ListSelectionListener;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
import org.sleuthkit.autopsy.coreutils.ImageUtils;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction;
import org.sleuthkit.autopsy.filequery.FileSearch.GroupKey;
import org.sleuthkit.autopsy.modules.hashdatabase.AddContentToHashDbAction;
import org.sleuthkit.autopsy.discovery.FileSearch.GroupKey;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import org.sleuthkit.autopsy.textsummarizer.TextSummary;
/**
* Panel for displaying of file discovery results and handling the paging of
* those results.
* Panel for displaying of Discovery results and handling the paging of those
* results.
*/
public class ResultsPanel extends javax.swing.JPanel {
final class ResultsPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private final static Logger logger = Logger.getLogger(ResultsPanel.class.getName());
@@ -79,15 +62,13 @@ public class ResultsPanel extends javax.swing.JPanel {
private int groupSize = 0;
private PageWorker pageWorker;
private final List<SwingWorker<Void, Void>> resultContentWorkers = new ArrayList<>();
private final DefaultListModel<AbstractFile> instancesListModel = new DefaultListModel<>();
private ListSelectionListener listener = null;
/**
* Creates new form ResultsPanel.
*/
@Messages({"ResultsPanel.viewFileInDir.name=View File in Directory",
"ResultsPanel.openInExternalViewer.name=Open in External Viewer"})
public ResultsPanel() {
ResultsPanel() {
initComponents();
imageThumbnailViewer = new ImageThumbnailViewer();
videoThumbnailViewer = new VideoThumbnailViewer();
@@ -95,103 +76,37 @@ public class ResultsPanel extends javax.swing.JPanel {
videoThumbnailViewer.addListSelectionListener((e) -> {
if (resultType == FileSearchData.FileType.VIDEO) {
if (!e.getValueIsAdjusting()) {
populateInstancesList();
//send populateMesage
DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.PopulateInstancesListEvent(getInstancesForSelected()));
} else {
instancesList.clearSelection();
//send clearSelection message
DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.ClearInstanceSelectionEvent());
}
}
});
imageThumbnailViewer.addListSelectionListener((e) -> {
if (resultType == FileSearchData.FileType.IMAGE) {
if (!e.getValueIsAdjusting()) {
populateInstancesList();
//send populateMesage
DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.PopulateInstancesListEvent(getInstancesForSelected()));
} else {
instancesList.clearSelection();
//send clearSelection message
DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.ClearInstanceSelectionEvent());
}
}
});
documentPreviewViewer.addListSelectionListener((e) -> {
if (resultType == FileSearchData.FileType.DOCUMENTS) {
if (!e.getValueIsAdjusting()) {
populateInstancesList();
//send populateMesage
DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.PopulateInstancesListEvent(getInstancesForSelected()));
} else {
instancesList.clearSelection();
//send clearSelection message
DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.ClearInstanceSelectionEvent());
}
}
});
//Add the context menu when right clicking
instancesList.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
SwingUtilities.invokeLater(() -> {
instancesList.setSelectedIndex(instancesList.locationToIndex(e.getPoint()));
Set<AbstractFile> files = new HashSet<>();
files.add(instancesList.getSelectedValue());
JPopupMenu menu = new JPopupMenu();
menu.add(new ViewContextAction(Bundle.ResultsPanel_viewFileInDir_name(), instancesList.getSelectedValue()));
menu.add(new ExternalViewerAction(Bundle.ResultsPanel_openInExternalViewer_name(), new FileNode(instancesList.getSelectedValue())));
menu.add(ViewFileInTimelineAction.createViewFileAction(instancesList.getSelectedValue()));
menu.add(new DiscoveryExtractAction(files));
menu.add(AddContentTagAction.getInstance().getMenuForContent(files));
menu.add(DeleteFileContentTagAction.getInstance().getMenuForFiles(files));
menu.add(AddContentToHashDbAction.getInstance().getMenuForFiles(files));
menu.show(instancesList, e.getPoint().x, e.getPoint().y);
});
}
}
});
}
/**
* Add a list selection listener to the instances list.
*
* @param listener The ListSelectionListener to add to the instances list.
*/
void addListSelectionListener(ListSelectionListener newListener) {
instancesList.removeListSelectionListener(listener);
listener = newListener;
instancesList.addListSelectionListener(listener);
}
/**
* Populate the instances list.
*/
synchronized void populateInstancesList() {
SwingUtilities.invokeLater(() -> {
List<AbstractFile> files = getInstancesForSelected();
if (files.isEmpty()) {
//if there are no files currently remove the current items without removing listener to cause content viewer to reset
instancesListModel.removeAllElements();
} else {
//remove listener so content viewer node is not set multiple times
instancesList.removeListSelectionListener(listener);
instancesListModel.removeAllElements();
for (AbstractFile file : files) {
instancesListModel.addElement(file);
}
//add listener back to allow selection of first index to cause content viewer node to be set
instancesList.addListSelectionListener(listener);
if (!instancesListModel.isEmpty()) {
instancesList.setSelectedIndex(0);
}
}
});
}
/**
* Get the AbstractFile for the item currently selected in the instances
* list.
*
* @return The AbstractFile which is currently selected.
*/
synchronized AbstractFile getSelectedFile() {
if (instancesList.getSelectedIndex() == -1) {
return null;
} else {
return instancesListModel.getElementAt(instancesList.getSelectedIndex());
}
}
/**
@@ -217,6 +132,18 @@ public class ResultsPanel extends javax.swing.JPanel {
return new ArrayList<>();
}
/**
* Subscribe to and reset the panel in response to SearchStartedEvents.
*
* @param searchStartedEvent The SearchStartedEvent which was received.
*/
@Subscribe
void handleSearchStartedEvent(DiscoveryEventUtils.SearchStartedEvent searchStartedEvent) {
SwingUtilities.invokeLater(() -> {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
});
}
/**
* Subscribe and respond to PageRetrievedEvents.
*
@@ -225,7 +152,9 @@ public class ResultsPanel extends javax.swing.JPanel {
@Subscribe
void handlePageRetrievedEvent(DiscoveryEventUtils.PageRetrievedEvent pageRetrievedEvent) {
SwingUtilities.invokeLater(() -> {
populateInstancesList();
//send populateMesage
DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.PopulateInstancesListEvent(getInstancesForSelected()));
currentPage = pageRetrievedEvent.getPageNumber();
updateControls();
resetResultViewer();
@@ -358,13 +287,27 @@ public class ResultsPanel extends javax.swing.JPanel {
});
}
/**
* Subscribe to and update cursor in response to SearchCompleteEvents.
*
* @param searchCompleteEvent The SearchCompleteEvent which was received.
*/
@Subscribe
void handleSearchCompleteEvent(DiscoveryEventUtils.SearchCompleteEvent searchCompleteEvent) {
SwingUtilities.invokeLater(() -> {
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
});
}
/**
* Set the page number and retrieve its contents.
*
* @param startingEntry The index of the first file in the group to include
* in this page.
*/
private synchronized void setPage(int startingEntry) {
@Subscribe
private synchronized void setPage(int startingEntry
) {
int pageSize = pageSizeComboBox.getItemAt(pageSizeComboBox.getSelectedIndex());
synchronized (this) {
if (pageWorker != null && !pageWorker.isDone()) {
@@ -376,11 +319,17 @@ public class ResultsPanel extends javax.swing.JPanel {
centralRepo = CentralRepository.getInstance();
} catch (CentralRepoException ex) {
centralRepo = null;
logger.log(Level.SEVERE, "Error loading central repository database, no central repository options will be available for File Discovery", ex);
logger.log(Level.SEVERE, "Error loading central repository database, no central repository options will be available for Discovery", ex);
}
}
pageWorker = new PageWorker(searchFilters, groupingAttribute, groupSort, fileSortMethod, selectedGroupKey, startingEntry, pageSize, resultType, centralRepo);
pageWorker.execute();
if (groupSize != 0) {
pageWorker = new PageWorker(searchFilters, groupingAttribute, groupSort, fileSortMethod, selectedGroupKey, startingEntry, pageSize, resultType, centralRepo);
pageWorker.execute();
} else {
SwingUtilities.invokeLater(() -> {
pageSizeComboBox.setEnabled(true);
});
}
}
}
@@ -425,15 +374,15 @@ public class ResultsPanel extends javax.swing.JPanel {
javax.swing.Box.Filler filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0));
javax.swing.Box.Filler filler3 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0));
javax.swing.Box.Filler filler4 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0));
javax.swing.JSplitPane resultsSplitPane = new javax.swing.JSplitPane();
javax.swing.JPanel instancesPanel = new javax.swing.JPanel();
javax.swing.JScrollPane instancesScrollPane = new javax.swing.JScrollPane();
instancesList = new javax.swing.JList<>();
resultsViewerPanel = new javax.swing.JPanel();
setPreferredSize(new java.awt.Dimension(777, 475));
setMinimumSize(new java.awt.Dimension(700, 200));
setPreferredSize(new java.awt.Dimension(700, 700));
setLayout(new java.awt.BorderLayout());
pagingPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
pagingPanel.setMinimumSize(new java.awt.Dimension(400, 39));
pagingPanel.setPreferredSize(new java.awt.Dimension(700, 39));
pagingPanel.setLayout(new java.awt.GridBagLayout());
previousPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); // NOI18N
@@ -516,6 +465,8 @@ public class ResultsPanel extends javax.swing.JPanel {
pagingPanel.add(gotoPageLabel, gridBagConstraints);
gotoPageField.setEnabled(false);
gotoPageField.setMinimumSize(new java.awt.Dimension(30, 22));
gotoPageField.setName(""); // NOI18N
gotoPageField.setPreferredSize(new java.awt.Dimension(26, 22));
gotoPageField.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
@@ -580,63 +531,12 @@ public class ResultsPanel extends javax.swing.JPanel {
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
pagingPanel.add(filler4, gridBagConstraints);
resultsSplitPane.setDividerLocation(380);
resultsSplitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
resultsSplitPane.setResizeWeight(1.0);
resultsSplitPane.setToolTipText(org.openide.util.NbBundle.getMessage(ResultsPanel.class, "ResultsPanel.resultsSplitPane.toolTipText")); // NOI18N
resultsSplitPane.setLastDividerLocation(180);
resultsSplitPane.setOpaque(false);
resultsSplitPane.setPreferredSize(new java.awt.Dimension(777, 440));
add(pagingPanel, java.awt.BorderLayout.PAGE_START);
instancesPanel.setPreferredSize(new java.awt.Dimension(775, 68));
instancesScrollPane.setPreferredSize(new java.awt.Dimension(775, 60));
instancesList.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(ResultsPanel.class, "ResultsPanel.instancesList.border.title"))); // NOI18N
instancesList.setModel(instancesListModel);
instancesList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
instancesList.setCellRenderer(new InstancesCellRenderer());
instancesList.setVisibleRowCount(2);
instancesScrollPane.setViewportView(instancesList);
javax.swing.GroupLayout instancesPanelLayout = new javax.swing.GroupLayout(instancesPanel);
instancesPanel.setLayout(instancesPanelLayout);
instancesPanelLayout.setHorizontalGroup(
instancesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 779, Short.MAX_VALUE)
.addGroup(instancesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(instancesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
instancesPanelLayout.setVerticalGroup(
instancesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 68, Short.MAX_VALUE)
.addGroup(instancesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, instancesPanelLayout.createSequentialGroup()
.addGap(0, 0, 0)
.addComponent(instancesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
);
resultsSplitPane.setRightComponent(instancesPanel);
resultsViewerPanel.setPreferredSize(new java.awt.Dimension(0, 380));
resultsViewerPanel.setMinimumSize(new java.awt.Dimension(0, 160));
resultsViewerPanel.setPreferredSize(new java.awt.Dimension(700, 700));
resultsViewerPanel.setLayout(new java.awt.BorderLayout());
resultsSplitPane.setLeftComponent(resultsViewerPanel);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(pagingPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
.addComponent(resultsSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(pagingPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0)
.addComponent(resultsSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 436, Short.MAX_VALUE)
.addGap(0, 0, 0))
);
add(resultsViewerPanel, java.awt.BorderLayout.CENTER);
}// </editor-fold>//GEN-END:initComponents
/**
@@ -719,7 +619,6 @@ public class ResultsPanel extends javax.swing.JPanel {
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel currentPageLabel;
private javax.swing.JTextField gotoPageField;
private javax.swing.JList<AbstractFile> instancesList;
private javax.swing.JButton nextPageButton;
private javax.swing.JComboBox<Integer> pageSizeComboBox;
private javax.swing.JButton previousPageButton;
@@ -853,29 +752,4 @@ public class ResultsPanel extends javax.swing.JPanel {
}
/**
* Cell renderer for the instances list.
*/
private class InstancesCellRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = 1L;
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
String name = "";
if (value instanceof AbstractFile) {
AbstractFile file = (AbstractFile) value;
try {
name = file.getUniquePath();
} catch (TskCoreException ingored) {
name = file.getParentPath() + "/" + file.getName();
}
}
setText(name);
return this;
}
}
}
@@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import java.util.ArrayList;
import java.util.Collections;
@@ -25,10 +25,10 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.sleuthkit.autopsy.filequery.FileSearch.GroupKey;
import org.sleuthkit.autopsy.discovery.FileSearch.GroupKey;
/**
* Class to hold the results of the filtering/grouping/sorting operations
* Class to hold the results of the filtering/grouping/sorting operations.
*/
class SearchResults {
@@ -42,13 +42,13 @@ class SearchResults {
private static final long MAX_OUTPUT_FILES = 2000; // For debug UI - maximum number of lines to print
/**
* Create an empty SearchResults object
* Create an empty SearchResults object.
*
* @param groupSortingType The method that should be used to
* sortGroupsAndFiles the groups
* @param attrType The attribute type to use for grouping
* sortGroupsAndFiles the groups.
* @param attrType The attribute type to use for grouping.
* @param fileSortingMethod The method that should be used to
* sortGroupsAndFiles the files in each group
* sortGroupsAndFiles the files in each group.
*/
SearchResults(FileGroup.GroupSortingAlgorithm groupSortingType, FileSearch.AttributeType attrType,
FileSorter.SortingMethod fileSortingMethod) {
@@ -68,9 +68,9 @@ class SearchResults {
}
/**
* Add a list of ResultFile to the results
* Add a list of ResultFile to the results.
*
* @param files the ResultFiles
* @param files The list of ResultFiles to add.
*/
void add(List<ResultFile> files) {
for (ResultFile file : files) {
@@ -124,20 +124,20 @@ class SearchResults {
}
/**
* Get the names of the groups with counts
* Get the names of the groups with counts.
*
* @return the group names
* @return The list of group names.
*/
List<String> getGroupNamesWithCounts() {
return groupList.stream().map(p -> p.getDisplayName() + " (" + p.getFiles().size() + ")").collect(Collectors.toList());
}
/**
* Get the result files for the selected group
* Get the result files for the selected group.
*
* @param groupName The name of the group. Can have the size appended.
*
* @return the list of result files
* @return The list of result files.
*/
List<ResultFile> getResultFilesInGroup(String groupName) {
if (groupName != null) {
@@ -154,7 +154,7 @@ class SearchResults {
/**
* Transform the results into a LinkedHashMap with result files.
*
* @return the grouped and sorted results
* @return The grouped and sorted results.
*/
Map<GroupKey, List<ResultFile>> toLinkedHashMap() throws FileSearchException {
Map<GroupKey, List<ResultFile>> map = new LinkedHashMap<>();
@@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import java.util.LinkedHashMap;
import javax.swing.SwingWorker;
@@ -25,11 +25,11 @@ import java.util.Map;
import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.filequery.FileSearch.GroupKey;
import org.sleuthkit.autopsy.discovery.FileSearch.GroupKey;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
/**
* SwingWorker to perform search on a background thread
* SwingWorker to perform search on a background thread.
*/
final class SearchWorker extends SwingWorker<Void, Void> {
@@ -43,13 +43,14 @@ final class SearchWorker extends SwingWorker<Void, Void> {
private final Map<GroupKey, Integer> results = new LinkedHashMap<>();
/**
* Create a SwingWorker which performs a search
* Create a SwingWorker which performs a search.
*
* @param centralRepo the central repository being used for the search
* @param searchfilters the FileFilters to use for the search
* @param groupingAttribute the AttributeType to group by
* @param groupSort the Algorithm to sort groups by
* @param fileSortMethod the SortingMethod to use for files
* @param centralRepo The central repository being used for the
* search.
* @param searchfilters The FileFilters to use for the search.
* @param groupingAttribute The AttributeType to group by.
* @param groupSort The Algorithm to sort groups by.
* @param fileSortMethod The SortingMethod to use for files.
*/
SearchWorker(CentralRepository centralRepo, List<FileSearchFiltering.FileFilter> searchfilters, FileSearch.AttributeType groupingAttribute, FileGroup.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod) {
centralRepoDb = centralRepo;
@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<NonVisualComponents>
<Component class="javax.swing.JCheckBox" name="sizeCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="SizeFilterPanel.sizeCheckbox.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="[150, 25]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[150, 25]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[150, 25]"/>
</Property>
<Property name="verticalAlignment" type="int" value="1"/>
<Property name="verticalTextPosition" type="int" value="1"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="sizeCheckboxActionPerformed"/>
</Events>
</Component>
</NonVisualComponents>
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[250, 30]"/>
</Property>
<Property name="name" type="java.lang.String" value="" noResource="true"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[250, 30]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="sizeScrollPane" 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="sizeScrollPane" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="sizeScrollPane">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[27, 27]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="sizeList">
<Properties>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new DefaultListModel&lt;FileSize&gt;()" type="code"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[32767, 32767]"/>
</Property>
<Property name="visibleRowCount" type="int" value="5"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;FileSize&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>
@@ -0,0 +1,187 @@
/*
* Autopsy
*
* Copyright 2020 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.discovery;
import java.util.ArrayList;
import java.util.List;
import javax.swing.DefaultListModel;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JList;
import org.sleuthkit.autopsy.discovery.FileSearchData.FileSize;
/**
* Panel to allow configuration of the Size Filter.
*/
final class SizeFilterPanel extends AbstractDiscoveryFilterPanel {
private static final long serialVersionUID = 1L;
/**
* Creates new form SizeFilterPanel.
*
* @param type The type of result being searched for.
*/
SizeFilterPanel(FileSearchData.FileType type) {
initComponents();
setUpSizeFilter(type);
}
/**
* 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() {
sizeCheckbox = new javax.swing.JCheckBox();
sizeScrollPane = new javax.swing.JScrollPane();
sizeList = new javax.swing.JList<>();
org.openide.awt.Mnemonics.setLocalizedText(sizeCheckbox, org.openide.util.NbBundle.getMessage(SizeFilterPanel.class, "SizeFilterPanel.sizeCheckbox.text")); // NOI18N
sizeCheckbox.setMaximumSize(new java.awt.Dimension(150, 25));
sizeCheckbox.setMinimumSize(new java.awt.Dimension(150, 25));
sizeCheckbox.setPreferredSize(new java.awt.Dimension(150, 25));
sizeCheckbox.setVerticalAlignment(javax.swing.SwingConstants.TOP);
sizeCheckbox.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
sizeCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
sizeCheckboxActionPerformed(evt);
}
});
setMinimumSize(new java.awt.Dimension(250, 30));
setName(""); // NOI18N
setPreferredSize(new java.awt.Dimension(250, 30));
sizeScrollPane.setPreferredSize(new java.awt.Dimension(27, 27));
sizeList.setModel(new DefaultListModel<FileSize>());
sizeList.setEnabled(false);
sizeList.setMaximumSize(new java.awt.Dimension(32767, 32767));
sizeList.setVisibleRowCount(5);
sizeScrollPane.setViewportView(sizeList);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(sizeScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(sizeScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGap(0, 0, 0))
);
}// </editor-fold>//GEN-END:initComponents
private void sizeCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sizeCheckboxActionPerformed
sizeList.setEnabled(sizeCheckbox.isSelected());
}//GEN-LAST:event_sizeCheckboxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JCheckBox sizeCheckbox;
private javax.swing.JList<FileSize> sizeList;
private javax.swing.JScrollPane sizeScrollPane;
// End of variables declaration//GEN-END:variables
@Override
void configurePanel(boolean selected, int[] indicesSelected) {
sizeCheckbox.setSelected(selected);
if (sizeCheckbox.isEnabled() && sizeCheckbox.isSelected()) {
sizeScrollPane.setEnabled(true);
sizeList.setEnabled(true);
if (indicesSelected != null) {
sizeList.setSelectedIndices(indicesSelected);
}
} else {
sizeScrollPane.setEnabled(false);
sizeList.setEnabled(false);
}
}
@Override
JCheckBox getCheckbox() {
return sizeCheckbox;
}
@Override
JLabel getAdditionalLabel() {
return null;
}
/**
* Initialize the file size filter.
*/
private void setUpSizeFilter(FileSearchData.FileType fileType) {
int count = 0;
DefaultListModel<FileSize> sizeListModel = (DefaultListModel<FileSize>) sizeList.getModel();
sizeListModel.removeAllElements();
if (null == fileType) {
for (FileSize size : FileSize.values()) {
sizeListModel.add(count, size);
}
} else {
List<FileSearchData.FileSize> sizes;
switch (fileType) {
case VIDEO:
sizes = FileSize.getOptionsForVideos();
break;
case IMAGE:
sizes = FileSize.getDefaultSizeOptions();
break;
case DOCUMENTS:
sizes = FileSize.getDefaultSizeOptions();
break;
default:
sizes = new ArrayList<>();
break;
}
for (FileSize size : sizes) {
sizeListModel.add(count, size);
}
}
}
@Override
String checkForError() {
if (sizeCheckbox.isSelected() && sizeList.getSelectedValuesList().isEmpty()) {
return "At least one size must be selected";
}
return "";
}
@Override
JList<?> getList() {
return sizeList;
}
@Override
FileSearchFiltering.FileFilter getFilter() {
if (sizeCheckbox.isSelected()) {
return new FileSearchFiltering.SizeFilter(sizeList.getSelectedValuesList());
}
return null;
}
}
@@ -0,0 +1,126 @@
/*
* Autopsy
*
* Copyright 2020 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.discovery;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
/**
*
* Class to animate Layouts for a given component.
*
* @author Greg Cope
* https://www.algosome.com/articles/java-swing-panel-animation.html
*
*/
final class SwingAnimator {
//callback object
private final SwingAnimatorCallback callback;
//Timer to animate on the EDT
private Timer timer = null;
//duration in milliseconds betweeen each firing of the Timer
private static final int INITIAL_TIMING = 10;
private int timing = INITIAL_TIMING;
/**
*
* Constructs a new SwingAnimator.
*
* @param callback The SwingAnimatorCallback to call.
*
*/
SwingAnimator(SwingAnimatorCallback callback) {
this(callback, INITIAL_TIMING);
}
/**
*
* Constructs a new SwingAnimator.
*
* @param callback The SwingAnimatorCallback to call.
* @param frameTiming Timing between each call to callback.
*
*/
SwingAnimator(SwingAnimatorCallback callback, int frameTiming) {
this.callback = callback;
timing = frameTiming;
}
/**
*
* Checks if this animator is running.
*
* @return True if the animator is running, false otherwise.
*
*/
boolean isRunning() {
if (timer == null) {
return false;
}
return timer.isRunning();
}
/**
*
* Stops the timer
*
*/
void stop() {
if (timer != null) {
timer.stop();
}
}
/**
*
* Starts the timer to fire. If the current timer is non-null and running,
* this method will first stop the timer before beginning a new one.
*/
void start() {
if (timer != null && timer.isRunning()) {
stop();
}
timer = new Timer(timing, new CallbackListener());
timer.start();
}
/**
*
* ActionListener implements to be passed to the internal timer instance.
*
*/
private class CallbackListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
if (callback.hasTerminated()) {
if (timer == null) {
throw new IllegalStateException("Callback listener should not be fired outside of SwingAnimator timer control");
}
timer.stop();
}
callback.callback(SwingAnimator.this);
}
}
}
@@ -0,0 +1,50 @@
/*
* Autopsy
*
* Copyright 2020 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.discovery;
/**
*
* Callback interface to be notified by a SwingAnimator of a new time frame.
*
*
* @author Greg Cope
* https://www.algosome.com/articles/java-swing-panel-animation.html
*
*/
interface SwingAnimatorCallback {
/**
*
* Callback method for the SwingAnimator.
*
* @param caller The object which is calling the Callback.
*
*/
void callback(Object caller);
/**
*
* Returns true if the SwingAnimator has terminated.
*
* @return True if the animator has terminated, false otherwise.
*
*/
boolean hasTerminated();
}
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<NonVisualComponents>
<Component class="javax.swing.JCheckBox" name="userCreatedCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="UserCreatedFilterPanel.userCreatedCheckbox.text_1" 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="[150, 25]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[150, 25]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[150, 25]"/>
</Property>
</Properties>
</Component>
</NonVisualComponents>
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[250, 30]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[250, 30]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="300" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="42" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Form>
@@ -0,0 +1,112 @@
/*
* Autopsy
*
* Copyright 2020 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.discovery;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JList;
/**
* Panel to allow configuration of the User Created Filter.
*/
final class UserCreatedFilterPanel extends AbstractDiscoveryFilterPanel {
private static final long serialVersionUID = 1L;
/**
* Creates new form UserCreatedFilterPanel.
*/
UserCreatedFilterPanel() {
initComponents();
}
/**
* 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() {
userCreatedCheckbox = new javax.swing.JCheckBox();
org.openide.awt.Mnemonics.setLocalizedText(userCreatedCheckbox, org.openide.util.NbBundle.getMessage(UserCreatedFilterPanel.class, "UserCreatedFilterPanel.userCreatedCheckbox.text_1")); // NOI18N
userCreatedCheckbox.setMaximumSize(new java.awt.Dimension(150, 25));
userCreatedCheckbox.setMinimumSize(new java.awt.Dimension(150, 25));
userCreatedCheckbox.setPreferredSize(new java.awt.Dimension(150, 25));
setMinimumSize(new java.awt.Dimension(250, 30));
setPreferredSize(new java.awt.Dimension(250, 30));
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 42, Short.MAX_VALUE)
);
}// </editor-fold>//GEN-END:initComponents
@Override
void configurePanel(boolean selected, int[] indicesSelected) {
userCreatedCheckbox.setSelected(selected);
}
@Override
JCheckBox getCheckbox() {
return userCreatedCheckbox;
}
@Override
JLabel getAdditionalLabel() {
return null;
}
@Override
String checkForError() {
//this filter currently has no errors it generates
return "";
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JCheckBox userCreatedCheckbox;
// End of variables declaration//GEN-END:variables
@Override
JList<?> getList() {
return null;
}
@Override
FileSearchFiltering.FileFilter getFilter() {
if (userCreatedCheckbox.isSelected()) {
return new FileSearchFiltering.UserCreatedFilter();
}
return null;
}
@Override
boolean hasPanel() {
return false;
}
}
@@ -0,0 +1,83 @@
<?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"/>
<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,0,73,0,0,1,24"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="videoFiltersScrollPane">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="Center"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="videoFiltersPanel">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[223, 66]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
<Component id="videoFiltersSplitPane" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
<Component id="videoFiltersSplitPane" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JSplitPane" name="videoFiltersSplitPane">
<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="Step 2: Filter which videos to show">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/discovery/Bundle.properties" key="VideoFilterPanel.videoFiltersSplitPane.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
<Property name="resizeWeight" type="double" value="0.5"/>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>
@@ -0,0 +1,104 @@
/*
* Autopsy
*
* Copyright 2020 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.discovery;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
/**
* Panel for displaying all filters available for the searches of type Video.
*/
final class VideoFilterPanel extends AbstractFiltersPanel {
private static final long serialVersionUID = 1L;
private static final FileSearchData.FileType FILE_TYPE = FileSearchData.FileType.VIDEO;
/**
* Creates new form VideoFilterPanel.
*/
VideoFilterPanel() {
super();
initComponents();
addFilter(new SizeFilterPanel(FileSearchData.FileType.VIDEO), false, null, 0);
addFilter(new DataSourceFilterPanel(), false, null, 0);
int[] pastOccurrencesIndices;
if (!CentralRepository.isEnabled()) {
pastOccurrencesIndices = new int[]{0};
} else {
pastOccurrencesIndices = new int[]{1, 2, 3, 4, 5, 6, 7};
}
addFilter(new PastOccurrencesFilterPanel(), true, pastOccurrencesIndices, 0);
addFilter(new UserCreatedFilterPanel(), false, null, 1);
addFilter(new HashSetFilterPanel(), false, null, 1);
addFilter(new InterestingItemsFilterPanel(), false, null, 1);
addFilter(new ObjectDetectedFilterPanel(), false, null, 1);
addFilter(new ParentFolderFilterPanel(), false, null, 1);
addPanelsToScrollPane(videoFiltersSplitPane);
}
/**
* 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() {
javax.swing.JScrollPane videoFiltersScrollPane = new javax.swing.JScrollPane();
javax.swing.JPanel videoFiltersPanel = new javax.swing.JPanel();
videoFiltersSplitPane = new javax.swing.JSplitPane();
setLayout(new java.awt.BorderLayout());
videoFiltersPanel.setPreferredSize(new java.awt.Dimension(223, 66));
videoFiltersSplitPane.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(VideoFilterPanel.class, "VideoFilterPanel.videoFiltersSplitPane.border.title"))); // NOI18N
videoFiltersSplitPane.setResizeWeight(0.5);
javax.swing.GroupLayout videoFiltersPanelLayout = new javax.swing.GroupLayout(videoFiltersPanel);
videoFiltersPanel.setLayout(videoFiltersPanelLayout);
videoFiltersPanelLayout.setHorizontalGroup(
videoFiltersPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(videoFiltersPanelLayout.createSequentialGroup()
.addGap(8, 8, 8)
.addComponent(videoFiltersSplitPane)
.addGap(8, 8, 8))
);
videoFiltersPanelLayout.setVerticalGroup(
videoFiltersPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(videoFiltersPanelLayout.createSequentialGroup()
.addGap(8, 8, 8)
.addComponent(videoFiltersSplitPane)
.addGap(8, 8, 8))
);
videoFiltersScrollPane.setViewportView(videoFiltersPanel);
add(videoFiltersScrollPane, java.awt.BorderLayout.CENTER);
}// </editor-fold>//GEN-END:initComponents
@Override
FileSearchData.FileType getFileType() {
return FILE_TYPE;
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JSplitPane videoFiltersSplitPane;
// End of variables declaration//GEN-END:variables
}
@@ -78,13 +78,13 @@
<Image iconType="3" name="/org/sleuthkit/autopsy/images/red-circle-exclamation.png"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())" type="code"/>
<Connection code="new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())" type="code"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())" type="code"/>
<Connection code="new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())" type="code"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())" type="code"/>
<Connection code="new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())" type="code"/>
</Property>
</Properties>
</Component>
@@ -94,13 +94,13 @@
<Image iconType="3" name="/org/sleuthkit/autopsy/images/file-icon-deleted.png"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())" type="code"/>
<Connection code="new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())" type="code"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())" type="code"/>
<Connection code="new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())" type="code"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())" type="code"/>
<Connection code="new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())" type="code"/>
</Property>
</Properties>
</Component>
@@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import java.awt.Color;
import java.awt.Component;
@@ -43,9 +43,9 @@ final class VideoThumbnailPanel extends javax.swing.JPanel implements ListCellRe
private static final int BYTE_UNIT_CONVERSION = 1000;
private static final long serialVersionUID = 1L;
private static final int MAX_NAME_STRING = 120;
/**
* Creates new form VideoThumbnailPanel
* Creates new form VideoThumbnailPanel.
*/
VideoThumbnailPanel() {
initComponents();
@@ -55,7 +55,8 @@ final class VideoThumbnailPanel extends javax.swing.JPanel implements ListCellRe
/**
* Add the thumbnails to the panel.
*
* @param thumbnailWrapper
* @param thumbnailWrapper The object which contains the video thumbnails to
* add.
*/
private void addThumbnails(VideoThumbnailsWrapper thumbnailWrapper) {
imagePanel.removeAll();
@@ -112,14 +113,14 @@ final class VideoThumbnailPanel extends javax.swing.JPanel implements ListCellRe
imagePanel.setLayout(new java.awt.GridBagLayout());
scoreLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/red-circle-exclamation.png"))); // NOI18N
scoreLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize()));
scoreLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize()));
scoreLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize()));
scoreLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize()));
scoreLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize()));
scoreLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize()));
deletedLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/file-icon-deleted.png"))); // NOI18N
deletedLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize()));
deletedLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize()));
deletedLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize()));
deletedLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize()));
deletedLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize()));
deletedLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize()));
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
@@ -35,11 +35,11 @@
</Property>
<Property name="selectionMode" type="int" value="0"/>
<Property name="cellRenderer" type="javax.swing.ListCellRenderer" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new org.sleuthkit.autopsy.filequery.VideoThumbnailPanel()" type="code"/>
<Connection code="new org.sleuthkit.autopsy.discovery.VideoThumbnailPanel()" type="code"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;org.sleuthkit.autopsy.filequery.VideoThumbnailsWrapper&gt;"/>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;org.sleuthkit.autopsy.discovery.VideoThumbnailsWrapper&gt;"/>
</AuxValues>
</Component>
</SubComponents>
@@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import java.util.ArrayList;
import java.util.List;
@@ -28,15 +28,15 @@ import org.sleuthkit.datamodel.AbstractFile;
* A JPanel to display video thumbnails.
*
*/
public class VideoThumbnailViewer extends javax.swing.JPanel {
final class VideoThumbnailViewer extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private final DefaultListModel<VideoThumbnailsWrapper> thumbnailListModel = new DefaultListModel<>();
/**
* Creates new form VideoThumbnailViewer
* Creates new form VideoThumbnailViewer.
*/
public VideoThumbnailViewer() {
VideoThumbnailViewer() {
initComponents();
}
@@ -104,7 +104,7 @@ public class VideoThumbnailViewer extends javax.swing.JPanel {
thumbnailList.setModel(thumbnailListModel);
thumbnailList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
thumbnailList.setCellRenderer(new VideoThumbnailPanel());
thumbnailList.setCellRenderer(new org.sleuthkit.autopsy.discovery.VideoThumbnailPanel());
thumbnailListScrollPane.setViewportView(thumbnailList);
add(thumbnailListScrollPane, java.awt.BorderLayout.CENTER);
@@ -112,7 +112,7 @@ public class VideoThumbnailViewer extends javax.swing.JPanel {
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JList<VideoThumbnailsWrapper> thumbnailList;
private javax.swing.JList<org.sleuthkit.autopsy.discovery.VideoThumbnailsWrapper> thumbnailList;
private javax.swing.JScrollPane thumbnailListScrollPane;
// End of variables declaration//GEN-END:variables
@@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filequery;
package org.sleuthkit.autopsy.discovery;
import java.awt.Image;
import java.util.ArrayList;

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