diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 1ddfb6e89b..8ada5fa596 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -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 diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties index b6e3b0044a..5bac74e842 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties @@ -980,3 +980,5 @@ CallLogArtifactViewer.localAccountPersonaLabel.text=Persona CallLogArtifactViewer.localAccountPersonaNameLabel.text=jLabel1 CallLogArtifactViewer.localAccountPersonaButton.text=jButton1 ContactArtifactViewer.personasLabel.text=Personas +MessageArtifactViewer.accountsTab.TabConstraints.tabTitle=Accounts +ContactArtifactViewer.contactImage.text= diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED index 650a0e6882..0aa57ce92b 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED @@ -107,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) @@ -1091,4 +1095,5 @@ CallLogArtifactViewer.localAccountPersonaLabel.text=Persona CallLogArtifactViewer.localAccountPersonaNameLabel.text=jLabel1 CallLogArtifactViewer.localAccountPersonaButton.text=jButton1 ContactArtifactViewer.personasLabel.text=Personas +MessageArtifactViewer.accountsTab.TabConstraints.tabTitle=Accounts ContactArtifactViewer.contactImage.text= diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java index 737da734cd..99b662f52a 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java @@ -70,7 +70,7 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac private final List personaSearchtasks = new ArrayList<>(); /** - * Creates new form CallLogArtifactViewerNew + * Creates new form CallLogArtifactViewer. */ public CallLogArtifactViewer() { initComponents(); @@ -402,13 +402,12 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac * * @return Account string to display. */ - @NbBundle.Messages({ - "CallLogArtifactViewer_suffix_local=(Local)", - }) + @NbBundle.Messages({ + "CallLogArtifactViewer_suffix_local=(Local)",}) private String getAccountDisplayString(String accountIdentifier, CallLogViewData callLogViewDataNew) { String accountDisplayValue = accountIdentifier; if (callLogViewDataNew.getLocalAccountId() != null && callLogViewDataNew.getLocalAccountId().equalsIgnoreCase(accountIdentifier)) { - accountDisplayValue += " " + Bundle.CallLogArtifactViewer_suffix_local() ; + accountDisplayValue += " " + Bundle.CallLogArtifactViewer_suffix_local(); } return accountDisplayValue; } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageAccountPanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageAccountPanel.java new file mode 100755 index 0000000000..027fe2f7bc --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageAccountPanel.java @@ -0,0 +1,422 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.sleuthkit.autopsy.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, 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 doInBackground() throws Exception { + List dataList = new ArrayList<>(); + + CommunicationsManager commManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager(); + List accountList = commManager.getAccountsRelatedToArtifact(artifact); + for (Account account : accountList) { + if (isCancelled()) { + return new ArrayList<>(); + } + + Collection 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 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 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 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 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 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); + } + + } +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageArtifactViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageArtifactViewer.form index b529e85146..f1a6ce5d4d 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageArtifactViewer.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageArtifactViewer.form @@ -320,6 +320,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageArtifactViewer.java index 6b86505b25..33a2518747 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageArtifactViewer.java @@ -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 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 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. */ diff --git a/Core/src/org/sleuthkit/autopsy/core/discoveryWsmode.xml b/Core/src/org/sleuthkit/autopsy/core/discoveryWsmode.xml index ef5da81277..cde1d1b91d 100644 --- a/Core/src/org/sleuthkit/autopsy/core/discoveryWsmode.xml +++ b/Core/src/org/sleuthkit/autopsy/core/discoveryWsmode.xml @@ -3,7 +3,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/Bundle.properties b/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/Bundle.properties index 310cf0a475..291cf91df5 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/Bundle.properties @@ -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. diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/Bundle.properties-MERGED index f86fa5612d..ec1a9bc5cc 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/Bundle.properties-MERGED @@ -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} diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java b/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java index 339a58142d..5bdec7daa6 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java @@ -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 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 fileExtractionTasks) { + private void runExtractionTasks(ActionEvent event, List fileExtractionTasks, String destName) { // verify all of the sources and destinations are OK for (Iterator 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 { private final Logger logger = Logger.getLogger(FileExtracter.class.getName()); + private final String destName; private ProgressHandle progress; private final List 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 extractionTasks) { + FileExtracter(List 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); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/AbstractDiscoveryFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/AbstractDiscoveryFilterPanel.java new file mode 100644 index 0000000000..24d8a8e946 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/AbstractDiscoveryFilterPanel.java @@ -0,0 +1,126 @@ +/* + * Autopsy + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.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; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java new file mode 100644 index 0000000000..7bcd1c8243 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java @@ -0,0 +1,268 @@ +/* + * Autopsy + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.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 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 getFilters() { + List 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(); + } + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties similarity index 54% rename from Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties rename to Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties index 284e78aead..52c989c8e7 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties @@ -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 diff --git a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED similarity index 78% rename from Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED rename to Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED index ec44af6ee0..0779798a6e 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED @@ -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 diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DataSourceFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/DataSourceFilterPanel.form new file mode 100644 index 0000000000..44ea93cd5a --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/DataSourceFilterPanel.form @@ -0,0 +1,89 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DataSourceFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DataSourceFilterPanel.java new file mode 100644 index 0000000000..a2a2cf4de9 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/DataSourceFilterPanel.java @@ -0,0 +1,204 @@ +/* + * Autopsy + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.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") + // //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()); + 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)) + ); + }// //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 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 dsListModel = (DefaultListModel) 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 dataSources = dataSourceList.getSelectedValuesList().stream().map(t -> t.getDataSource()).collect(Collectors.toList()); + return new FileSearchFiltering.DataSourceFilter(dataSources); + } + return null; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DataSourceModulesWrapper.java b/Core/src/org/sleuthkit/autopsy/discovery/DataSourceModulesWrapper.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/filequery/DataSourceModulesWrapper.java rename to Core/src/org/sleuthkit/autopsy/discovery/DataSourceModulesWrapper.java index 53cabedfb3..b1857c2413 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DataSourceModulesWrapper.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DataSourceModulesWrapper.java @@ -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; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DetailsPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/DetailsPanel.form new file mode 100644 index 0000000000..32f78a9645 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/DetailsPanel.form @@ -0,0 +1,133 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DetailsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DetailsPanel.java new file mode 100644 index 0000000000..6b0a37e276 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/DetailsPanel.java @@ -0,0 +1,261 @@ +/* + * Autopsy + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.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 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 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 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") + // //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)) + ); + }// //GEN-END:initComponents + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JSplitPane detailsSplitPane; + private javax.swing.JList 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; + } + + } +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form new file mode 100644 index 0000000000..d19a7dda96 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form @@ -0,0 +1,379 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java new file mode 100644 index 0000000000..948dbd4bee --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java @@ -0,0 +1,584 @@ +/* + * Autopsy + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.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_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") + // //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(); + }// //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 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 groupByCombobox; + private javax.swing.JComboBox groupSortingComboBox; + private javax.swing.JButton imagesButton; + private javax.swing.JComboBox 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; + } + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryEventUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java similarity index 82% rename from Core/src/org/sleuthkit/autopsy/filequery/DiscoveryEventUtils.java rename to Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java index f73cf4171e..ea5fca6676 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryEventUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java @@ -1,7 +1,7 @@ /* * Autopsy * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2020 Basis Technology Corp. * Contact: carrier sleuthkit 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 instances; + + /** + * Construct a new PopulateInstancesListEvent. + */ + PopulateInstancesListEvent(List files) { + instances = files; + } + + /** + * @return the instances + */ + List 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; + } + } + } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryExtractAction.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryExtractAction.java similarity index 90% rename from Core/src/org/sleuthkit/autopsy/filequery/DiscoveryExtractAction.java rename to Core/src/org/sleuthkit/autopsy/discovery/DiscoveryExtractAction.java index 27d1d8e401..acaf0ccc99 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryExtractAction.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryExtractAction.java @@ -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 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 selectedFiles) { + DiscoveryExtractAction(Collection selectedFiles) { super(NbBundle.getMessage(DiscoveryExtractAction.class, "DiscoveryExtractAction.title.extractFiles.text")); files.addAll(selectedFiles); } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryThumbnailChildren.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryThumbnailChildren.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/filequery/DiscoveryThumbnailChildren.java rename to Core/src/org/sleuthkit/autopsy/discovery/DiscoveryThumbnailChildren.java index 35ee60ac5c..bdcf2f876f 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryThumbnailChildren.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryThumbnailChildren.java @@ -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; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.form b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.form new file mode 100644 index 0000000000..4e62b44cb9 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.form @@ -0,0 +1,158 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java new file mode 100644 index 0000000000..30341184ad --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java @@ -0,0 +1,341 @@ +/* + * Autopsy + * + * Copyright 2019-2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.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") + // //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); + }// //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 availableModes(List 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); + } + + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryUiUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryUiUtils.java similarity index 64% rename from Core/src/org/sleuthkit/autopsy/filequery/DiscoveryUiUtils.java rename to Core/src/org/sleuthkit/autopsy/discovery/DiscoveryUiUtils.java index 0a8f93fa92..3890751dc7 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryUiUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryUiUtils.java @@ -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 getSetNames(BlackboardArtifact.ARTIFACT_TYPE artifactType, BlackboardAttribute.ATTRIBUTE_TYPE setNameAttribute) throws TskCoreException { + List arts = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifacts(artifactType); + List 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 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. */ diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.form new file mode 100644 index 0000000000..a1c49c4c07 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.form @@ -0,0 +1,78 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java new file mode 100644 index 0000000000..9756045387 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java @@ -0,0 +1,100 @@ +/* + * Autopsy + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.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") + // //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); + }// //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 + +} diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/DocumentPanel.form similarity index 91% rename from Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/DocumentPanel.form index beacd1f271..bb29cdb8b4 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/DocumentPanel.form @@ -80,16 +80,16 @@ - + - + - + - + @@ -100,20 +100,20 @@ - + - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DocumentPanel.java similarity index 92% rename from Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/DocumentPanel.java index 6f6008a053..2852c7579a 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DocumentPanel.java @@ -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 { +class DocumentPanel extends javax.swing.JPanel implements ListCellRenderer { 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 diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPreviewViewer.form b/Core/src/org/sleuthkit/autopsy/discovery/DocumentPreviewViewer.form similarity index 100% rename from Core/src/org/sleuthkit/autopsy/filequery/DocumentPreviewViewer.form rename to Core/src/org/sleuthkit/autopsy/discovery/DocumentPreviewViewer.form diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPreviewViewer.java b/Core/src/org/sleuthkit/autopsy/discovery/DocumentPreviewViewer.java similarity index 96% rename from Core/src/org/sleuthkit/autopsy/filequery/DocumentPreviewViewer.java rename to Core/src/org/sleuthkit/autopsy/discovery/DocumentPreviewViewer.java index c65287da42..6d79268b75 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPreviewViewer.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DocumentPreviewViewer.java @@ -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 documentListModel = new DefaultListModel<>(); /** - * Creates new form DocumentViewer + * Creates new form DocumentViewer. */ - public DocumentPreviewViewer() { + DocumentPreviewViewer() { initComponents(); } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DocumentWrapper.java b/Core/src/org/sleuthkit/autopsy/discovery/DocumentWrapper.java similarity index 96% rename from Core/src/org/sleuthkit/autopsy/filequery/DocumentWrapper.java rename to Core/src/org/sleuthkit/autopsy/discovery/DocumentWrapper.java index 9bf3b173ff..02a2b0530e 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DocumentWrapper.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DocumentWrapper.java @@ -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; diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileGroup.java b/Core/src/org/sleuthkit/autopsy/discovery/FileGroup.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/filequery/FileGroup.java rename to Core/src/org/sleuthkit/autopsy/discovery/FileGroup.java index 3c69c4c8f3..ad88550df6 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileGroup.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/FileGroup.java @@ -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. diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/FileSearch.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java rename to Core/src/org/sleuthkit/autopsy/discovery/FileSearch.java index b25f83d195..0590351793 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/FileSearch.java @@ -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; diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchData.java b/Core/src/org/sleuthkit/autopsy/discovery/FileSearchData.java similarity index 95% rename from Core/src/org/sleuthkit/autopsy/filequery/FileSearchData.java rename to Core/src/org/sleuthkit/autopsy/discovery/FileSearchData.java index 8efabf2704..40df3ee905 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchData.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/FileSearchData.java @@ -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 getOptionsForImages() { + static List 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 DOCUMENT_MIME_TYPES = new ImmutableSet.Builder() .add("text/html", //NON-NLS @@ -291,14 +292,15 @@ final class FileSearchData { "application/vnd.oasis.opendocument.text" //NON-NLS ).build(); - private static final ImmutableSet IMAGE_UNSUPPORTED_DOC_TYPES + private static final ImmutableSet IMAGE_UNSUPPORTED_DOC_TYPES = new ImmutableSet.Builder() .add("application/pdf", //NON-NLS - "application/xhtml+xml").build(); //NON-NLS - - static Collection getDocTypesWithoutImageExtraction(){ - return Collections.unmodifiableCollection(IMAGE_UNSUPPORTED_DOC_TYPES); - } + "application/xhtml+xml").build(); //NON-NLS + + static Collection 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 diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchException.java b/Core/src/org/sleuthkit/autopsy/discovery/FileSearchException.java similarity index 61% rename from Core/src/org/sleuthkit/autopsy/filequery/FileSearchException.java rename to Core/src/org/sleuthkit/autopsy/discovery/FileSearchException.java index 2b9a79b39c..df22e26488 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchException.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/FileSearchException.java @@ -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); } } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/filequery/FileSearchFiltering.java rename to Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java index a96db2fd35..326bc7c15c 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java @@ -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 { diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSorter.java b/Core/src/org/sleuthkit/autopsy/discovery/FileSorter.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/filequery/FileSorter.java rename to Core/src/org/sleuthkit/autopsy/discovery/FileSorter.java index 6d73c20b01..fc74dd5713 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSorter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/FileSorter.java @@ -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; diff --git a/Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/GroupListPanel.form similarity index 98% rename from Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/GroupListPanel.form index 9df241e5ab..be51027b3a 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/GroupListPanel.form @@ -46,7 +46,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/GroupListPanel.java similarity index 81% rename from Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/GroupListPanel.java index 374c079590..6e3951b47b 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/GroupListPanel.java @@ -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 diff --git a/Core/src/org/sleuthkit/autopsy/discovery/HashSetFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/HashSetFilterPanel.form new file mode 100644 index 0000000000..8f83bc0e77 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/HashSetFilterPanel.form @@ -0,0 +1,80 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/HashSetFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/HashSetFilterPanel.java new file mode 100644 index 0000000000..eaad0f06f2 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/HashSetFilterPanel.java @@ -0,0 +1,170 @@ +/* + * Autopsy + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.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 hashListModel = (DefaultListModel) hashSetList.getModel(); + hashListModel.removeAllElements(); + List 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") + // //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()); + 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) + ); + }// //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 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; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.form new file mode 100644 index 0000000000..7a3374f5cb --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.form @@ -0,0 +1,81 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java new file mode 100644 index 0000000000..8eec6dd60f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java @@ -0,0 +1,106 @@ +/* + * Autopsy + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.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") + // //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); + }// //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 +} diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailPanel.form similarity index 90% rename from Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailPanel.form index b491a2c6de..c3ae30091c 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailPanel.form @@ -102,16 +102,16 @@
- + - + - + - + @@ -122,13 +122,13 @@ - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailPanel.java similarity index 90% rename from Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailPanel.java index 78654296cb..8f7b90ad08 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailPanel.java @@ -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 { +final class ImageThumbnailPanel extends javax.swing.JPanel implements ListCellRenderer { 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); diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailViewer.form b/Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailViewer.form similarity index 100% rename from Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailViewer.form rename to Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailViewer.form diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailViewer.java b/Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailViewer.java similarity index 95% rename from Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailViewer.java rename to Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailViewer.java index e2688359c9..b1f5ce97e7 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailViewer.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailViewer.java @@ -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 thumbnailListModel = new DefaultListModel<>(); /** - * Creates new form ImageThumbnailViewer + * Creates new form ImageThumbnailViewer. */ - public ImageThumbnailViewer() { + ImageThumbnailViewer() { initComponents(); } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailWrapper.java b/Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailWrapper.java similarity index 96% rename from Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailWrapper.java rename to Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailWrapper.java index dd1923007d..b4e7bb0b01 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailWrapper.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailWrapper.java @@ -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; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/InterestingItemsFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/InterestingItemsFilterPanel.form new file mode 100644 index 0000000000..ff3b7cea10 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/InterestingItemsFilterPanel.form @@ -0,0 +1,85 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/InterestingItemsFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/InterestingItemsFilterPanel.java new file mode 100644 index 0000000000..a073d6b928 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/InterestingItemsFilterPanel.java @@ -0,0 +1,172 @@ +/* + * Autopsy + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.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 intListModel = (DefaultListModel) interestingItemsList.getModel(); + intListModel.removeAllElements(); + List 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") + // //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()); + 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) + ); + }// //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 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; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ObjectDetectedFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ObjectDetectedFilterPanel.form new file mode 100644 index 0000000000..6c6953c55f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/ObjectDetectedFilterPanel.form @@ -0,0 +1,92 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ObjectDetectedFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ObjectDetectedFilterPanel.java new file mode 100644 index 0000000000..335ca8af43 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/ObjectDetectedFilterPanel.java @@ -0,0 +1,177 @@ +/* + * Autopsy + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.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 objListModel = (DefaultListModel) objectsList.getModel(); + objListModel.removeAllElements(); + List 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") + // //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()); + 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) + ); + }// //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 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; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/OpenDiscoveryAction.java b/Core/src/org/sleuthkit/autopsy/discovery/OpenDiscoveryAction.java new file mode 100644 index 0000000000..9ef7d5dfe6 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/OpenDiscoveryAction.java @@ -0,0 +1,112 @@ +/* + * Autopsy + * + * Copyright 2019-2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.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 + } +} diff --git a/Core/src/org/sleuthkit/autopsy/filequery/PageWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/PageWorker.java similarity index 97% rename from Core/src/org/sleuthkit/autopsy/filequery/PageWorker.java rename to Core/src/org/sleuthkit/autopsy/discovery/PageWorker.java index 04ee8b05bd..6eda6c6c3a 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/PageWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/PageWorker.java @@ -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; /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.form new file mode 100644 index 0000000000..c35bc16cb4 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.form @@ -0,0 +1,224 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java new file mode 100644 index 0000000000..3ecb095868 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java @@ -0,0 +1,306 @@ +/* + * Autopsy + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.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 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) 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") + // //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()); + 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)) + ); + }// //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 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 getParentPaths() { + List 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; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.form new file mode 100644 index 0000000000..37ea6de900 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.form @@ -0,0 +1,88 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java new file mode 100644 index 0000000000..f80bfbfad5 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java @@ -0,0 +1,163 @@ +/* + * Autopsy + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.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") + // //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()); + 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)) + ); + }// //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 frequencyListModel = (DefaultListModel) 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 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; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ResultFile.java b/Core/src/org/sleuthkit/autopsy/discovery/ResultFile.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/filequery/ResultFile.java rename to Core/src/org/sleuthkit/autopsy/discovery/ResultFile.java index e6b16d34c9..73d57ccf37 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ResultFile.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ResultFile.java @@ -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 { diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.form similarity index 71% rename from Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.form index 09e12b5693..d35521df46 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.form @@ -2,8 +2,11 @@
+ + + - + @@ -16,26 +19,10 @@ + - - - - - - - - - - - - - - - - - - + @@ -44,11 +31,22 @@ + + + + + + + + + + + @@ -81,7 +79,7 @@ - + @@ -129,7 +127,7 @@ - + @@ -155,7 +153,7 @@ - + @@ -180,6 +178,10 @@ + + + + @@ -197,7 +199,7 @@ - + @@ -310,120 +312,22 @@ - + - - - - - + + - - - + - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.java similarity index 75% rename from Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.java index 0acc2e1bf3..7082b0d835 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.java @@ -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> resultContentWorkers = new ArrayList<>(); - private final DefaultListModel 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 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 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); }// //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 instancesList; private javax.swing.JButton nextPageButton; private javax.swing.JComboBox 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; - } - - } } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/SearchResults.java b/Core/src/org/sleuthkit/autopsy/discovery/SearchResults.java similarity index 90% rename from Core/src/org/sleuthkit/autopsy/filequery/SearchResults.java rename to Core/src/org/sleuthkit/autopsy/discovery/SearchResults.java index 7cc9b8a596..29e6eb924d 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/SearchResults.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/SearchResults.java @@ -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 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 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 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> toLinkedHashMap() throws FileSearchException { Map> map = new LinkedHashMap<>(); diff --git a/Core/src/org/sleuthkit/autopsy/filequery/SearchWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/SearchWorker.java similarity index 83% rename from Core/src/org/sleuthkit/autopsy/filequery/SearchWorker.java rename to Core/src/org/sleuthkit/autopsy/discovery/SearchWorker.java index 74196e7b01..1a513afda1 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/SearchWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/SearchWorker.java @@ -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 { @@ -43,13 +43,14 @@ final class SearchWorker extends SwingWorker { private final Map 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 searchfilters, FileSearch.AttributeType groupingAttribute, FileGroup.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod) { centralRepoDb = centralRepo; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/SizeFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/SizeFilterPanel.form new file mode 100644 index 0000000000..1b77a4329e --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/SizeFilterPanel.form @@ -0,0 +1,94 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/SizeFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/SizeFilterPanel.java new file mode 100644 index 0000000000..1e78b9a079 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/SizeFilterPanel.java @@ -0,0 +1,187 @@ +/* + * Autopsy + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.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") + // //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()); + 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)) + ); + }// //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 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 sizeListModel = (DefaultListModel) sizeList.getModel(); + sizeListModel.removeAllElements(); + if (null == fileType) { + for (FileSize size : FileSize.values()) { + sizeListModel.add(count, size); + } + } else { + List 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; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/SwingAnimator.java b/Core/src/org/sleuthkit/autopsy/discovery/SwingAnimator.java new file mode 100644 index 0000000000..eb5ba0d26f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/SwingAnimator.java @@ -0,0 +1,126 @@ +/* + * Autopsy + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.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); + } + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/SwingAnimatorCallback.java b/Core/src/org/sleuthkit/autopsy/discovery/SwingAnimatorCallback.java new file mode 100644 index 0000000000..86f7d2f7fb --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/SwingAnimatorCallback.java @@ -0,0 +1,50 @@ +/* + * Autopsy + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.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(); + +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/UserCreatedFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/UserCreatedFilterPanel.form new file mode 100644 index 0000000000..520bf47dc3 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/UserCreatedFilterPanel.form @@ -0,0 +1,54 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/UserCreatedFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/UserCreatedFilterPanel.java new file mode 100644 index 0000000000..6c0ca9d67a --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/UserCreatedFilterPanel.java @@ -0,0 +1,112 @@ +/* + * Autopsy + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.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") + // //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) + ); + }// //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; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.form new file mode 100644 index 0000000000..259a188967 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.form @@ -0,0 +1,83 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java new file mode 100644 index 0000000000..48522a9474 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java @@ -0,0 +1,104 @@ +/* + * Autopsy + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.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") + // //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); + }// //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 + +} diff --git a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailPanel.form similarity index 88% rename from Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailPanel.form index 222d87dc20..522acb16c8 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailPanel.form @@ -78,13 +78,13 @@
- + - + - + @@ -94,13 +94,13 @@ - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailPanel.java similarity index 93% rename from Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailPanel.java index a72400a64c..d8845f565a 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailPanel.java @@ -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); diff --git a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailViewer.form b/Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailViewer.form similarity index 95% rename from Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailViewer.form rename to Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailViewer.form index 931f7f1bd1..aa8875a52d 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailViewer.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailViewer.form @@ -35,11 +35,11 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailViewer.java b/Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailViewer.java similarity index 90% rename from Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailViewer.java rename to Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailViewer.java index a1dc742eab..bb3c5a30ea 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailViewer.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailViewer.java @@ -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 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 thumbnailList; + private javax.swing.JList thumbnailList; private javax.swing.JScrollPane thumbnailListScrollPane; // End of variables declaration//GEN-END:variables diff --git a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailsWrapper.java b/Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailsWrapper.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailsWrapper.java rename to Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailsWrapper.java index 08c68611c0..52c188ac80 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailsWrapper.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailsWrapper.java @@ -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; diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryTopComponent.form b/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryTopComponent.form deleted file mode 100644 index a97349ea65..0000000000 --- a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryTopComponent.form +++ /dev/null @@ -1,242 +0,0 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryTopComponent.java deleted file mode 100644 index 91d1db2b12..0000000000 --- a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryTopComponent.java +++ /dev/null @@ -1,408 +0,0 @@ -/* - * Autopsy - * - * Copyright 2019 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.filequery; - -import com.google.common.eventbus.Subscribe; -import java.awt.Color; -import java.util.List; -import java.util.stream.Collectors; -import javax.swing.SwingUtilities; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; -import org.openide.util.NbBundle; -import org.openide.windows.Mode; -import org.openide.windows.RetainLocation; -import org.openide.windows.TopComponent; -import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.corecomponents.DataContentPanel; -import org.sleuthkit.autopsy.corecomponents.TableFilterNode; -import org.sleuthkit.autopsy.coreutils.ThreadConfined; -import org.sleuthkit.autopsy.datamodel.FileNode; -import org.sleuthkit.datamodel.AbstractFile; - -/** - * Create a dialog for displaying the file discovery tool - */ -@TopComponent.Description(preferredID = "DiscoveryTopComponent", persistenceType = TopComponent.PERSISTENCE_NEVER) -@TopComponent.Registration(mode = "discovery", openAtStartup = false) -@RetainLocation("discovery") -@NbBundle.Messages("DiscoveryTopComponent.name= File Discovery") -public final class DiscoveryTopComponent extends TopComponent { - - private static final long serialVersionUID = 1L; - private static final String PREFERRED_ID = "DiscoveryTopComponent"; // NON-NLS - private static final Color SELECTED_COLOR = new Color(216, 230, 242); - private static final Color UNSELECTED_COLOR = new Color(240, 240, 240); - private final FileSearchPanel fileSearchPanel; - private final GroupListPanel groupListPanel; - private final DataContentPanel dataContentPanel; - private final ResultsPanel resultsPanel; - - /** - * Creates new form FileDiscoveryDialog - */ - @ThreadConfined(type = ThreadConfined.ThreadType.AWT) - public DiscoveryTopComponent() { - initComponents(); - setName(Bundle.DiscoveryTopComponent_name()); - fileSearchPanel = new FileSearchPanel(); - dataContentPanel = DataContentPanel.createInstance(); - resultsPanel = new ResultsPanel(); - groupListPanel = new GroupListPanel(); - leftSplitPane.setLeftComponent(fileSearchPanel); - leftSplitPane.setRightComponent(groupListPanel); - rightSplitPane.setTopComponent(resultsPanel); - rightSplitPane.setBottomComponent(dataContentPanel); - //add list selection listener so the content viewer will be updated with the selected file - //when a file is selected in the results panel - resultsPanel.addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e) { - if (!e.getValueIsAdjusting()) { - SwingUtilities.invokeLater(() -> { - AbstractFile file = resultsPanel.getSelectedFile(); - if (file != null) { - dataContentPanel.setNode(new TableFilterNode(new FileNode(file), false)); - } else { - dataContentPanel.setNode(null); - } - }); - } - } - }); - - } - - /** - * 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(); - } - - /** - * Update the search settings to a default state. - */ - void updateSearchSettings() { - resetTopComponent(); - fileSearchPanel.resetPanel(); - 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); - fileSearchPanel.setSelectedType(FileSearchData.FileType.IMAGE); - } - - @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(fileSearchPanel); - } - - @Override - protected void componentClosed() { - fileSearchPanel.cancelSearch(); - DiscoveryEventUtils.getDiscoveryEventBus().unregister(this); - DiscoveryEventUtils.getDiscoveryEventBus().unregister(fileSearchPanel); - DiscoveryEventUtils.getDiscoveryEventBus().unregister(groupListPanel); - DiscoveryEventUtils.getDiscoveryEventBus().unregister(resultsPanel); - 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") - // //GEN-BEGIN:initComponents - private void initComponents() { - - javax.swing.JSplitPane mainSplitPane = new javax.swing.JSplitPane(); - leftSplitPane = new javax.swing.JSplitPane(); - rightSplitPane = new javax.swing.JSplitPane(); - javax.swing.JPanel toolBarPanel = new javax.swing.JPanel(); - imagesButton = new javax.swing.JButton(); - javax.swing.JLabel stepOneLabel = new javax.swing.JLabel(); - videosButton = new javax.swing.JButton(); - javax.swing.Box.Filler filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(119, 0), new java.awt.Dimension(119, 0), new java.awt.Dimension(119, 32767)); - documentsButton = new javax.swing.JButton(); - - setPreferredSize(new java.awt.Dimension(1400, 900)); - setLayout(new java.awt.BorderLayout()); - - mainSplitPane.setDividerLocation(450); - mainSplitPane.setPreferredSize(new java.awt.Dimension(1400, 828)); - - leftSplitPane.setDividerLocation(325); - leftSplitPane.setToolTipText(""); - leftSplitPane.setPreferredSize(new java.awt.Dimension(400, 828)); - mainSplitPane.setLeftComponent(leftSplitPane); - - rightSplitPane.setDividerLocation(475); - rightSplitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT); - rightSplitPane.setResizeWeight(0.5); - rightSplitPane.setPreferredSize(new java.awt.Dimension(1000, 828)); - mainSplitPane.setRightComponent(rightSplitPane); - - add(mainSplitPane, java.awt.BorderLayout.CENTER); - - 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(DiscoveryTopComponent.class, "DiscoveryTopComponent.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); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(stepOneLabel, org.openide.util.NbBundle.getMessage(DiscoveryTopComponent.class, "DiscoveryTopComponent.stepOneLabel.text")); // NOI18N - - 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(DiscoveryTopComponent.class, "DiscoveryTopComponent.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(DiscoveryTopComponent.class, "DiscoveryTopComponent.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); - } - }); - - 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(414, Short.MAX_VALUE) - .addGroup(toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .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)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, toolBarPanelLayout.createSequentialGroup() - .addComponent(filler1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0) - .addComponent(stepOneLabel) - .addGap(119, 119, 119))) - .addContainerGap(413, Short.MAX_VALUE)) - ); - - toolBarPanelLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {documentsButton, imagesButton, videosButton}); - - toolBarPanelLayout.setVerticalGroup( - toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(toolBarPanelLayout.createSequentialGroup() - .addGap(4, 4, 4) - .addGroup(toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(stepOneLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(filler1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .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(5, 5, 5)) - ); - - toolBarPanelLayout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {documentsButton, imagesButton, videosButton}); - - add(toolBarPanel, java.awt.BorderLayout.PAGE_START); - }// //GEN-END:initComponents - - private void imagesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_imagesButtonActionPerformed - resetTopComponent(); - 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); - fileSearchPanel.setSelectedType(FileSearchData.FileType.IMAGE); - }//GEN-LAST:event_imagesButtonActionPerformed - - private void videosButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_videosButtonActionPerformed - resetTopComponent(); - 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); - fileSearchPanel.setSelectedType(FileSearchData.FileType.VIDEO); - }//GEN-LAST:event_videosButtonActionPerformed - - private void documentsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_documentsButtonActionPerformed - resetTopComponent(); - 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); - fileSearchPanel.setSelectedType(FileSearchData.FileType.DOCUMENTS); - }//GEN-LAST:event_documentsButtonActionPerformed - - /** - * Update the user interface in response to a search being cancelled. - * - * @param searchCancelledEvent The SearchCancelledEvent received. - */ - @Subscribe - void handleSearchCancelledEvent(DiscoveryEventUtils.SearchCancelledEvent searchCancelledEvent) { - SwingUtilities.invokeLater(() -> { - if (null != fileSearchPanel.getSelectedType()) { - switch (fileSearchPanel.getSelectedType()) { - case VIDEO: - imagesButton.setEnabled(true); - documentsButton.setEnabled(true); - break; - case IMAGE: - videosButton.setEnabled(true); - documentsButton.setEnabled(true); - break; - case DOCUMENTS: - videosButton.setEnabled(true); - imagesButton.setEnabled(true); - break; - default: - break; - } - } - - }); - } - - /** - * Update the user interface in response to a search being completed. - * - * @param searchCompletedEvent The SearchCompletedEvent received. - */ - @Subscribe - void handleSearchCompletedEvent(DiscoveryEventUtils.SearchCompleteEvent searchCompletedEvent) { - SwingUtilities.invokeLater(() -> { - if (null != fileSearchPanel.getSelectedType()) { - switch (fileSearchPanel.getSelectedType()) { - case VIDEO: - imagesButton.setEnabled(true); - documentsButton.setEnabled(true); - break; - case IMAGE: - videosButton.setEnabled(true); - documentsButton.setEnabled(true); - break; - case DOCUMENTS: - videosButton.setEnabled(true); - imagesButton.setEnabled(true); - break; - default: - break; - } - } - }); - } - - @Override - public List availableModes(List 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()); - } - - /** - * Update the user interface in response to a search being started. - * - * @param searchStartedEvent The SearchStartedEvent received. - */ - @Subscribe - void handleSearchStartedEvent(DiscoveryEventUtils.SearchStartedEvent searchStartedEvent) { - SwingUtilities.invokeLater(() -> { - imagesButton.setEnabled(false); - videosButton.setEnabled(false); - documentsButton.setEnabled(false); - }); - } - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton documentsButton; - private javax.swing.JButton imagesButton; - private javax.swing.JSplitPane leftSplitPane; - private javax.swing.JSplitPane rightSplitPane; - private javax.swing.JButton videosButton; - // End of variables declaration//GEN-END:variables - -} diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchPanel.form b/Core/src/org/sleuthkit/autopsy/filequery/FileSearchPanel.form deleted file mode 100644 index 5ea238b49a..0000000000 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchPanel.form +++ /dev/null @@ -1,984 +0,0 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/FileSearchPanel.java deleted file mode 100644 index eb823f0530..0000000000 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchPanel.java +++ /dev/null @@ -1,1993 +0,0 @@ -/* - * Autopsy - * - * Copyright 2019-2020 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.filequery; - -import com.google.common.eventbus.Subscribe; -import java.awt.Cursor; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.logging.Level; -import java.util.stream.Collectors; -import javax.swing.DefaultListCellRenderer; -import javax.swing.DefaultListModel; -import javax.swing.JCheckBox; -import javax.swing.JList; -import javax.swing.SwingUtilities; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; -import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.filequery.FileGroup.GroupSortingAlgorithm; -import org.sleuthkit.autopsy.filequery.FileSearch.GroupingAttributeType; -import org.sleuthkit.autopsy.filequery.FileSearchData.FileType; -import org.sleuthkit.autopsy.filequery.FileSearchData.FileSize; -import org.sleuthkit.autopsy.filequery.FileSearchData.Frequency; -import org.sleuthkit.autopsy.filequery.FileSearchData.Score; -import org.sleuthkit.autopsy.filequery.FileSearchFiltering.ParentSearchTerm; -import org.sleuthkit.autopsy.filequery.FileSorter.SortingMethod; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.DataSource; -import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; - -/** - * Dialog to allow the user to choose filtering and grouping options. - */ -final class FileSearchPanel extends javax.swing.JPanel implements ActionListener { - - private static final long serialVersionUID = 1L; - private static final String[] DEFAULT_IGNORED_PATHS = {"/Windows/", "/Program Files/"}; //NON-NLS - private final static Logger logger = Logger.getLogger(FileSearchPanel.class.getName()); - private FileType fileType = FileType.IMAGE; - private DefaultListModel parentListModel; - private SearchWorker searchWorker = null; - - /** - * Creates new form FileSearchDialog - */ - @NbBundle.Messages({"FileSearchPanel.dialogTitle.text=Test file search"}) - FileSearchPanel() { - initComponents(); - for (GroupSortingAlgorithm groupSortAlgorithm : GroupSortingAlgorithm.values()) { - groupSortingComboBox.addItem(groupSortAlgorithm); - } - parentListModel = (DefaultListModel) parentList.getModel(); - for (String ignorePath : DEFAULT_IGNORED_PATHS) { - parentListModel.add(parentListModel.size(), new ParentSearchTerm(ignorePath, false, false)); - } - } - - /** - * Setup the data source filter settings. - * - * @param visible Boolean indicating if the filter should be - * visible. - * @param enabled Boolean indicating if the filter should be - * enabled. - * @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. - */ - private void dataSourceFilterSettings(boolean visible, boolean enabled, boolean selected, int[] indicesSelected) { - dataSourceCheckbox.setVisible(visible); - dataSourceScrollPane.setVisible(visible); - dataSourceList.setVisible(visible); - dataSourceCheckbox.setEnabled(enabled); - 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); - } - } - - /** - * Setup the file size filter settings. - * - * @param visible Boolean indicating if the filter should be - * visible. - * @param enabled Boolean indicating if the filter should be - * enabled. - * @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. - */ - private void sizeFilterSettings(boolean visible, boolean enabled, boolean selected, int[] indicesSelected) { - sizeCheckbox.setVisible(visible); - sizeScrollPane.setVisible(visible); - sizeList.setVisible(visible); - sizeCheckbox.setEnabled(enabled); - 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); - } - } - - /** - * Setup the central repository frequency filter settings. - * - * @param visible Boolean indicating if the filter should be - * visible. - * @param enabled Boolean indicating if the filter should be - * enabled. - * @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. - */ - private void crFrequencyFilterSettings(boolean visible, boolean enabled, boolean selected, int[] indicesSelected) { - crFrequencyCheckbox.setVisible(visible); - crFrequencyScrollPane.setVisible(visible); - crFrequencyList.setVisible(visible); - crFrequencyCheckbox.setEnabled(enabled); - crFrequencyCheckbox.setSelected(selected); - if (crFrequencyCheckbox.isEnabled() && crFrequencyCheckbox.isSelected()) { - crFrequencyScrollPane.setEnabled(true); - crFrequencyList.setEnabled(true); - if (indicesSelected != null) { - crFrequencyList.setSelectedIndices(indicesSelected); - } - } else { - crFrequencyScrollPane.setEnabled(false); - crFrequencyList.setEnabled(false); - } - } - - /** - * Setup the objects filter settings. - * - * @param visible Boolean indicating if the filter should be - * visible. - * @param enabled Boolean indicating if the filter should be - * enabled. - * @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. - */ - private void objectsFilterSettings(boolean visible, boolean enabled, boolean selected, int[] indicesSelected) { - objectsCheckbox.setVisible(visible); - objectsScrollPane.setVisible(visible); - objectsList.setVisible(visible); - boolean hasObjects = objectsList.getModel().getSize() > 0; - objectsCheckbox.setEnabled(enabled && 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); - } - } - - /** - * Setup the hash set filter settings. - * - * @param visible Boolean indicating if the filter should be - * visible. - * @param enabled Boolean indicating if the filter should be - * enabled. - * @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. - */ - private void hashSetFilterSettings(boolean visible, boolean enabled, boolean selected, int[] indicesSelected) { - hashSetCheckbox.setVisible(visible); - hashSetScrollPane.setVisible(visible); - hashSetList.setVisible(visible); - boolean hasHashSets = hashSetList.getModel().getSize() > 0; - hashSetCheckbox.setEnabled(enabled && 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); - } - } - - /** - * Setup the interesting items filter settings. - * - * @param visible Boolean indicating if the filter should be - * visible. - * @param enabled Boolean indicating if the filter should be - * enabled. - * @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. - */ - private void interestingItemsFilterSettings(boolean visible, boolean enabled, boolean selected, int[] indicesSelected) { - interestingItemsCheckbox.setVisible(visible); - interestingItemsScrollPane.setVisible(visible); - interestingItemsList.setVisible(visible); - boolean hasInterestingItems = interestingItemsList.getModel().getSize() > 0; - interestingItemsCheckbox.setEnabled(enabled && 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); - } - } - - /** - * Setup the score filter settings. - * - * @param visible Boolean indicating if the filter should be - * visible. - * @param enabled Boolean indicating if the filter should be - * enabled. - * @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. - */ - private void scoreFilterSettings(boolean visible, boolean enabled, boolean selected, int[] indicesSelected) { - scoreCheckbox.setVisible(visible); - scoreScrollPane.setVisible(visible); - scoreList.setVisible(visible); - scoreCheckbox.setEnabled(enabled); - scoreCheckbox.setSelected(selected); - if (scoreCheckbox.isEnabled() && scoreCheckbox.isSelected()) { - scoreScrollPane.setEnabled(true); - scoreList.setEnabled(true); - if (indicesSelected != null) { - scoreList.setSelectedIndices(indicesSelected); - } - } else { - scoreScrollPane.setEnabled(false); - scoreList.setEnabled(false); - } - } - - /** - * Setup the parent path filter settings. - * - * @param visible Boolean indicating if the filter should be - * visible. - * @param enabled Boolean indicating if the filter should be - * enabled. - * @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. - */ - private void parentFilterSettings(boolean visible, boolean enabled, boolean selected, int[] indicesSelected) { - parentCheckbox.setVisible(visible); - parentScrollPane.setVisible(visible); - parentList.setVisible(visible); - parentCheckbox.setEnabled(enabled); - 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); - } - } - - /** - * Setup the tags filter settings. - * - * @param visible Boolean indicating if the filter should be - * visible. - * @param enabled Boolean indicating if the filter should be - * enabled. - * @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. - */ - private void tagsFilterSettings(boolean visible, boolean enabled, boolean selected, int[] indicesSelected) { - tagsCheckbox.setVisible(visible); - tagsScrollPane.setVisible(visible); - tagsList.setVisible(visible); - tagsCheckbox.setEnabled(enabled); - tagsCheckbox.setSelected(selected); - if (tagsCheckbox.isEnabled() && tagsCheckbox.isSelected()) { - tagsScrollPane.setEnabled(true); - tagsList.setEnabled(true); - if (indicesSelected != null) { - tagsList.setSelectedIndices(indicesSelected); - } - } else { - tagsScrollPane.setEnabled(false); - tagsList.setEnabled(false); - } - } - - /** - * Setup the keyword filter settings. - * - * @param visible Boolean indicating if the filter should be - * visible. - * @param enabled Boolean indicating if the filter should be - * enabled. - * @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. - */ - private void keywordFilterSettings(boolean visible, boolean enabled, boolean selected, int[] indicesSelected) { - keywordCheckbox.setVisible(visible); - keywordScrollPane.setVisible(visible); - keywordList.setVisible(visible); - keywordCheckbox.setEnabled(enabled); - keywordCheckbox.setSelected(selected); - if (keywordCheckbox.isEnabled() && keywordCheckbox.isSelected()) { - keywordScrollPane.setEnabled(true); - keywordList.setEnabled(true); - if (indicesSelected != null) { - keywordList.setSelectedIndices(indicesSelected); - } - } else { - keywordScrollPane.setEnabled(false); - keywordList.setEnabled(false); - } - } - - /** - * Setup the user created filter settings. - * - * @param visible Boolean indicating if the filter should be visible. - * @param enabled Boolean indicating if the filter should be enabled. - * @param selected Boolean indicating if the filter should be selected. - */ - private void userCreatedFilterSettings(boolean visible, boolean enabled, boolean selected) { - userCreatedCheckbox.setVisible(visible); - userCreatedCheckbox.setEnabled(enabled); - userCreatedCheckbox.setSelected(selected); - } - - /** - * Setup the known status filter settings. - * - * @param visible Boolean indicating if the filter should be visible. - * @param enabled Boolean indicating if the filter should be enabled. - * @param selected Boolean indicating if the filter should be selected. - */ - private void knownFilesFilterSettings(boolean visible, boolean enabled, boolean selected) { - knownFilesCheckbox.setVisible(visible); - knownFilesCheckbox.setEnabled(enabled); - knownFilesCheckbox.setSelected(selected); - } - - /** - * Setup the notable filter settings. - * - * @param visible Boolean indicating if the filter should be visible. - * @param enabled Boolean indicating if the filter should be enabled. - * @param selected Boolean indicating if the filter should be selected. - */ - private void notableFilterSettings(boolean visible, boolean enabled, boolean selected) { - notableCheckbox.setVisible(visible); - notableCheckbox.setEnabled(enabled); - notableCheckbox.setSelected(selected); - } - - /** - * Set the UI elements available to be the set of UI elements available when - * an Image search is being performed. - * - * @param enabled Boolean indicating if the filters present for images - * should be enabled. - * @param resetSelected Boolean indicating if selection of the filters - * present for images should be reset to their default - * status. - */ - @NbBundle.Messages({"FileSearchPanel.steptwo.images=Step 2: Filter which images to show"}) - private void imagesSelected(boolean enabled, boolean resetSelected) { - stepTwoLabel.setText(Bundle.FileSearchPanel_steptwo_images()); - dataSourceFilterSettings(true, enabled, !resetSelected && dataSourceCheckbox.isSelected(), null); - int[] selectedSizeIndices = {1, 2, 3, 4, 5}; - sizeFilterSettings(true, enabled, resetSelected || sizeCheckbox.isSelected(), resetSelected == true ? selectedSizeIndices : null); - int[] selectedFrequencyIndices; - if (!CentralRepository.isEnabled()) { - selectedFrequencyIndices = new int[]{0}; - } else { - selectedFrequencyIndices = new int[]{1, 2, 3, 4, 5, 6, 7}; - } - crFrequencyFilterSettings(true, enabled, resetSelected || crFrequencyCheckbox.isSelected(), resetSelected == true ? selectedFrequencyIndices : null); - userCreatedFilterSettings(true, enabled, !resetSelected && userCreatedCheckbox.isSelected()); - objectsFilterSettings(true, enabled, !resetSelected && objectsCheckbox.isSelected(), null); - hashSetFilterSettings(true, enabled, !resetSelected && hashSetCheckbox.isSelected(), null); - interestingItemsFilterSettings(true, enabled, !resetSelected && interestingItemsCheckbox.isSelected(), null); - parentFilterSettings(true, enabled, !resetSelected && parentCheckbox.isSelected(), null); - scoreFilterSettings(false, false, false, null); - tagsFilterSettings(false, false, false, null); - keywordFilterSettings(false, false, false, null); - knownFilesFilterSettings(false, false, false); - notableFilterSettings(false, false, false); - } - - /** - * Set the UI elements available to be the set of UI elements available when - * a Video search is being performed. - * - * @param enabled Boolean indicating if the filters present for videos - * should be enabled. - * @param resetSelected Boolean indicating if selection of the filters - * present for videos should be reset to their default - * status. - */ - @NbBundle.Messages({"FileSearchPanel.steptwo.videos=Step 2: Filter which videos to show"}) - private void videosSelected(boolean enabled, boolean resetSelected) { - stepTwoLabel.setText(Bundle.FileSearchPanel_steptwo_videos()); - dataSourceFilterSettings(true, enabled, !resetSelected && dataSourceCheckbox.isSelected(), null); - sizeFilterSettings(true, enabled, !resetSelected && sizeCheckbox.isSelected(), null); - int[] selectedFrequencyIndices; - if (!CentralRepository.isEnabled()) { - selectedFrequencyIndices = new int[]{0}; - } else { - selectedFrequencyIndices = new int[]{1, 2, 3, 4, 5, 6, 7}; - } - crFrequencyFilterSettings(true, enabled, resetSelected || crFrequencyCheckbox.isSelected(), resetSelected == true ? selectedFrequencyIndices : null); - userCreatedFilterSettings(true, enabled, !resetSelected && userCreatedCheckbox.isSelected()); - objectsFilterSettings(true, enabled, !resetSelected && objectsCheckbox.isSelected(), null); - hashSetFilterSettings(true, enabled, !resetSelected && hashSetCheckbox.isSelected(), null); - interestingItemsFilterSettings(true, enabled, !resetSelected && interestingItemsCheckbox.isSelected(), null); - parentFilterSettings(true, enabled, !resetSelected && parentCheckbox.isSelected(), null); - scoreFilterSettings(false, false, false, null); - tagsFilterSettings(false, false, false, null); - keywordFilterSettings(false, false, false, null); - knownFilesFilterSettings(false, false, false); - notableFilterSettings(false, false, false); - } - - /** - * Set the UI elements available to be the set of UI elements available when - * a Document search is being performed. - * - * @param enabled Boolean indicating if the filters present for - * documents should be enabled. - * @param resetSelected Boolean indicating if selection of the filters - * present for documents should be reset to their - * default status. - */ - @NbBundle.Messages({"FileSearchPanel.steptwo.documents=Step 2: Filter which documents to show"}) - private void documentsSelected(boolean enabled, boolean resetSelected) { - stepTwoLabel.setText(Bundle.FileSearchPanel_steptwo_documents()); - dataSourceFilterSettings(true, enabled, !resetSelected && dataSourceCheckbox.isSelected(), null); - sizeFilterSettings(true, enabled, !resetSelected && sizeCheckbox.isSelected(), null); - int[] selectedFrequencyIndices; - if (!CentralRepository.isEnabled()) { - selectedFrequencyIndices = new int[]{0}; - } else { - selectedFrequencyIndices = new int[]{1, 2, 3, 4, 5, 6, 7}; - } - crFrequencyFilterSettings(true, enabled, resetSelected || crFrequencyCheckbox.isSelected(), resetSelected == true ? selectedFrequencyIndices : null); - userCreatedFilterSettings(false, false, false); - objectsFilterSettings(false, false, false, null); - hashSetFilterSettings(true, enabled, !resetSelected && hashSetCheckbox.isSelected(), null); - interestingItemsFilterSettings(true, enabled, !resetSelected && interestingItemsCheckbox.isSelected(), null); - parentFilterSettings(true, enabled, !resetSelected && parentCheckbox.isSelected(), null); - scoreFilterSettings(false, false, false, null); - tagsFilterSettings(false, false, false, null); - keywordFilterSettings(false, false, false, null); - knownFilesFilterSettings(false, false, false); - notableFilterSettings(false, false, false); - } - - /** - * Set the type of search to perform. - * - * @param type The type of File to be found by the search. - */ - void setSelectedType(FileType type) { - fileType = type; - setUpSizeFilter(); - if (null != fileType) { - switch (fileType) { - case IMAGE: - imagesSelected(true, true); - break; - case VIDEO: - videosSelected(true, true); - break; - case DOCUMENTS: - documentsSelected(true, true); - break; - default: - break; - } - } - validateFields(); - } - - FileType getSelectedType() { - return fileType; - } - - /** - * Reset the panel to its initial configuration. - */ - void resetPanel() { - - searchButton.setEnabled(false); - - // Set up the filters - setUpDataSourceFilter(); - setUpFrequencyFilter(); - setUpSizeFilter(); - setUpKWFilter(); - setUpParentPathFilter(); - setUpHashFilter(); - setUpInterestingItemsFilter(); - setUpTagsFilter(); - setUpObjectFilter(); - setUpScoreFilter(); - - groupByCombobox.removeAllItems(); - // Set up the grouping attributes - for (FileSearch.GroupingAttributeType type : FileSearch.GroupingAttributeType.getOptionsForGrouping()) { - if ((type != GroupingAttributeType.FREQUENCY || CentralRepository.isEnabled()) - && (type != GroupingAttributeType.OBJECT_DETECTED || objectsList.getModel().getSize() > 0) - && (type != GroupingAttributeType.INTERESTING_ITEM_SET || interestingItemsList.getModel().getSize() > 0) - && (type != GroupingAttributeType.HASH_LIST_NAME || hashSetList.getModel().getSize() > 0)) { - groupByCombobox.addItem(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); - setSelectedType(FileType.IMAGE); - validateFields(); - } - - /** - * Add listeners to the checkbox/list set if listeners have not already been - * added. Either can be null. - * - * @param checkBox - * @param list - */ - private void addListeners(JCheckBox checkBox, JList list) { - if (checkBox != null) { - checkBox.addActionListener(this); - } - if (list != null) { - list.addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent evt) { - if (!evt.getValueIsAdjusting()) { - validateFields(); - } - } - }); - } - } - - /** - * Initialize the data source filter - */ - private void setUpDataSourceFilter() { - int count = 0; - try { - DefaultListModel dsListModel = (DefaultListModel) 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); - } - addListeners(dataSourceCheckbox, dataSourceList); - } - - /** - * Initialize the frequency filter - */ - private void setUpFrequencyFilter() { - int count = 0; - DefaultListModel frequencyListModel = (DefaultListModel) 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); - } - } - addListeners(crFrequencyCheckbox, crFrequencyList); - } - - /** - * Initialize the file size filter - */ - private void setUpSizeFilter() { - int count = 0; - DefaultListModel sizeListModel = (DefaultListModel) sizeList.getModel(); - sizeListModel.removeAllElements(); - if (null == fileType) { - for (FileSearchData.FileSize size : FileSearchData.FileSize.values()) { - sizeListModel.add(count, size); - } - } else { - List sizes; - switch (fileType) { - case VIDEO: - sizes = FileSearchData.FileSize.getOptionsForVideos(); - break; - case IMAGE: - sizes = FileSearchData.FileSize.getOptionsForImages(); - break; - case DOCUMENTS: - sizes = FileSearchData.FileSize.getOptionsForImages(); - break; - default: - sizes = new ArrayList<>(); - break; - } - for (FileSearchData.FileSize size : sizes) { - sizeListModel.add(count, size); - } - } - addListeners(sizeCheckbox, sizeList); - } - - /** - * Initialize the keyword list names filter - */ - private void setUpKWFilter() { - int count = 0; - try { - DefaultListModel kwListModel = (DefaultListModel) keywordList.getModel(); - kwListModel.removeAllElements(); - List setNames = getSetNames(BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT, - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME); - for (String name : setNames) { - kwListModel.add(count, name); - } - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error loading keyword list names", ex); - keywordCheckbox.setEnabled(false); - keywordList.setEnabled(false); - } - addListeners(keywordCheckbox, keywordList); - } - - /** - * Initialize the hash filter. - */ - private void setUpHashFilter() { - int count = 0; - try { - DefaultListModel hashListModel = (DefaultListModel) hashSetList.getModel(); - hashListModel.removeAllElements(); - List setNames = 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); - } - addListeners(hashSetCheckbox, hashSetList); - } - - /** - * Initialize the interesting items filter. - */ - private void setUpInterestingItemsFilter() { - int count = 0; - try { - DefaultListModel intListModel = (DefaultListModel) interestingItemsList.getModel(); - intListModel.removeAllElements(); - List setNames = 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); - } - addListeners(interestingItemsCheckbox, interestingItemsList); - } - - /** - * Initialize the tags filter. - */ - private void setUpTagsFilter() { - int count = 0; - try { - DefaultListModel tagsListModel = (DefaultListModel) tagsList.getModel(); - tagsListModel.removeAllElements(); - List tagNames = Case.getCurrentCase().getSleuthkitCase().getTagNamesInUse(); - for (TagName name : tagNames) { - tagsListModel.add(count, name); - count++; - } - tagsList.setCellRenderer(new TagsListCellRenderer()); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error loading tag names", ex); - tagsCheckbox.setEnabled(false); - tagsList.setEnabled(false); - } - addListeners(tagsCheckbox, tagsList); - } - - /** - * TagsListCellRenderer - */ - private class TagsListCellRenderer extends DefaultListCellRenderer { - - private static final long serialVersionUID = 1L; - - @Override - public java.awt.Component getListCellRendererComponent( - JList list, - Object value, - int index, - boolean isSelected, - boolean cellHasFocus) { - Object newValue = value; - if (value instanceof TagName) { - newValue = ((TagName) value).getDisplayName(); - } - super.getListCellRendererComponent(list, newValue, index, isSelected, cellHasFocus); - return this; - } - } - - /** - * Initialize the object filter - */ - private void setUpObjectFilter() { - int count = 0; - try { - DefaultListModel objListModel = (DefaultListModel) objectsList.getModel(); - objListModel.removeAllElements(); - List setNames = 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); - } - addListeners(objectsCheckbox, objectsList); - } - - /** - * Initialize the score filter - */ - private void setUpScoreFilter() { - - int count = 0; - DefaultListModel scoreListModel = (DefaultListModel) scoreList.getModel(); - scoreListModel.removeAllElements(); - for (Score score : Score.getOptionsForFiltering()) { - scoreListModel.add(count, score); - } - addListeners(scoreCheckbox, scoreList); - } - - /** - * 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 - */ - private List getSetNames(BlackboardArtifact.ARTIFACT_TYPE artifactType, BlackboardAttribute.ATTRIBUTE_TYPE setNameAttribute) throws TskCoreException { - List arts = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifacts(artifactType); - List 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; - } - - /** - * Initialize the parent path filter - */ - private void setUpParentPathFilter() { - fullRadioButton.setSelected(true); - includeRadioButton.setSelected(true); - parentListModel = (DefaultListModel) parentList.getModel(); - addListeners(parentCheckbox, parentList); - } - - /** - * Get a list of all filters selected by the user. - * - * @return the list of filters - */ - List getFilters() { - List filters = new ArrayList<>(); - filters.add(new FileSearchFiltering.FileTypeFilter(fileType)); - if (parentCheckbox.isSelected()) { - // For the parent paths, everything in the box is used (not just the selected entries) - filters.add(new FileSearchFiltering.ParentFilter(getParentPaths())); - } - - if (dataSourceCheckbox.isSelected()) { - List dataSources = dataSourceList.getSelectedValuesList().stream().map(t -> t.getDataSource()).collect(Collectors.toList()); - filters.add(new FileSearchFiltering.DataSourceFilter(dataSources)); - } - - if (crFrequencyCheckbox.isSelected()) { - filters.add(new FileSearchFiltering.FrequencyFilter(crFrequencyList.getSelectedValuesList())); - } - - if (sizeCheckbox.isSelected()) { - filters.add(new FileSearchFiltering.SizeFilter(sizeList.getSelectedValuesList())); - } - - if (keywordCheckbox.isSelected()) { - filters.add(new FileSearchFiltering.KeywordListFilter(keywordList.getSelectedValuesList())); - } - - if (hashSetCheckbox.isSelected()) { - filters.add(new FileSearchFiltering.HashSetFilter(hashSetList.getSelectedValuesList())); - } - - if (interestingItemsCheckbox.isSelected()) { - filters.add(new FileSearchFiltering.InterestingFileSetFilter(interestingItemsList.getSelectedValuesList())); - } - - if (objectsCheckbox.isSelected()) { - filters.add(new FileSearchFiltering.ObjectDetectionFilter(objectsList.getSelectedValuesList())); - } - - if (tagsCheckbox.isSelected()) { - filters.add(new FileSearchFiltering.TagsFilter(tagsList.getSelectedValuesList())); - } - - if (userCreatedCheckbox.isSelected()) { - filters.add(new FileSearchFiltering.UserCreatedFilter()); - } - - if (notableCheckbox.isSelected()) { - filters.add(new FileSearchFiltering.NotableFilter()); - } - - if (knownFilesCheckbox.isSelected()) { - filters.add(new FileSearchFiltering.KnownFilter()); - } - - if (scoreCheckbox.isSelected()) { - filters.add(new FileSearchFiltering.ScoreFilter(scoreList.getSelectedValuesList())); - } - - return filters; - } - - /** - * Utility method to get the parent path objects out of the JList. - * - * @return The list of entered ParentSearchTerm objects - */ - private List getParentPaths() { - List results = new ArrayList<>(); - for (int i = 0; i < parentListModel.getSize(); i++) { - results.add(parentListModel.get(i)); - } - return results; - } - - /** - * Get the attribute to group by - * - * @return the grouping attribute - */ - FileSearch.AttributeType getGroupingAttribute() { - return groupByCombobox.getItemAt(groupByCombobox.getSelectedIndex()).getAttributeType(); - } - - /** - * Get the sorting method for groups. - * - * @return the selected sorting method - */ - FileGroup.GroupSortingAlgorithm getGroupSortingMethod() { - return groupSortingComboBox.getItemAt(groupSortingComboBox.getSelectedIndex()); - - } - - /** - * Get the sorting method for files. - * - * @return the selected sorting method - */ - FileSorter.SortingMethod getFileSortingMethod() { - return (FileSorter.SortingMethod) orderByCombobox.getSelectedItem(); - } - - @Override - public void actionPerformed(ActionEvent e) { - validateFields(); - } - - /** - * Utility class to allow us to display the data source ID along with the - * name - */ - private class DataSourceItem { - - private final DataSource ds; - - DataSourceItem(DataSource ds) { - this.ds = ds; - } - - DataSource getDataSource() { - return ds; - } - - @Override - public String toString() { - return ds.getName() + " (ID: " + ds.getId() + ")"; - } - } - - /** - * Validate the form. If we use any of this in the final dialog we should - * use bundle messages. - */ - private void validateFields() { - // There will be a file type selected. - if (fileType == null) { - setInvalid("At least one file type must be selected"); - return; - } - // For most enabled filters, there should be something selected - if (dataSourceCheckbox.isSelected() && dataSourceList.getSelectedValuesList().isEmpty()) { - setInvalid("At least one data source must be selected"); - return; - } - if (crFrequencyCheckbox.isSelected() && crFrequencyList.getSelectedValuesList().isEmpty()) { - setInvalid("At least one CR frequency must be selected"); - return; - } - if (sizeCheckbox.isSelected() && sizeList.getSelectedValuesList().isEmpty()) { - setInvalid("At least one size must be selected"); - return; - } - if (keywordCheckbox.isSelected() && keywordList.getSelectedValuesList().isEmpty()) { - setInvalid("At least one keyword list name must be selected"); - return; - } - - // Parent uses everything in the box - if (parentCheckbox.isSelected() && getParentPaths().isEmpty()) { - setInvalid("At least one parent path must be entered"); - return; - } - - if (hashSetCheckbox.isSelected() && hashSetList.getSelectedValuesList().isEmpty()) { - setInvalid("At least one hash set name must be selected"); - return; - } - - if (interestingItemsCheckbox.isSelected() && interestingItemsList.getSelectedValuesList().isEmpty()) { - setInvalid("At least one interesting file set name must be selected"); - return; - } - - if (objectsCheckbox.isSelected() && objectsList.getSelectedValuesList().isEmpty()) { - setInvalid("At least one object type name must be selected"); - return; - } - - if (tagsCheckbox.isSelected() && tagsList.getSelectedValuesList().isEmpty()) { - setInvalid("At least one tag name must be selected"); - return; - } - - if (scoreCheckbox.isSelected() && scoreList.getSelectedValuesList().isEmpty()) { - setInvalid("At least one score must be selected"); - return; - } - setValid(); - } - - /** - * The settings are valid so enable the Search button - */ - private void setValid() { - errorLabel.setText(""); - searchButton.setEnabled(true); - } - - /** - * The settings are not valid so disable the search button and display the - * given error message. - * - * @param error - */ - private void setInvalid(String error) { - errorLabel.setText(error); - searchButton.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") - // //GEN-BEGIN:initComponents - private void initComponents() { - java.awt.GridBagConstraints gridBagConstraints; - - javax.swing.ButtonGroup parentPathButtonGroup = new javax.swing.ButtonGroup(); - javax.swing.ButtonGroup parentIncludeButtonGroup = new javax.swing.ButtonGroup(); - javax.swing.JScrollPane filtersScrollPane = new javax.swing.JScrollPane(); - javax.swing.JPanel filtersPanel = new javax.swing.JPanel(); - sizeCheckbox = new javax.swing.JCheckBox(); - dataSourceCheckbox = new javax.swing.JCheckBox(); - crFrequencyCheckbox = new javax.swing.JCheckBox(); - keywordCheckbox = new javax.swing.JCheckBox(); - parentCheckbox = new javax.swing.JCheckBox(); - dataSourceScrollPane = new javax.swing.JScrollPane(); - dataSourceList = new javax.swing.JList<>(); - substringRadioButton = new javax.swing.JRadioButton(); - addButton = new javax.swing.JButton(); - deleteButton = new javax.swing.JButton(); - sizeScrollPane = new javax.swing.JScrollPane(); - sizeList = new javax.swing.JList<>(); - crFrequencyScrollPane = new javax.swing.JScrollPane(); - crFrequencyList = new javax.swing.JList<>(); - keywordScrollPane = new javax.swing.JScrollPane(); - keywordList = new javax.swing.JList<>(); - javax.swing.JLabel parentLabel = new javax.swing.JLabel(); - parentScrollPane = new javax.swing.JScrollPane(); - parentList = new javax.swing.JList<>(); - hashSetCheckbox = new javax.swing.JCheckBox(); - hashSetScrollPane = new javax.swing.JScrollPane(); - hashSetList = new javax.swing.JList<>(); - objectsCheckbox = new javax.swing.JCheckBox(); - tagsCheckbox = new javax.swing.JCheckBox(); - interestingItemsCheckbox = new javax.swing.JCheckBox(); - scoreCheckbox = new javax.swing.JCheckBox(); - userCreatedCheckbox = new javax.swing.JCheckBox(); - notableCheckbox = new javax.swing.JCheckBox(); - objectsScrollPane = new javax.swing.JScrollPane(); - objectsList = new javax.swing.JList<>(); - tagsScrollPane = new javax.swing.JScrollPane(); - tagsList = new javax.swing.JList<>(); - interestingItemsScrollPane = new javax.swing.JScrollPane(); - interestingItemsList = new javax.swing.JList<>(); - scoreScrollPane = new javax.swing.JScrollPane(); - scoreList = new javax.swing.JList<>(); - excludeRadioButton = new javax.swing.JRadioButton(); - knownFilesCheckbox = new javax.swing.JCheckBox(); - javax.swing.JPanel fullRadioPanel = new javax.swing.JPanel(); - fullRadioButton = new javax.swing.JRadioButton(); - javax.swing.JPanel includeRadioPanel = new 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, 32767)); - includeRadioButton = new javax.swing.JRadioButton(); - javax.swing.JPanel parentTextPanel = new javax.swing.JPanel(); - parentTextField = new javax.swing.JTextField(); - searchButton = new javax.swing.JButton(); - 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<>(); - errorLabel = new javax.swing.JLabel(); - cancelButton = new javax.swing.JButton(); - stepTwoLabel = new javax.swing.JLabel(); - javax.swing.JLabel stepThreeLabel = new javax.swing.JLabel(); - - setMinimumSize(new java.awt.Dimension(10, 0)); - setPreferredSize(new java.awt.Dimension(321, 400)); - - filtersScrollPane.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.filtersScrollPane.border.title"))); // NOI18N - filtersScrollPane.setPreferredSize(new java.awt.Dimension(309, 400)); - - filtersPanel.setMinimumSize(new java.awt.Dimension(280, 500)); - filtersPanel.setPreferredSize(new java.awt.Dimension(280, 540)); - filtersPanel.setLayout(new java.awt.GridBagLayout()); - - org.openide.awt.Mnemonics.setLocalizedText(sizeCheckbox, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.sizeCheckbox.text")); // NOI18N - sizeCheckbox.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - sizeCheckboxActionPerformed(evt); - } - }); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 0; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.insets = new java.awt.Insets(6, 6, 4, 0); - filtersPanel.add(sizeCheckbox, gridBagConstraints); - - org.openide.awt.Mnemonics.setLocalizedText(dataSourceCheckbox, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.dataSourceCheckbox.text")); // NOI18N - dataSourceCheckbox.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - dataSourceCheckboxActionPerformed(evt); - } - }); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 1; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 0); - filtersPanel.add(dataSourceCheckbox, gridBagConstraints); - - org.openide.awt.Mnemonics.setLocalizedText(crFrequencyCheckbox, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.crFrequencyCheckbox.text")); // NOI18N - crFrequencyCheckbox.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - crFrequencyCheckboxActionPerformed(evt); - } - }); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 2; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 0); - filtersPanel.add(crFrequencyCheckbox, gridBagConstraints); - - org.openide.awt.Mnemonics.setLocalizedText(keywordCheckbox, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.keywordCheckbox.text")); // NOI18N - keywordCheckbox.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - keywordCheckboxActionPerformed(evt); - } - }); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 12; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 0); - filtersPanel.add(keywordCheckbox, gridBagConstraints); - - org.openide.awt.Mnemonics.setLocalizedText(parentCheckbox, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.parentCheckbox.text")); // NOI18N - parentCheckbox.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - parentCheckboxActionPerformed(evt); - } - }); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 7; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 0); - filtersPanel.add(parentCheckbox, gridBagConstraints); - - dataSourceList.setModel(new DefaultListModel()); - dataSourceList.setEnabled(false); - dataSourceList.setVisibleRowCount(5); - dataSourceScrollPane.setViewportView(dataSourceList); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 1; - gridBagConstraints.gridwidth = 3; - gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.weightx = 0.5; - gridBagConstraints.weighty = 0.1; - gridBagConstraints.insets = new java.awt.Insets(0, 4, 4, 6); - filtersPanel.add(dataSourceScrollPane, gridBagConstraints); - - parentPathButtonGroup.add(substringRadioButton); - org.openide.awt.Mnemonics.setLocalizedText(substringRadioButton, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.substringRadioButton.text")); // NOI18N - substringRadioButton.setEnabled(false); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 2; - gridBagConstraints.gridy = 9; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.weightx = 0.1; - gridBagConstraints.insets = new java.awt.Insets(0, 4, 4, 0); - filtersPanel.add(substringRadioButton, gridBagConstraints); - - org.openide.awt.Mnemonics.setLocalizedText(addButton, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.addButton.text")); // 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); - } - }); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 3; - gridBagConstraints.gridy = 11; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_END; - gridBagConstraints.insets = new java.awt.Insets(0, 10, 6, 6); - filtersPanel.add(addButton, gridBagConstraints); - - org.openide.awt.Mnemonics.setLocalizedText(deleteButton, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.deleteButton.text")); // 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); - } - }); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 3; - gridBagConstraints.gridy = 10; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_END; - gridBagConstraints.insets = new java.awt.Insets(0, 10, 4, 6); - filtersPanel.add(deleteButton, gridBagConstraints); - - sizeList.setModel(new DefaultListModel()); - sizeList.setEnabled(false); - sizeList.setVisibleRowCount(5); - sizeScrollPane.setViewportView(sizeList); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 0; - gridBagConstraints.gridwidth = 3; - gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.weightx = 0.5; - gridBagConstraints.weighty = 0.1; - gridBagConstraints.insets = new java.awt.Insets(6, 4, 4, 6); - filtersPanel.add(sizeScrollPane, gridBagConstraints); - - crFrequencyList.setModel(new DefaultListModel()); - crFrequencyList.setEnabled(false); - crFrequencyList.setVisibleRowCount(5); - crFrequencyScrollPane.setViewportView(crFrequencyList); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 2; - gridBagConstraints.gridwidth = 3; - gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.weightx = 0.5; - gridBagConstraints.weighty = 0.1; - gridBagConstraints.insets = new java.awt.Insets(0, 4, 4, 6); - filtersPanel.add(crFrequencyScrollPane, gridBagConstraints); - - keywordList.setModel(new DefaultListModel()); - keywordList.setEnabled(false); - keywordList.setVisibleRowCount(3); - keywordScrollPane.setViewportView(keywordList); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 12; - gridBagConstraints.gridwidth = 3; - gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.weightx = 0.5; - gridBagConstraints.insets = new java.awt.Insets(0, 4, 4, 6); - filtersPanel.add(keywordScrollPane, gridBagConstraints); - - org.openide.awt.Mnemonics.setLocalizedText(parentLabel, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.parentLabel.text")); // NOI18N - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 8; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 0); - filtersPanel.add(parentLabel, gridBagConstraints); - - parentList.setModel(new DefaultListModel()); - 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); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 7; - gridBagConstraints.gridwidth = 3; - gridBagConstraints.gridheight = 2; - gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.weightx = 0.5; - gridBagConstraints.weighty = 0.05; - gridBagConstraints.insets = new java.awt.Insets(0, 4, 4, 6); - filtersPanel.add(parentScrollPane, gridBagConstraints); - - org.openide.awt.Mnemonics.setLocalizedText(hashSetCheckbox, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.hashSetCheckbox.text")); // NOI18N - hashSetCheckbox.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - hashSetCheckboxActionPerformed(evt); - } - }); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 4; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 0); - filtersPanel.add(hashSetCheckbox, gridBagConstraints); - - hashSetList.setModel(new DefaultListModel()); - hashSetList.setEnabled(false); - hashSetList.setVisibleRowCount(3); - hashSetScrollPane.setViewportView(hashSetList); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 4; - gridBagConstraints.gridwidth = 3; - gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.weightx = 0.5; - gridBagConstraints.weighty = 0.05; - gridBagConstraints.insets = new java.awt.Insets(0, 4, 4, 6); - filtersPanel.add(hashSetScrollPane, gridBagConstraints); - - org.openide.awt.Mnemonics.setLocalizedText(objectsCheckbox, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.objectsCheckbox.text")); // NOI18N - objectsCheckbox.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - objectsCheckboxActionPerformed(evt); - } - }); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 6; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 0); - filtersPanel.add(objectsCheckbox, gridBagConstraints); - - org.openide.awt.Mnemonics.setLocalizedText(tagsCheckbox, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.tagsCheckbox.text")); // NOI18N - tagsCheckbox.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - tagsCheckboxActionPerformed(evt); - } - }); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 13; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 0); - filtersPanel.add(tagsCheckbox, gridBagConstraints); - - org.openide.awt.Mnemonics.setLocalizedText(interestingItemsCheckbox, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.interestingItemsCheckbox.text")); // NOI18N - interestingItemsCheckbox.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - interestingItemsCheckboxActionPerformed(evt); - } - }); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 5; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 0); - filtersPanel.add(interestingItemsCheckbox, gridBagConstraints); - - org.openide.awt.Mnemonics.setLocalizedText(scoreCheckbox, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.scoreCheckbox.text")); // NOI18N - scoreCheckbox.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - scoreCheckboxActionPerformed(evt); - } - }); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 14; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 0); - filtersPanel.add(scoreCheckbox, gridBagConstraints); - - org.openide.awt.Mnemonics.setLocalizedText(userCreatedCheckbox, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.userCreatedCheckbox.text")); // NOI18N - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 3; - gridBagConstraints.gridwidth = 4; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 6); - filtersPanel.add(userCreatedCheckbox, gridBagConstraints); - - org.openide.awt.Mnemonics.setLocalizedText(notableCheckbox, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.notableCheckbox.text")); // NOI18N - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 15; - gridBagConstraints.gridwidth = 4; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 6); - filtersPanel.add(notableCheckbox, gridBagConstraints); - - objectsList.setModel(new DefaultListModel()); - objectsList.setEnabled(false); - objectsList.setVisibleRowCount(2); - objectsScrollPane.setViewportView(objectsList); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 6; - gridBagConstraints.gridwidth = 3; - gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.weightx = 0.5; - gridBagConstraints.weighty = 0.05; - gridBagConstraints.insets = new java.awt.Insets(0, 4, 4, 6); - filtersPanel.add(objectsScrollPane, gridBagConstraints); - - tagsList.setModel(new DefaultListModel()); - tagsList.setEnabled(false); - tagsList.setVisibleRowCount(3); - tagsScrollPane.setViewportView(tagsList); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 13; - gridBagConstraints.gridwidth = 3; - gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.weightx = 0.5; - gridBagConstraints.insets = new java.awt.Insets(0, 4, 4, 6); - filtersPanel.add(tagsScrollPane, gridBagConstraints); - - interestingItemsList.setModel(new DefaultListModel()); - interestingItemsList.setEnabled(false); - interestingItemsList.setVisibleRowCount(2); - interestingItemsScrollPane.setViewportView(interestingItemsList); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 5; - gridBagConstraints.gridwidth = 3; - gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.weightx = 0.5; - gridBagConstraints.weighty = 0.05; - gridBagConstraints.insets = new java.awt.Insets(0, 4, 4, 6); - filtersPanel.add(interestingItemsScrollPane, gridBagConstraints); - - scoreList.setModel(new DefaultListModel()); - scoreList.setEnabled(false); - scoreList.setVisibleRowCount(3); - scoreScrollPane.setViewportView(scoreList); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 14; - gridBagConstraints.gridwidth = 3; - gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.weightx = 0.5; - gridBagConstraints.insets = new java.awt.Insets(0, 4, 4, 6); - filtersPanel.add(scoreScrollPane, gridBagConstraints); - - parentIncludeButtonGroup.add(excludeRadioButton); - org.openide.awt.Mnemonics.setLocalizedText(excludeRadioButton, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.excludeRadioButton.text")); // NOI18N - excludeRadioButton.setEnabled(false); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 2; - gridBagConstraints.gridy = 10; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.weightx = 0.1; - gridBagConstraints.insets = new java.awt.Insets(0, 4, 4, 0); - filtersPanel.add(excludeRadioButton, gridBagConstraints); - - org.openide.awt.Mnemonics.setLocalizedText(knownFilesCheckbox, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.knownFilesCheckbox.text")); // NOI18N - knownFilesCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.knownFilesCheckbox.toolTipText")); // NOI18N - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 16; - gridBagConstraints.gridwidth = 4; - gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; - gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 6); - filtersPanel.add(knownFilesCheckbox, gridBagConstraints); - - parentPathButtonGroup.add(fullRadioButton); - fullRadioButton.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(fullRadioButton, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.fullRadioButton.text")); // NOI18N - fullRadioButton.setEnabled(false); - - javax.swing.GroupLayout fullRadioPanelLayout = new javax.swing.GroupLayout(fullRadioPanel); - fullRadioPanel.setLayout(fullRadioPanelLayout); - fullRadioPanelLayout.setHorizontalGroup( - fullRadioPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, fullRadioPanelLayout.createSequentialGroup() - .addContainerGap(58, Short.MAX_VALUE) - .addComponent(fullRadioButton) - .addGap(20, 20, 20)) - ); - fullRadioPanelLayout.setVerticalGroup( - fullRadioPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(fullRadioPanelLayout.createSequentialGroup() - .addComponent(fullRadioButton) - .addGap(0, 4, Short.MAX_VALUE)) - ); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 9; - gridBagConstraints.gridwidth = 2; - gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; - gridBagConstraints.weightx = 1.0; - filtersPanel.add(fullRadioPanel, gridBagConstraints); - - parentIncludeButtonGroup.add(includeRadioButton); - includeRadioButton.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(includeRadioButton, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.includeRadioButton.text")); // NOI18N - includeRadioButton.setEnabled(false); - - javax.swing.GroupLayout includeRadioPanelLayout = new javax.swing.GroupLayout(includeRadioPanel); - includeRadioPanel.setLayout(includeRadioPanelLayout); - includeRadioPanelLayout.setHorizontalGroup( - includeRadioPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(includeRadioPanelLayout.createSequentialGroup() - .addComponent(filler2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 58, Short.MAX_VALUE) - .addComponent(includeRadioButton)) - ); - includeRadioPanelLayout.setVerticalGroup( - includeRadioPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(filler2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(includeRadioButton) - ); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 10; - gridBagConstraints.gridwidth = 2; - gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; - gridBagConstraints.weightx = 1.0; - filtersPanel.add(includeRadioPanel, gridBagConstraints); - - parentTextField.setEnabled(false); - - javax.swing.GroupLayout parentTextPanelLayout = new javax.swing.GroupLayout(parentTextPanel); - parentTextPanel.setLayout(parentTextPanelLayout); - parentTextPanelLayout.setHorizontalGroup( - parentTextPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, parentTextPanelLayout.createSequentialGroup() - .addGap(0, 0, 0) - .addComponent(parentTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 71, Short.MAX_VALUE)) - ); - parentTextPanelLayout.setVerticalGroup( - parentTextPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(parentTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - ); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 11; - gridBagConstraints.gridwidth = 2; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.weightx = 1.5; - gridBagConstraints.insets = new java.awt.Insets(0, 4, 4, 0); - filtersPanel.add(parentTextPanel, gridBagConstraints); - - filtersScrollPane.setViewportView(filtersPanel); - - org.openide.awt.Mnemonics.setLocalizedText(searchButton, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.searchButton.text")); // NOI18N - searchButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - searchButtonActionPerformed(evt); - } - }); - - sortingPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.sortingPanel.border.title"))); // NOI18N - sortingPanel.setPreferredSize(new java.awt.Dimension(345, 112)); - - org.openide.awt.Mnemonics.setLocalizedText(orderGroupsByLabel, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.orderGroupsByLabel.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(orderByLabel, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.orderByLabel.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(groupByLabel, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.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) - .addGroup(sortingPanelLayout.createSequentialGroup() - .addGroup(sortingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(groupByLabel) - .addComponent(orderByLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(sortingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(groupSortingComboBox, javax.swing.GroupLayout.Alignment.LEADING, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(orderByCombobox, javax.swing.GroupLayout.Alignment.LEADING, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(groupByCombobox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) - .addContainerGap()) - ); - sortingPanelLayout.setVerticalGroup( - sortingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(sortingPanelLayout.createSequentialGroup() - .addGap(6, 6, 6) - .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)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .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)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(sortingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(orderByCombobox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(orderByLabel)) - .addContainerGap()) - ); - - errorLabel.setForeground(new java.awt.Color(255, 0, 0)); - - org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.cancelButton.text")); // NOI18N - cancelButton.setEnabled(false); - cancelButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - cancelButtonActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(stepThreeLabel, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.stepThreeLabel.text")); // NOI18N - - 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(6, 6, 6) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(stepTwoLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addContainerGap()) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(cancelButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(searchButton)) - .addComponent(stepThreeLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(filtersScrollPane, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(sortingPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 309, Short.MAX_VALUE)) - .addGap(6, 6, 6)))) - ); - - layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cancelButton, searchButton}); - - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGap(6, 6, 6) - .addComponent(stepTwoLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(filtersScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 207, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(stepThreeLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(sortingPanel, 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.LEADING) - .addComponent(errorLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(cancelButton) - .addComponent(searchButton))) - .addGap(6, 6, 6)) - ); - }// //GEN-END:initComponents - - private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed - // Get the selected filters - List filters = getFilters(); - enableSearch(false); - DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.SearchStartedEvent(fileType)); - - // Get the grouping attribute and group sorting method - FileSearch.AttributeType groupingAttr = getGroupingAttribute(); - FileGroup.GroupSortingAlgorithm groupSortAlgorithm = getGroupSortingMethod(); - - // Get the file sorting method - FileSorter.SortingMethod fileSort = getFileSortingMethod(); - 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 File Discovery", ex); - } - } - searchWorker = new SearchWorker(centralRepoDb, filters, groupingAttr, groupSortAlgorithm, fileSort); - searchWorker.execute(); - }//GEN-LAST:event_searchButtonActionPerformed - - /** - * Set the enabled status of the search controls. - * - * @param enabled Boolean which indicates if the search should be enabled. - * True if the search button and controls should be enabled, - * false otherwise. - */ - private void enableSearch(boolean enabled) { - if (enabled) { - DiscoveryTopComponent.getTopComponent().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - } else { - DiscoveryTopComponent.getTopComponent().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - } - if (null != fileType) { - switch (fileType) { - case IMAGE: - imagesSelected(enabled, false); - break; - case VIDEO: - videosSelected(enabled, false); - break; - case DOCUMENTS: - documentsSelected(enabled, false); - break; - default: - break; - } - } - searchButton.setEnabled(enabled); - cancelButton.setEnabled(!enabled); - orderByCombobox.setEnabled(enabled); - groupByCombobox.setEnabled(enabled); - groupSortingComboBox.setEnabled(enabled); - } - - /** - * Update the user interface when a search has been cancelled. - * - * @param searchCancelledEvent The SearchCancelledEvent which was received. - */ - @Subscribe - void handleSearchCancelledEvent(DiscoveryEventUtils.SearchCancelledEvent searchCancelledEvent) { - SwingUtilities.invokeLater(() -> { - enableSearch(true); - }); - } - - /** - * Update the user interface when a search has been successfully completed. - * - * @param searchCompleteEvent The SearchCompleteEvent which was received. - */ - @Subscribe - void handleSearchCompleteEvent(DiscoveryEventUtils.SearchCompleteEvent searchCompleteEvent) { - SwingUtilities.invokeLater(() -> { - enableSearch(true); - }); - } - - private void parentCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_parentCheckboxActionPerformed - parentFilterSettings(true, true, parentCheckbox.isSelected(), null); - }//GEN-LAST:event_parentCheckboxActionPerformed - - private void keywordCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_keywordCheckboxActionPerformed - keywordList.setEnabled(keywordCheckbox.isSelected()); - }//GEN-LAST:event_keywordCheckboxActionPerformed - - private void sizeCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sizeCheckboxActionPerformed - sizeList.setEnabled(sizeCheckbox.isSelected()); - }//GEN-LAST:event_sizeCheckboxActionPerformed - - private void crFrequencyCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_crFrequencyCheckboxActionPerformed - crFrequencyList.setEnabled(crFrequencyCheckbox.isSelected()); - }//GEN-LAST:event_crFrequencyCheckboxActionPerformed - - 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); - validateFields(); - parentTextField.setText(""); - } - }//GEN-LAST:event_addButtonActionPerformed - - /** - * Cancel the current search. - */ - void cancelSearch() { - if (searchWorker != null) { - searchWorker.cancel(true); - } - } - - private void deleteButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteButtonActionPerformed - int index = parentList.getSelectedIndex(); - if (index >= 0) { - parentListModel.remove(index); - } - validateFields(); - }//GEN-LAST:event_deleteButtonActionPerformed - - 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 dataSourceCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dataSourceCheckboxActionPerformed - dataSourceList.setEnabled(dataSourceCheckbox.isSelected()); - }//GEN-LAST:event_dataSourceCheckboxActionPerformed - - private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed - cancelSearch(); - }//GEN-LAST:event_cancelButtonActionPerformed - - private void hashSetCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hashSetCheckboxActionPerformed - hashSetList.setEnabled(hashSetCheckbox.isSelected()); - }//GEN-LAST:event_hashSetCheckboxActionPerformed - - private void objectsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_objectsCheckboxActionPerformed - objectsList.setEnabled(objectsCheckbox.isSelected()); - }//GEN-LAST:event_objectsCheckboxActionPerformed - - private void tagsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tagsCheckboxActionPerformed - tagsList.setEnabled(tagsCheckbox.isSelected()); - }//GEN-LAST:event_tagsCheckboxActionPerformed - - private void interestingItemsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_interestingItemsCheckboxActionPerformed - interestingItemsList.setEnabled(interestingItemsCheckbox.isSelected()); - }//GEN-LAST:event_interestingItemsCheckboxActionPerformed - - private void scoreCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scoreCheckboxActionPerformed - scoreList.setEnabled(scoreCheckbox.isSelected()); - }//GEN-LAST:event_scoreCheckboxActionPerformed - - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton addButton; - private javax.swing.JButton cancelButton; - private javax.swing.JCheckBox crFrequencyCheckbox; - private javax.swing.JList crFrequencyList; - private javax.swing.JScrollPane crFrequencyScrollPane; - private javax.swing.JCheckBox dataSourceCheckbox; - private javax.swing.JList dataSourceList; - private javax.swing.JScrollPane dataSourceScrollPane; - private javax.swing.JButton deleteButton; - private javax.swing.JLabel errorLabel; - private javax.swing.JRadioButton excludeRadioButton; - private javax.swing.JRadioButton fullRadioButton; - private javax.swing.JComboBox groupByCombobox; - private javax.swing.JComboBox groupSortingComboBox; - private javax.swing.JCheckBox hashSetCheckbox; - private javax.swing.JList hashSetList; - private javax.swing.JScrollPane hashSetScrollPane; - private javax.swing.JRadioButton includeRadioButton; - private javax.swing.JCheckBox interestingItemsCheckbox; - private javax.swing.JList interestingItemsList; - private javax.swing.JScrollPane interestingItemsScrollPane; - private javax.swing.JCheckBox keywordCheckbox; - private javax.swing.JList keywordList; - private javax.swing.JScrollPane keywordScrollPane; - private javax.swing.JCheckBox knownFilesCheckbox; - private javax.swing.JCheckBox notableCheckbox; - private javax.swing.JCheckBox objectsCheckbox; - private javax.swing.JList objectsList; - private javax.swing.JScrollPane objectsScrollPane; - private javax.swing.JComboBox orderByCombobox; - private javax.swing.JCheckBox parentCheckbox; - private javax.swing.JList parentList; - private javax.swing.JScrollPane parentScrollPane; - private javax.swing.JTextField parentTextField; - private javax.swing.JCheckBox scoreCheckbox; - private javax.swing.JList scoreList; - private javax.swing.JScrollPane scoreScrollPane; - private javax.swing.JButton searchButton; - private javax.swing.JCheckBox sizeCheckbox; - private javax.swing.JList sizeList; - private javax.swing.JScrollPane sizeScrollPane; - private javax.swing.JLabel stepTwoLabel; - private javax.swing.JRadioButton substringRadioButton; - private javax.swing.JCheckBox tagsCheckbox; - private javax.swing.JList tagsList; - private javax.swing.JScrollPane tagsScrollPane; - private javax.swing.JCheckBox userCreatedCheckbox; - // End of variables declaration//GEN-END:variables - -} diff --git a/Core/src/org/sleuthkit/autopsy/filequery/OpenFileDiscoveryAction.java b/Core/src/org/sleuthkit/autopsy/filequery/OpenFileDiscoveryAction.java deleted file mode 100644 index 188939c6b6..0000000000 --- a/Core/src/org/sleuthkit/autopsy/filequery/OpenFileDiscoveryAction.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Autopsy - * - * Copyright 2019 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.filequery; - -import java.awt.Component; -import java.util.HashMap; -import java.util.Map; -import java.util.logging.Level; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JOptionPane; -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; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.datamodel.DataSource; -import org.sleuthkit.datamodel.IngestJobInfo; -import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * Class to open the File Discovery top component. Allows the user to run - * searches and see results. - */ -@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.newpackage.OpenFileDiscoveryAction") -@ActionReferences(value = { - @ActionReference(path = "Menu/Tools", position = 103) - , - @ActionReference(path = "Toolbars/Case", position = 105)}) -@ActionRegistration(displayName = "#CTL_OpenFileDiscoveryAction", lazy = false) -@NbBundle.Messages({"CTL_OpenFileDiscoveryAction=File Discovery"}) -public final class OpenFileDiscoveryAction extends CallableSystemAction implements Presenter.Toolbar { - - private static final Logger logger = Logger.getLogger(OpenFileDiscoveryAction.class.getName()); - - private static final String DISPLAY_NAME = Bundle.CTL_OpenFileDiscoveryAction(); - private static final long serialVersionUID = 1L; - private final JButton toolbarButton = new JButton(); - - public OpenFileDiscoveryAction() { - toolbarButton.addActionListener(OpenFileDiscoveryAction.this::actionPerformed); - this.setEnabled(false); - } - - @Override - public boolean isEnabled() { - return Case.isCaseOpen(); - } - - @NbBundle.Messages({"OpenFileDiscoveryAction.resultsIncomplete.text=Results may be incomplete"}) - - @Override - @SuppressWarnings("fallthrough") - public void performAction() { - final DiscoveryTopComponent tc = DiscoveryTopComponent.getTopComponent(); - if (tc != null) { - if (tc.isOpened() == false) { - tc.open(); - tc.updateSearchSettings(); - displayErrorMessage(tc); - } - tc.toFront(); - tc.requestActive(); - - } - } - - /** - * Private helper method to display an error message when the results of the - * File Discovery Top component may be incomplete. - * - * @param tc The File Discovery Top component. - */ - private void displayErrorMessage(DiscoveryTopComponent tc) { - //check if modules run and assemble message - try { - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - Map 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(tc, message, Bundle.OpenFileDiscoveryAction_resultsIncomplete_text(), JOptionPane.INFORMATION_MESSAGE); - } - } catch (NoCurrentCaseException | TskCoreException ex) { - logger.log(Level.WARNING, "Exception while determining which modules have been run for File Discovery", ex); - } - } - - /** - * 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 - } -}