19 package org.sleuthkit.autopsy.commonpropertiessearch;
23 import java.awt.Dimension;
24 import java.sql.SQLException;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.HashMap;
28 import java.util.List;
30 import java.util.Objects;
31 import java.util.Observable;
32 import java.util.Observer;
33 import java.util.concurrent.ExecutionException;
34 import java.util.logging.Level;
35 import javax.swing.JPanel;
36 import javax.swing.SwingWorker;
37 import javax.swing.event.DocumentEvent;
38 import javax.swing.event.DocumentListener;
39 import org.netbeans.api.progress.ProgressHandle;
40 import org.openide.DialogDisplayer;
41 import org.openide.NotifyDescriptor;
42 import org.openide.explorer.ExplorerManager;
43 import org.openide.nodes.Node;
44 import org.openide.util.NbBundle;
45 import org.openide.util.NbBundle.Messages;
46 import org.openide.windows.WindowManager;
73 @SuppressWarnings(
"PMD.SingularField")
74 final class CommonAttributePanel extends javax.swing.JDialog implements Observer {
76 private static final Logger LOGGER = Logger.getLogger(CommonAttributePanel.class.getName());
77 private static final long serialVersionUID = 1L;
79 private static final Long NO_DATA_SOURCE_SELECTED = -1L;
81 private final UserInputErrorManager errorManager;
83 private int percentageThresholdValue = 20;
85 private final IntraCasePanel intraCasePanel;
86 private final InterCasePanel interCasePanel;
92 "CommonAttributePanel.title=Common Property Panel",
93 "CommonAttributePanel.exception=Unexpected Exception loading DataSources.",
94 "CommonAttributePanel.frame.title=Find Common Properties",
95 "CommonAttributePanel.intraCasePanel.title=Curren Case Options"})
96 CommonAttributePanel() {
97 super(WindowManager.getDefault().getMainWindow(), Bundle.CommonAttributePanel_frame_title(),
true);
99 this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
101 interCasePanel =
new InterCasePanel();
102 interCasePanel.setVisible(
true);
103 interCasePanel.setSize((
int) containerPanel.getPreferredSize().getWidth(), (int) containerPanel.getPreferredSize().getHeight());
105 intraCasePanel =
new IntraCasePanel();
106 intraCasePanel.setVisible(
true);
107 intraCasePanel.setSize((
int) containerPanel.getPreferredSize().getWidth(), (int) containerPanel.getPreferredSize().getHeight());
109 this.setupDataSources();
111 if (CommonAttributePanel.isEamDbAvailableForIntercaseSearch()) {
113 this.interCasePanel.setupCorrelationTypeFilter();
114 this.interCaseRadio.setSelected(
true);
115 switchInnerPanel(interCasePanel);
117 this.disableIntercaseSearch();
118 this.intraCaseRadio.setSelected(
true);
119 switchInnerPanel(intraCasePanel);
124 this.updatePercentageOptions(CommonAttributePanel.getNumberOfDataSourcesAvailable());
126 this.errorManager =
new UserInputErrorManager();
128 this.percentageThresholdInputBox.getDocument().addDocumentListener(
new DocumentListener() {
130 private final Dimension preferredSize = CommonAttributePanel.this.percentageThresholdInputBox.getPreferredSize();
132 private void maintainSize() {
133 CommonAttributePanel.this.percentageThresholdInputBox.setSize(preferredSize);
137 public void insertUpdate(DocumentEvent event) {
139 CommonAttributePanel.this.percentageThresholdChanged();
143 public void removeUpdate(DocumentEvent event) {
145 CommonAttributePanel.this.percentageThresholdChanged();
149 public void changedUpdate(DocumentEvent event) {
151 CommonAttributePanel.this.percentageThresholdChanged();
163 static boolean isEamDbAvailableForIntercaseSearch() {
165 return EamDb.isEnabled()
166 && EamDb.getInstance() != null
167 && EamDb.getInstance().getCases().size() > 1
169 && Case.getCurrentCase() != null
170 && EamDb.getInstance().getCase(Case.getCurrentCase()) != null;
171 }
catch (EamDbException ex) {
172 LOGGER.log(Level.SEVERE,
"Unexpected exception while checking for EamDB enabled.", ex);
178 public void update(Observable o, Object arg) {
179 checkFileTypeCheckBoxState();
189 private static Long getNumberOfDataSourcesAvailable() {
191 if (EamDb.isEnabled()
192 && EamDb.getInstance() != null) {
193 return EamDb.getInstance().getCountUniqueDataSources();
195 }
catch (EamDbException ex) {
196 LOGGER.log(Level.SEVERE,
"Unexpected exception while checking for EamDB enabled.", ex);
205 private void disableIntercaseSearch() {
206 this.intraCaseRadio.setSelected(
true);
207 this.interCaseRadio.setEnabled(
false);
214 "CommonAttributePanel.search.results.pathText=Common Properties Results",
215 "CommonAttributePanel.search.done.searchProgressGathering=Gathering Common Properties Results.",
216 "CommonAttributePanel.search.done.searchProgressDisplay=Displaying Common Properties Results.",
217 "CommonAttributePanel.search.done.tskCoreException=Unable to run query against DB.",
218 "CommonAttributePanel.search.done.noCurrentCaseException=Unable to open case file.",
219 "CommonAttributePanel.search.done.exception=Unexpected exception running Find Common Properties.",
220 "CommonAttributePanel.search.done.interupted=Something went wrong finding common properties.",
221 "CommonAttributePanel.search.done.sqlException=Unable to query db for properties or data sources.",
222 "CommonAttributePanel.search.done.noResults=No results found."})
223 private void searchByCount() {
224 new SwingWorker<CommonAttributeCountSearchResults, Void>() {
226 private String tabTitle;
227 private ProgressHandle progress;
230 protected CommonAttributeCountSearchResults doInBackground() throws TskCoreException, NoCurrentCaseException, SQLException, EamDbException {
231 progress = ProgressHandle.createHandle(Bundle.CommonAttributePanel_search_done_searchProgressGathering());
233 progress.switchToIndeterminate();
235 Long dataSourceId = intraCasePanel.getSelectedDataSourceId();
236 Integer caseId = interCasePanel.getSelectedCaseId();
238 AbstractCommonAttributeSearcher builder;
239 CommonAttributeCountSearchResults metadata;
241 boolean filterByMedia =
false;
242 boolean filterByDocuments =
false;
244 int percentageThreshold = CommonAttributePanel.this.percentageThresholdValue;
246 if (!CommonAttributePanel.this.percentageThresholdCheck.isSelected()) {
248 percentageThreshold = 0;
251 if (CommonAttributePanel.this.interCaseRadio.isSelected()) {
252 CorrelationAttributeInstance.Type corType = interCasePanel.getSelectedCorrelationType();
253 if (interCasePanel.fileCategoriesButtonIsSelected()) {
254 filterByMedia = interCasePanel.pictureVideoCheckboxIsSelected();
255 filterByDocuments = interCasePanel.documentsCheckboxIsSelected();
257 if (corType == null) {
258 corType = CorrelationAttributeInstance.getDefaultCorrelationTypes().get(0);
260 if (caseId == InterCasePanel.NO_CASE_SELECTED) {
261 builder =
new AllInterCaseCommonAttributeSearcher(filterByMedia, filterByDocuments, corType, percentageThreshold);
264 builder =
new SingleInterCaseCommonAttributeSearcher(caseId, filterByMedia, filterByDocuments, corType, percentageThreshold);
268 if (intraCasePanel.fileCategoriesButtonIsSelected()) {
269 filterByMedia = intraCasePanel.pictureVideoCheckboxIsSelected();
270 filterByDocuments = intraCasePanel.documentsCheckboxIsSelected();
272 if (Objects.equals(dataSourceId, CommonAttributePanel.NO_DATA_SOURCE_SELECTED)) {
273 builder =
new AllIntraCaseCommonAttributeSearcher(intraCasePanel.getDataSourceMap(), filterByMedia, filterByDocuments, percentageThreshold);
275 builder =
new SingleIntraCaseCommonAttributeSearcher(dataSourceId, intraCasePanel.getDataSourceMap(), filterByMedia, filterByDocuments, percentageThreshold);
279 metadata = builder.findMatchesByCount();
280 metadata.filterMetadata();
281 this.tabTitle = builder.getTabTitle();
286 protected void done() {
289 CommonAttributeCountSearchResults metadata = this.
get();
290 boolean noKeysExist = metadata.getMetadata().keySet().isEmpty();
292 Node commonFilesNode =
new TableFilterNode(
new EmptyNode(Bundle.CommonAttributePanel_search_done_noResults()),
true);
293 progress.setDisplayName(Bundle.CommonAttributePanel_search_done_searchProgressDisplay());
294 DataResultTopComponent.createInstance(tabTitle, Bundle.CommonAttributePanel_search_results_pathText(), commonFilesNode, 1);
297 CorrelationAttributeInstance.Type correlationType = null;
298 if (interCaseRadio.isSelected()){
299 correlationType = interCasePanel.getSelectedCorrelationType();
301 Node commonFilesNode =
new CommonAttributeSearchResultRootNode(metadata, correlationType);
302 DataResultFilterNode dataResultFilterNode =
new DataResultFilterNode(commonFilesNode, ExplorerManager.find(CommonAttributePanel.this));
303 TableFilterNode tableFilterWithDescendantsNode =
new TableFilterNode(dataResultFilterNode, 3);
304 DataResultViewerTable table =
new CommonAttributesSearchResultsViewerTable();
305 Collection<DataResultViewer> viewers =
new ArrayList<>(1);
307 progress.setDisplayName(Bundle.CommonAttributePanel_search_done_searchProgressDisplay());
308 DataResultTopComponent.createInstance(tabTitle, Bundle.CommonAttributePanel_search_results_pathText(), tableFilterWithDescendantsNode, metadata.size(), viewers);
311 }
catch (InterruptedException ex) {
312 LOGGER.log(Level.SEVERE,
"Interrupted while loading Common Files", ex);
313 MessageNotifyUtil.Message.error(Bundle.CommonAttributePanel_search_done_interupted());
314 }
catch (ExecutionException ex) {
316 Throwable inner = ex.getCause();
317 if (inner instanceof TskCoreException) {
318 LOGGER.log(Level.SEVERE,
"Failed to load files from database.", ex);
319 errorMessage = Bundle.CommonAttributePanel_search_done_tskCoreException();
320 }
else if (inner instanceof NoCurrentCaseException) {
321 LOGGER.log(Level.SEVERE,
"Current case has been closed.", ex);
322 errorMessage = Bundle.CommonAttributePanel_search_done_noCurrentCaseException();
323 }
else if (inner instanceof SQLException) {
324 LOGGER.log(Level.SEVERE,
"Unable to query db for files.", ex);
325 errorMessage = Bundle.CommonAttributePanel_search_done_sqlException();
327 LOGGER.log(Level.SEVERE,
"Unexpected exception while running Common Files Search.", ex);
328 errorMessage = Bundle.CommonAttributePanel_search_done_exception();
330 MessageNotifyUtil.Message.error(errorMessage);
341 private void searchByCase() {
342 new SwingWorker<CommonAttributeCaseSearchResults, Void>() {
343 private String tabTitle;
344 private ProgressHandle progress;
347 protected CommonAttributeCaseSearchResults doInBackground() throws TskCoreException, NoCurrentCaseException, SQLException, EamDbException {
348 progress = ProgressHandle.createHandle(Bundle.CommonAttributePanel_search_done_searchProgressGathering());
350 progress.switchToIndeterminate();
351 Long dataSourceId = intraCasePanel.getSelectedDataSourceId();
352 Integer caseId = interCasePanel.getSelectedCaseId();
353 AbstractCommonAttributeSearcher builder;
354 CommonAttributeCaseSearchResults metadata;
355 boolean filterByMedia =
false;
356 boolean filterByDocuments =
false;
357 int percentageThreshold = CommonAttributePanel.this.percentageThresholdValue;
358 if (!CommonAttributePanel.this.percentageThresholdCheck.isSelected()) {
360 percentageThreshold = 0;
362 if (CommonAttributePanel.this.interCaseRadio.isSelected()) {
363 CorrelationAttributeInstance.Type corType = interCasePanel.getSelectedCorrelationType();
364 if (interCasePanel.fileCategoriesButtonIsSelected()) {
365 filterByMedia = interCasePanel.pictureVideoCheckboxIsSelected();
366 filterByDocuments = interCasePanel.documentsCheckboxIsSelected();
368 if (corType == null) {
369 corType = CorrelationAttributeInstance.getDefaultCorrelationTypes().get(0);
371 if (caseId == InterCasePanel.NO_CASE_SELECTED) {
372 builder =
new AllInterCaseCommonAttributeSearcher(filterByMedia, filterByDocuments, corType, percentageThreshold);
374 builder =
new SingleInterCaseCommonAttributeSearcher(caseId, filterByMedia, filterByDocuments, corType, percentageThreshold);
377 if (intraCasePanel.fileCategoriesButtonIsSelected()) {
378 filterByMedia = intraCasePanel.pictureVideoCheckboxIsSelected();
379 filterByDocuments = intraCasePanel.documentsCheckboxIsSelected();
381 if (Objects.equals(dataSourceId, CommonAttributePanel.NO_DATA_SOURCE_SELECTED)) {
382 builder =
new AllIntraCaseCommonAttributeSearcher(intraCasePanel.getDataSourceMap(), filterByMedia, filterByDocuments, percentageThreshold);
384 builder =
new SingleIntraCaseCommonAttributeSearcher(dataSourceId, intraCasePanel.getDataSourceMap(), filterByMedia, filterByDocuments, percentageThreshold);
387 metadata = builder.findMatchesByCase();
388 this.tabTitle = builder.getTabTitle();
393 protected void done() {
396 CommonAttributeCaseSearchResults metadata = this.
get();
397 if (metadata.getMetadata().keySet().isEmpty()) {
398 Node commonFilesNode =
new TableFilterNode(
new EmptyNode(Bundle.CommonAttributePanel_search_done_noResults()),
true);
399 progress.setDisplayName(Bundle.CommonAttributePanel_search_done_searchProgressDisplay());
400 DataResultTopComponent.createInstance(tabTitle, Bundle.CommonAttributePanel_search_results_pathText(), commonFilesNode, 1);
403 Node commonFilesNode =
new CommonAttributeSearchResultRootNode(metadata);
404 DataResultFilterNode dataResultFilterNode =
new DataResultFilterNode(commonFilesNode, ExplorerManager.find(CommonAttributePanel.this));
405 TableFilterNode tableFilterWithDescendantsNode =
new TableFilterNode(dataResultFilterNode, 3);
406 DataResultViewerTable table =
new CommonAttributesSearchResultsViewerTable();
407 Collection<DataResultViewer> viewers =
new ArrayList<>(1);
409 progress.setDisplayName(Bundle.CommonAttributePanel_search_done_searchProgressDisplay());
411 DataResultTopComponent.createInstance(tabTitle, Bundle.CommonAttributePanel_search_results_pathText(), tableFilterWithDescendantsNode, 0, viewers);
413 }
catch (InterruptedException ex) {
414 LOGGER.log(Level.SEVERE,
"Interrupted while loading Common Files", ex);
415 MessageNotifyUtil.Message.error(Bundle.CommonAttributePanel_search_done_interupted());
416 }
catch (ExecutionException ex) {
418 Throwable inner = ex.getCause();
419 if (inner instanceof TskCoreException) {
420 LOGGER.log(Level.SEVERE,
"Failed to load files from database.", ex);
421 errorMessage = Bundle.CommonAttributePanel_search_done_tskCoreException();
422 }
else if (inner instanceof NoCurrentCaseException) {
423 LOGGER.log(Level.SEVERE,
"Current case has been closed.", ex);
424 errorMessage = Bundle.CommonAttributePanel_search_done_noCurrentCaseException();
425 }
else if (inner instanceof SQLException) {
426 LOGGER.log(Level.SEVERE,
"Unable to query db for files.", ex);
427 errorMessage = Bundle.CommonAttributePanel_search_done_sqlException();
429 LOGGER.log(Level.SEVERE,
"Unexpected exception while running Common Files Search.", ex);
430 errorMessage = Bundle.CommonAttributePanel_search_done_exception();
432 MessageNotifyUtil.Message.error(errorMessage);
448 "CommonAttributePanel.setupDataSources.done.tskCoreException=Unable to run query against DB.",
449 "CommonAttributePanel.setupDataSources.done.noCurrentCaseException=Unable to open case file.",
450 "CommonAttributePanel.setupDataSources.done.exception=Unexpected exception loading data sources.",
451 "CommonAttributePanel.setupDataSources.done.interupted=Something went wrong building the Common Files Search dialog box.",
452 "CommonAttributePanel.setupDataSources.done.sqlException=Unable to query db for data sources.",
453 "CommonAttributePanel.setupDataSources.updateUi.noDataSources=No data sources were found."})
455 private void setupDataSources() {
457 new SwingWorker<Map<Long, String>, Void>() {
463 private void updateUi() {
465 final Map<Long, String> dataSourceMap = CommonAttributePanel.this.intraCasePanel.getDataSourceMap();
467 String[] dataSourcesNames =
new String[dataSourceMap.size()];
470 if (dataSourcesNames.length > 0) {
471 dataSourcesNames = dataSourceMap.values().toArray(dataSourcesNames);
472 CommonAttributePanel.this.intraCasePanel.setDatasourceComboboxModel(
new DataSourceComboBoxModel(dataSourcesNames));
474 if (!this.caseHasMultipleSources()) {
475 intraCaseRadio.setEnabled(
false);
476 interCaseRadio.setSelected(
true);
478 CommonAttributePanel.this.updateErrorTextAndSearchButton();
488 private boolean caseHasMultipleSources() {
489 return CommonAttributePanel.this.intraCasePanel.getDataSourceMap().size() > 1;
493 protected Map<Long, String> doInBackground() throws NoCurrentCaseException, TskCoreException, SQLException {
494 DataSourceLoader loader =
new DataSourceLoader();
495 return loader.getDataSourceMap();
499 protected void done() {
502 CommonAttributePanel.this.intraCasePanel.setDataSourceMap(this.
get());
505 }
catch (InterruptedException ex) {
506 LOGGER.log(Level.SEVERE,
"Interrupted while building Common Files Search dialog.", ex);
507 MessageNotifyUtil.Message.error(Bundle.CommonAttributePanel_setupDataSources_done_interupted());
508 }
catch (ExecutionException ex) {
510 Throwable inner = ex.getCause();
511 if (inner instanceof TskCoreException) {
512 LOGGER.log(Level.SEVERE,
"Failed to load data sources from database.", ex);
513 errorMessage = Bundle.CommonAttributePanel_setupDataSources_done_tskCoreException();
514 }
else if (inner instanceof NoCurrentCaseException) {
515 LOGGER.log(Level.SEVERE,
"Current case has been closed.", ex);
516 errorMessage = Bundle.CommonAttributePanel_setupDataSources_done_noCurrentCaseException();
517 }
else if (inner instanceof SQLException) {
518 LOGGER.log(Level.SEVERE,
"Unable to query db for data sources.", ex);
519 errorMessage = Bundle.CommonAttributePanel_setupDataSources_done_sqlException();
521 LOGGER.log(Level.SEVERE,
"Unexpected exception while building Common Files Search dialog panel.", ex);
522 errorMessage = Bundle.CommonAttributePanel_setupDataSources_done_exception();
524 MessageNotifyUtil.Message.error(errorMessage);
535 private void switchInnerPanel(JPanel panel) {
536 containerPanel.removeAll();
537 containerPanel.add(panel);
538 caseResultsRadioButton.setVisible(this.interCaseRadio.isSelected());
539 countResultsRadioButton.setVisible(this.interCaseRadio.isSelected());
540 displayResultsLabel.setVisible(this.interCaseRadio.isSelected());
546 "CommonAttributePanel.setupCases.done.interruptedException=Something went wrong building the Common Files Search dialog box.",
547 "CommonAttributePanel.setupCases.done.exeutionException=Unexpected exception loading cases."})
548 private void setupCases() {
550 new SwingWorker<Map<Integer, String>, Void>() {
556 private void updateUi() {
558 final Map<Integer, String> caseMap = CommonAttributePanel.this.interCasePanel.getCaseMap();
560 String[] caseNames =
new String[caseMap.size()];
562 if (caseNames.length > 0) {
563 caseNames = caseMap.values().toArray(caseNames);
564 CommonAttributePanel.this.interCasePanel.setCaseComboboxModel(
new DataSourceComboBoxModel(caseNames));
566 CommonAttributePanel.this.disableIntercaseSearch();
579 private Map<Integer, String> mapCases(List<CorrelationCase> cases)
throws EamDbException {
580 Map<Integer, String> casemap =
new HashMap<>();
581 CorrelationCase currentCorCase = EamDb.getInstance().getCase(Case.getCurrentCase());
582 for (CorrelationCase correlationCase : cases) {
583 if (currentCorCase.getID() != correlationCase.getID()) {
584 casemap.put(correlationCase.getID(), correlationCase.getDisplayName());
591 protected Map<Integer, String> doInBackground() throws EamDbException {
593 List<CorrelationCase> dataSources = EamDb.getInstance().getCases();
594 Map<Integer, String> caseMap = mapCases(dataSources);
600 protected void done() {
602 Map<Integer, String> cases = this.
get();
603 CommonAttributePanel.this.interCasePanel.setCaseMap(cases);
605 }
catch (InterruptedException ex) {
606 LOGGER.log(Level.SEVERE,
"Interrupted while building Common Files Search dialog.", ex);
607 MessageNotifyUtil.Message.error(Bundle.CommonAttributePanel_setupCases_done_interruptedException());
608 }
catch (ExecutionException ex) {
609 LOGGER.log(Level.SEVERE,
"Unexpected exception while building Common Files Search dialog.", ex);
610 MessageNotifyUtil.Message.error(Bundle.CommonAttributePanel_setupCases_done_exeutionException());
622 @SuppressWarnings(
"unchecked")
624 private
void initComponents() {
626 interIntraButtonGroup =
new javax.swing.ButtonGroup();
627 displayResultsButtonGroup =
new javax.swing.ButtonGroup();
628 jPanel1 =
new javax.swing.JPanel();
629 commonItemSearchDescription =
new javax.swing.JLabel();
630 scopeLabel =
new javax.swing.JLabel();
631 intraCaseRadio =
new javax.swing.JRadioButton();
632 interCaseRadio =
new javax.swing.JRadioButton();
633 containerPanel =
new javax.swing.JPanel();
634 percentageThresholdCheck =
new javax.swing.JCheckBox();
635 percentageThresholdInputBox =
new javax.swing.JTextField();
636 percentageThresholdTextTwo =
new javax.swing.JLabel();
637 dataSourcesLabel =
new javax.swing.JLabel();
638 errorText =
new javax.swing.JLabel();
639 searchButton =
new javax.swing.JButton();
640 caseResultsRadioButton =
new javax.swing.JRadioButton();
641 countResultsRadioButton =
new javax.swing.JRadioButton();
642 displayResultsLabel =
new javax.swing.JLabel();
644 setMinimumSize(
new java.awt.Dimension(450, 570));
646 addWindowListener(
new java.awt.event.WindowAdapter() {
647 public void windowClosed(java.awt.event.WindowEvent evt) {
648 formWindowClosed(evt);
652 jPanel1.setMaximumSize(null);
653 jPanel1.setPreferredSize(
new java.awt.Dimension(450, 646));
654 jPanel1.setRequestFocusEnabled(
false);
656 org.openide.awt.Mnemonics.setLocalizedText(commonItemSearchDescription,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.commonItemSearchDescription.text"));
657 commonItemSearchDescription.setFocusable(
false);
659 org.openide.awt.Mnemonics.setLocalizedText(scopeLabel,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.scopeLabel.text"));
660 scopeLabel.setFocusable(
false);
662 interIntraButtonGroup.add(intraCaseRadio);
663 intraCaseRadio.setSelected(
true);
664 org.openide.awt.Mnemonics.setLocalizedText(intraCaseRadio,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.intraCaseRadio.text"));
665 intraCaseRadio.addActionListener(
new java.awt.event.ActionListener() {
666 public void actionPerformed(java.awt.event.ActionEvent evt) {
667 intraCaseRadioActionPerformed(evt);
671 interIntraButtonGroup.add(interCaseRadio);
672 org.openide.awt.Mnemonics.setLocalizedText(interCaseRadio,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonFilesPanel.jRadioButton2.text"));
673 interCaseRadio.addActionListener(
new java.awt.event.ActionListener() {
674 public void actionPerformed(java.awt.event.ActionEvent evt) {
675 interCaseRadioActionPerformed(evt);
679 containerPanel.setBackground(
new java.awt.Color(0, 0, 0));
680 containerPanel.setOpaque(
false);
682 javax.swing.GroupLayout containerPanelLayout =
new javax.swing.GroupLayout(containerPanel);
683 containerPanel.setLayout(containerPanelLayout);
684 containerPanelLayout.setHorizontalGroup(
685 containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
686 .addGap(0, 430, Short.MAX_VALUE)
688 containerPanelLayout.setVerticalGroup(
689 containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
690 .addGap(0, 326, Short.MAX_VALUE)
693 org.openide.awt.Mnemonics.setLocalizedText(percentageThresholdCheck,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.percentageThresholdCheck.text_1_1"));
694 percentageThresholdCheck.addActionListener(
new java.awt.event.ActionListener() {
695 public void actionPerformed(java.awt.event.ActionEvent evt) {
696 percentageThresholdCheckActionPerformed(evt);
700 percentageThresholdInputBox.setHorizontalAlignment(javax.swing.JTextField.TRAILING);
701 percentageThresholdInputBox.setText(
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.percentageThresholdInputBox.text"));
702 percentageThresholdInputBox.setMaximumSize(
new java.awt.Dimension(40, 24));
703 percentageThresholdInputBox.setMinimumSize(
new java.awt.Dimension(40, 24));
704 percentageThresholdInputBox.setPreferredSize(
new java.awt.Dimension(40, 24));
706 org.openide.awt.Mnemonics.setLocalizedText(percentageThresholdTextTwo,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.percentageThresholdTextTwo.text_1"));
708 org.openide.awt.Mnemonics.setLocalizedText(dataSourcesLabel,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.dataSourcesLabel.text"));
710 errorText.setForeground(
new java.awt.Color(255, 0, 0));
711 org.openide.awt.Mnemonics.setLocalizedText(errorText,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.errorText.text"));
712 errorText.setVerticalAlignment(javax.swing.SwingConstants.TOP);
714 org.openide.awt.Mnemonics.setLocalizedText(searchButton,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.searchButton.text"));
715 searchButton.setEnabled(
false);
716 searchButton.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
717 searchButton.addActionListener(
new java.awt.event.ActionListener() {
718 public void actionPerformed(java.awt.event.ActionEvent evt) {
719 searchButtonActionPerformed(evt);
723 displayResultsButtonGroup.add(caseResultsRadioButton);
724 caseResultsRadioButton.setSelected(
true);
725 org.openide.awt.Mnemonics.setLocalizedText(caseResultsRadioButton,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.caseResultsRadioButton.text"));
726 caseResultsRadioButton.addActionListener(
new java.awt.event.ActionListener() {
727 public void actionPerformed(java.awt.event.ActionEvent evt) {
728 caseResultsRadioButtonActionPerformed(evt);
732 displayResultsButtonGroup.add(countResultsRadioButton);
733 org.openide.awt.Mnemonics.setLocalizedText(countResultsRadioButton,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.countResultsRadioButton.text"));
735 org.openide.awt.Mnemonics.setLocalizedText(displayResultsLabel,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.displayResultsLabel.text_2"));
737 javax.swing.GroupLayout jPanel1Layout =
new javax.swing.GroupLayout(jPanel1);
738 jPanel1.setLayout(jPanel1Layout);
739 jPanel1Layout.setHorizontalGroup(
740 jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
741 .addGroup(jPanel1Layout.createSequentialGroup()
743 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
744 .addGroup(jPanel1Layout.createSequentialGroup()
745 .addComponent(dataSourcesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
747 .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
748 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
749 .addGroup(jPanel1Layout.createSequentialGroup()
750 .addGap(0, 0, Short.MAX_VALUE)
751 .addComponent(intraCaseRadio, javax.swing.GroupLayout.PREFERRED_SIZE, 383, javax.swing.GroupLayout.PREFERRED_SIZE))
752 .addComponent(scopeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
754 .addGroup(jPanel1Layout.createSequentialGroup()
755 .addComponent(percentageThresholdCheck)
756 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
757 .addComponent(percentageThresholdInputBox, javax.swing.GroupLayout.PREFERRED_SIZE, 40, javax.swing.GroupLayout.PREFERRED_SIZE)
758 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
759 .addComponent(percentageThresholdTextTwo, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
761 .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
762 .addComponent(errorText, javax.swing.GroupLayout.PREFERRED_SIZE, 330, javax.swing.GroupLayout.PREFERRED_SIZE)
763 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
764 .addComponent(searchButton)
766 .addGroup(jPanel1Layout.createSequentialGroup()
767 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
768 .addComponent(containerPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
769 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING,
false)
770 .addComponent(commonItemSearchDescription, javax.swing.GroupLayout.Alignment.LEADING)
771 .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel1Layout.createSequentialGroup()
773 .addComponent(interCaseRadio, javax.swing.GroupLayout.PREFERRED_SIZE, 383, javax.swing.GroupLayout.PREFERRED_SIZE))))
774 .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
775 .addGroup(jPanel1Layout.createSequentialGroup()
776 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
777 .addGroup(jPanel1Layout.createSequentialGroup()
779 .addComponent(displayResultsLabel))
780 .addGroup(jPanel1Layout.createSequentialGroup()
782 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
783 .addComponent(caseResultsRadioButton, javax.swing.GroupLayout.PREFERRED_SIZE, 410, javax.swing.GroupLayout.PREFERRED_SIZE)
784 .addComponent(countResultsRadioButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
787 jPanel1Layout.setVerticalGroup(
788 jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
789 .addGroup(jPanel1Layout.createSequentialGroup()
791 .addComponent(commonItemSearchDescription, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
792 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
793 .addComponent(scopeLabel)
794 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
795 .addComponent(intraCaseRadio)
796 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
797 .addComponent(interCaseRadio)
798 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
799 .addComponent(containerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
800 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
801 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
802 .addComponent(percentageThresholdCheck)
803 .addComponent(percentageThresholdInputBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
804 .addComponent(percentageThresholdTextTwo))
805 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
806 .addComponent(displayResultsLabel)
807 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
808 .addComponent(caseResultsRadioButton)
810 .addComponent(countResultsRadioButton)
811 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
812 .addComponent(dataSourcesLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
813 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
814 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
815 .addComponent(searchButton)
816 .addComponent(errorText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
817 .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
820 getContentPane().add(jPanel1, java.awt.BorderLayout.CENTER);
823 private void formWindowClosed(java.awt.event.WindowEvent evt) {
827 private void percentageThresholdCheckActionPerformed(java.awt.event.ActionEvent evt) {
828 if (this.percentageThresholdCheck.isSelected()) {
829 this.percentageThresholdInputBox.setEnabled(
true);
831 this.percentageThresholdInputBox.setEnabled(
false);
834 this.handleFrequencyPercentageState();
837 private void interCaseRadioActionPerformed(java.awt.event.ActionEvent evt) {
838 switchInnerPanel(interCasePanel);
841 private void intraCaseRadioActionPerformed(java.awt.event.ActionEvent evt) {
842 switchInnerPanel(intraCasePanel);
845 private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {
846 checkDataSourcesAndSearch();
850 private void caseResultsRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {
868 @Messages({
"CommonAttributePanel.incompleteResults.introText=Results may be incomplete. Not all data sources in the current case were ingested into the current Central Repository. The following data sources have not been processed:",
869 "CommonAttributePanel.incompleteResults.continueText=\n\n Continue with search anyway?",
870 "CommonAttributePanel.incompleteResults.title=Search may be incomplete"
872 private void checkDataSourcesAndSearch() {
873 new SwingWorker<List<String>, Void>() {
876 protected List<String> doInBackground() throws Exception {
877 List<String> unCorrelatedDataSources =
new ArrayList<>();
878 if (!interCaseRadio.isSelected() || !EamDb.isEnabled() || EamDb.getInstance() == null) {
879 return unCorrelatedDataSources;
882 HashMap<DataSource, CorrelatedStatus> dataSourceCorrelationMap =
new HashMap<>();
883 String correlationEngineModuleName = CentralRepoIngestModuleFactory.getModuleName();
884 SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
885 List<CorrelationDataSource> correlatedDataSources = EamDb.getInstance().getDataSources();
886 List<IngestJobInfo> ingestJobs = skCase.getIngestJobs();
887 for (IngestJobInfo jobInfo : ingestJobs) {
889 DataSource dataSource = skCase.getDataSource(jobInfo.getObjectId());
890 String deviceID = dataSource.getDeviceId();
892 dataSourceCorrelationMap.putIfAbsent(dataSource, CorrelatedStatus.NOT_CORRELATED);
893 if (dataSourceCorrelationMap.get(dataSource) == CorrelatedStatus.NOT_CORRELATED) {
895 for (CorrelationDataSource correlatedDataSource : correlatedDataSources) {
896 if (deviceID.equals(correlatedDataSource.getDeviceID())) {
898 dataSourceCorrelationMap.put(dataSource, CorrelatedStatus.IN_CENTRAL_REPO);
903 if (dataSourceCorrelationMap.get(dataSource) == CorrelatedStatus.IN_CENTRAL_REPO) {
905 for (IngestModuleInfo ingestModuleInfo : jobInfo.getIngestModuleInfo()) {
906 if (correlationEngineModuleName.equals(ingestModuleInfo.getDisplayName())) {
907 dataSourceCorrelationMap.put(dataSource, CorrelatedStatus.CORRELATED);
914 for (DataSource dataSource : dataSourceCorrelationMap.keySet()) {
915 if (dataSourceCorrelationMap.get(dataSource) != CorrelatedStatus.CORRELATED) {
916 unCorrelatedDataSources.add(dataSource.getName());
919 return unCorrelatedDataSources;
923 protected void done() {
926 List<String> unProcessedDataSources =
get();
927 boolean performSearch =
true;
928 if (!unProcessedDataSources.isEmpty()) {
929 String warning = Bundle.CommonAttributePanel_incompleteResults_introText();
930 warning = unProcessedDataSources.stream().map((dataSource) ->
"\n - " + dataSource).reduce(warning, String::concat);
931 warning += Bundle.CommonAttributePanel_incompleteResults_continueText();
933 NotifyDescriptor descriptor =
new NotifyDescriptor.Confirmation(warning, Bundle.CommonAttributePanel_incompleteResults_title(), NotifyDescriptor.YES_NO_OPTION);
934 performSearch = DialogDisplayer.getDefault().notify(descriptor) == NotifyDescriptor.YES_OPTION;
937 if (interCaseRadio.isSelected() && caseResultsRadioButton.isSelected()) {
943 }
catch (InterruptedException | ExecutionException ex) {
944 LOGGER.log(Level.SEVERE,
"Unexpected exception while looking for common properties", ex);
954 private void percentageThresholdChanged() {
955 String percentageString = this.percentageThresholdInputBox.getText();
958 this.percentageThresholdValue = Integer.parseInt(percentageString);
960 }
catch (NumberFormatException ignored) {
961 this.percentageThresholdValue = -1;
964 this.handleFrequencyPercentageState();
971 private void updateErrorTextAndSearchButton() {
972 if (this.errorManager.anyErrors()) {
973 this.searchButton.setEnabled(
false);
975 this.errorText.setText(this.errorManager.getErrors().get(0));
976 this.errorText.setVisible(
true);
978 this.searchButton.setEnabled(
true);
979 this.errorText.setVisible(
false);
991 "# {0} - number of datasources",
992 "CommonAttributePanel.dataSourcesLabel.text=The current Central Repository contains {0} data source(s)."})
993 private void updatePercentageOptions(Long numberOfDataSources) {
994 boolean enabled = numberOfDataSources > 0L;
995 String numberOfDataSourcesText = enabled ? Bundle.CommonAttributePanel_dataSourcesLabel_text(numberOfDataSources) :
"";
996 this.dataSourcesLabel.setText(numberOfDataSourcesText);
997 this.percentageThresholdInputBox.setEnabled(enabled);
998 this.percentageThresholdCheck.setEnabled(enabled);
999 this.percentageThresholdCheck.setSelected(enabled);
1000 this.percentageThresholdTextTwo.setEnabled(enabled);
1009 private void handleFrequencyPercentageState() {
1010 if (this.percentageThresholdValue > 0 && this.percentageThresholdValue <= 100) {
1011 this.errorManager.setError(UserInputErrorManager.FREQUENCY_PERCENTAGE_OUT_OF_RANGE_KEY,
false);
1014 this.errorManager.setError(UserInputErrorManager.FREQUENCY_PERCENTAGE_OUT_OF_RANGE_KEY,
true);
1016 this.updateErrorTextAndSearchButton();
1020 private javax.swing.JRadioButton caseResultsRadioButton;
1021 private javax.swing.JLabel commonItemSearchDescription;
1022 private javax.swing.JPanel containerPanel;
1023 private javax.swing.JRadioButton countResultsRadioButton;
1024 private javax.swing.JLabel dataSourcesLabel;
1025 private javax.swing.ButtonGroup displayResultsButtonGroup;
1026 private javax.swing.JLabel displayResultsLabel;
1027 private javax.swing.JLabel errorText;
1028 private javax.swing.JRadioButton interCaseRadio;
1029 private javax.swing.ButtonGroup interIntraButtonGroup;
1030 private javax.swing.JRadioButton intraCaseRadio;
1031 private javax.swing.JPanel jPanel1;
1032 private javax.swing.JCheckBox percentageThresholdCheck;
1033 private javax.swing.JTextField percentageThresholdInputBox;
1034 private javax.swing.JLabel percentageThresholdTextTwo;
1035 private javax.swing.JLabel scopeLabel;
1036 private javax.swing.JButton searchButton;
1043 void observeSubPanels() {
1044 intraCasePanel.addObserver(
this);
1045 interCasePanel.addObserver(
this);
1053 private void checkFileTypeCheckBoxState() {
1054 boolean validCheckBoxState =
true;
1055 if (CommonAttributePanel.this.interCaseRadio.isSelected()) {
1056 if (interCasePanel.fileCategoriesButtonIsSelected()) {
1057 validCheckBoxState = interCasePanel.pictureVideoCheckboxIsSelected() || interCasePanel.documentsCheckboxIsSelected();
1060 if (intraCasePanel.fileCategoriesButtonIsSelected()) {
1061 validCheckBoxState = intraCasePanel.pictureVideoCheckboxIsSelected() || intraCasePanel.documentsCheckboxIsSelected();
1064 if (validCheckBoxState) {
1065 this.errorManager.setError(UserInputErrorManager.NO_FILE_CATEGORIES_SELECTED_KEY,
false);
1067 this.errorManager.setError(UserInputErrorManager.NO_FILE_CATEGORIES_SELECTED_KEY,
true);
1069 this.updateErrorTextAndSearchButton();