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 CentralRepository.isEnabled()
166 && CentralRepository.getInstance() != null
167 && CentralRepository.getInstance().getCases().size() > 1
169 && Case.getCurrentCase() != null
170 && CentralRepository.getInstance().getCase(Case.getCurrentCase()) != null;
171 }
catch (CentralRepoException 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 (CentralRepository.isEnabled()
192 && CentralRepository.getInstance() != null) {
193 return CentralRepository.getInstance().getCountUniqueDataSources();
195 }
catch (CentralRepoException 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, CentralRepoException {
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 = CentralRepository.getInstance().getDefinedCorrelationTypes().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, CentralRepoException {
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 = CentralRepository.getInstance().getDefinedCorrelationTypes().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 return DataSourceLoader.getAllDataSources();
498 protected void done() {
501 CommonAttributePanel.this.intraCasePanel.setDataSourceMap(this.
get());
504 }
catch (InterruptedException ex) {
505 LOGGER.log(Level.SEVERE,
"Interrupted while building Common Files Search dialog.", ex);
506 MessageNotifyUtil.Message.error(Bundle.CommonAttributePanel_setupDataSources_done_interupted());
507 }
catch (ExecutionException ex) {
509 Throwable inner = ex.getCause();
510 if (inner instanceof TskCoreException) {
511 LOGGER.log(Level.SEVERE,
"Failed to load data sources from database.", ex);
512 errorMessage = Bundle.CommonAttributePanel_setupDataSources_done_tskCoreException();
513 }
else if (inner instanceof NoCurrentCaseException) {
514 LOGGER.log(Level.SEVERE,
"Current case has been closed.", ex);
515 errorMessage = Bundle.CommonAttributePanel_setupDataSources_done_noCurrentCaseException();
516 }
else if (inner instanceof SQLException) {
517 LOGGER.log(Level.SEVERE,
"Unable to query db for data sources.", ex);
518 errorMessage = Bundle.CommonAttributePanel_setupDataSources_done_sqlException();
520 LOGGER.log(Level.SEVERE,
"Unexpected exception while building Common Files Search dialog panel.", ex);
521 errorMessage = Bundle.CommonAttributePanel_setupDataSources_done_exception();
523 MessageNotifyUtil.Message.error(errorMessage);
534 private void switchInnerPanel(JPanel panel) {
535 containerPanel.removeAll();
536 containerPanel.add(panel);
537 caseResultsRadioButton.setVisible(this.interCaseRadio.isSelected());
538 countResultsRadioButton.setVisible(this.interCaseRadio.isSelected());
539 displayResultsLabel.setVisible(this.interCaseRadio.isSelected());
545 "CommonAttributePanel.setupCases.done.interruptedException=Something went wrong building the Common Files Search dialog box.",
546 "CommonAttributePanel.setupCases.done.exeutionException=Unexpected exception loading cases."})
547 private void setupCases() {
549 new SwingWorker<Map<Integer, String>, Void>() {
555 private void updateUi() {
557 final Map<Integer, String> caseMap = CommonAttributePanel.this.interCasePanel.getCaseMap();
559 String[] caseNames =
new String[caseMap.size()];
561 if (caseNames.length > 0) {
562 caseNames = caseMap.values().toArray(caseNames);
563 CommonAttributePanel.this.interCasePanel.setCaseComboboxModel(
new DataSourceComboBoxModel(caseNames));
565 CommonAttributePanel.this.disableIntercaseSearch();
578 private Map<Integer, String> mapCases(List<CorrelationCase> cases)
throws CentralRepoException {
579 Map<Integer, String> casemap =
new HashMap<>();
580 CorrelationCase currentCorCase = CentralRepository.getInstance().getCase(Case.getCurrentCase());
581 for (CorrelationCase correlationCase : cases) {
582 if (currentCorCase.getID() != correlationCase.getID()) {
583 casemap.put(correlationCase.getID(), correlationCase.getDisplayName());
590 protected Map<Integer, String> doInBackground() throws CentralRepoException {
592 List<CorrelationCase> dataSources = CentralRepository.getInstance().getCases();
593 Map<Integer, String> caseMap = mapCases(dataSources);
599 protected void done() {
601 Map<Integer, String> cases = this.
get();
602 CommonAttributePanel.this.interCasePanel.setCaseMap(cases);
604 }
catch (InterruptedException ex) {
605 LOGGER.log(Level.SEVERE,
"Interrupted while building Common Files Search dialog.", ex);
606 MessageNotifyUtil.Message.error(Bundle.CommonAttributePanel_setupCases_done_interruptedException());
607 }
catch (ExecutionException ex) {
608 LOGGER.log(Level.SEVERE,
"Unexpected exception while building Common Files Search dialog.", ex);
609 MessageNotifyUtil.Message.error(Bundle.CommonAttributePanel_setupCases_done_exeutionException());
621 @SuppressWarnings(
"unchecked")
623 private
void initComponents() {
625 interIntraButtonGroup =
new javax.swing.ButtonGroup();
626 displayResultsButtonGroup =
new javax.swing.ButtonGroup();
627 jPanel1 =
new javax.swing.JPanel();
628 commonItemSearchDescription =
new javax.swing.JLabel();
629 scopeLabel =
new javax.swing.JLabel();
630 intraCaseRadio =
new javax.swing.JRadioButton();
631 interCaseRadio =
new javax.swing.JRadioButton();
632 containerPanel =
new javax.swing.JPanel();
633 percentageThresholdCheck =
new javax.swing.JCheckBox();
634 percentageThresholdInputBox =
new javax.swing.JTextField();
635 percentageThresholdTextTwo =
new javax.swing.JLabel();
636 dataSourcesLabel =
new javax.swing.JLabel();
637 errorText =
new javax.swing.JLabel();
638 searchButton =
new javax.swing.JButton();
639 caseResultsRadioButton =
new javax.swing.JRadioButton();
640 countResultsRadioButton =
new javax.swing.JRadioButton();
641 displayResultsLabel =
new javax.swing.JLabel();
643 setMinimumSize(
new java.awt.Dimension(450, 570));
645 addWindowListener(
new java.awt.event.WindowAdapter() {
646 public void windowClosed(java.awt.event.WindowEvent evt) {
647 formWindowClosed(evt);
651 jPanel1.setMaximumSize(null);
652 jPanel1.setPreferredSize(
new java.awt.Dimension(450, 646));
653 jPanel1.setRequestFocusEnabled(
false);
655 org.openide.awt.Mnemonics.setLocalizedText(commonItemSearchDescription,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.commonItemSearchDescription.text"));
656 commonItemSearchDescription.setFocusable(
false);
658 org.openide.awt.Mnemonics.setLocalizedText(scopeLabel,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.scopeLabel.text"));
659 scopeLabel.setFocusable(
false);
661 interIntraButtonGroup.add(intraCaseRadio);
662 intraCaseRadio.setSelected(
true);
663 org.openide.awt.Mnemonics.setLocalizedText(intraCaseRadio,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.intraCaseRadio.text"));
664 intraCaseRadio.addActionListener(
new java.awt.event.ActionListener() {
665 public void actionPerformed(java.awt.event.ActionEvent evt) {
666 intraCaseRadioActionPerformed(evt);
670 interIntraButtonGroup.add(interCaseRadio);
671 org.openide.awt.Mnemonics.setLocalizedText(interCaseRadio,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonFilesPanel.jRadioButton2.text"));
672 interCaseRadio.addActionListener(
new java.awt.event.ActionListener() {
673 public void actionPerformed(java.awt.event.ActionEvent evt) {
674 interCaseRadioActionPerformed(evt);
678 containerPanel.setBackground(
new java.awt.Color(0, 0, 0));
679 containerPanel.setOpaque(
false);
681 javax.swing.GroupLayout containerPanelLayout =
new javax.swing.GroupLayout(containerPanel);
682 containerPanel.setLayout(containerPanelLayout);
683 containerPanelLayout.setHorizontalGroup(
684 containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
685 .addGap(0, 430, Short.MAX_VALUE)
687 containerPanelLayout.setVerticalGroup(
688 containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
689 .addGap(0, 326, Short.MAX_VALUE)
692 org.openide.awt.Mnemonics.setLocalizedText(percentageThresholdCheck,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.percentageThresholdCheck.text_1_1"));
693 percentageThresholdCheck.addActionListener(
new java.awt.event.ActionListener() {
694 public void actionPerformed(java.awt.event.ActionEvent evt) {
695 percentageThresholdCheckActionPerformed(evt);
699 percentageThresholdInputBox.setHorizontalAlignment(javax.swing.JTextField.TRAILING);
700 percentageThresholdInputBox.setText(
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.percentageThresholdInputBox.text"));
701 percentageThresholdInputBox.setMaximumSize(
new java.awt.Dimension(40, 24));
702 percentageThresholdInputBox.setMinimumSize(
new java.awt.Dimension(40, 24));
703 percentageThresholdInputBox.setPreferredSize(
new java.awt.Dimension(40, 24));
705 org.openide.awt.Mnemonics.setLocalizedText(percentageThresholdTextTwo,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.percentageThresholdTextTwo.text_1"));
707 org.openide.awt.Mnemonics.setLocalizedText(dataSourcesLabel,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.dataSourcesLabel.text"));
709 errorText.setForeground(
new java.awt.Color(255, 0, 0));
710 org.openide.awt.Mnemonics.setLocalizedText(errorText,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.errorText.text"));
711 errorText.setVerticalAlignment(javax.swing.SwingConstants.TOP);
713 org.openide.awt.Mnemonics.setLocalizedText(searchButton,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.searchButton.text"));
714 searchButton.setEnabled(
false);
715 searchButton.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
716 searchButton.addActionListener(
new java.awt.event.ActionListener() {
717 public void actionPerformed(java.awt.event.ActionEvent evt) {
718 searchButtonActionPerformed(evt);
722 displayResultsButtonGroup.add(caseResultsRadioButton);
723 caseResultsRadioButton.setSelected(
true);
724 org.openide.awt.Mnemonics.setLocalizedText(caseResultsRadioButton,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.caseResultsRadioButton.text"));
725 caseResultsRadioButton.addActionListener(
new java.awt.event.ActionListener() {
726 public void actionPerformed(java.awt.event.ActionEvent evt) {
727 caseResultsRadioButtonActionPerformed(evt);
731 displayResultsButtonGroup.add(countResultsRadioButton);
732 org.openide.awt.Mnemonics.setLocalizedText(countResultsRadioButton,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.countResultsRadioButton.text"));
734 org.openide.awt.Mnemonics.setLocalizedText(displayResultsLabel,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.displayResultsLabel.text_2"));
736 javax.swing.GroupLayout jPanel1Layout =
new javax.swing.GroupLayout(jPanel1);
737 jPanel1.setLayout(jPanel1Layout);
738 jPanel1Layout.setHorizontalGroup(
739 jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
740 .addGroup(jPanel1Layout.createSequentialGroup()
742 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
743 .addGroup(jPanel1Layout.createSequentialGroup()
744 .addComponent(dataSourcesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
746 .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
747 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
748 .addGroup(jPanel1Layout.createSequentialGroup()
749 .addGap(0, 0, Short.MAX_VALUE)
750 .addComponent(intraCaseRadio, javax.swing.GroupLayout.PREFERRED_SIZE, 383, javax.swing.GroupLayout.PREFERRED_SIZE))
751 .addComponent(scopeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
753 .addGroup(jPanel1Layout.createSequentialGroup()
754 .addComponent(percentageThresholdCheck)
755 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
756 .addComponent(percentageThresholdInputBox, javax.swing.GroupLayout.PREFERRED_SIZE, 40, javax.swing.GroupLayout.PREFERRED_SIZE)
757 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
758 .addComponent(percentageThresholdTextTwo, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
760 .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
761 .addComponent(errorText, javax.swing.GroupLayout.PREFERRED_SIZE, 330, javax.swing.GroupLayout.PREFERRED_SIZE)
762 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
763 .addComponent(searchButton)
765 .addGroup(jPanel1Layout.createSequentialGroup()
766 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
767 .addComponent(containerPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
768 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING,
false)
769 .addComponent(commonItemSearchDescription, javax.swing.GroupLayout.Alignment.LEADING)
770 .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel1Layout.createSequentialGroup()
772 .addComponent(interCaseRadio, javax.swing.GroupLayout.PREFERRED_SIZE, 383, javax.swing.GroupLayout.PREFERRED_SIZE))))
773 .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
774 .addGroup(jPanel1Layout.createSequentialGroup()
775 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
776 .addGroup(jPanel1Layout.createSequentialGroup()
778 .addComponent(displayResultsLabel))
779 .addGroup(jPanel1Layout.createSequentialGroup()
781 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
782 .addComponent(caseResultsRadioButton, javax.swing.GroupLayout.PREFERRED_SIZE, 410, javax.swing.GroupLayout.PREFERRED_SIZE)
783 .addComponent(countResultsRadioButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
786 jPanel1Layout.setVerticalGroup(
787 jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
788 .addGroup(jPanel1Layout.createSequentialGroup()
790 .addComponent(commonItemSearchDescription, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
791 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
792 .addComponent(scopeLabel)
793 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
794 .addComponent(intraCaseRadio)
795 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
796 .addComponent(interCaseRadio)
797 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
798 .addComponent(containerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
799 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
800 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
801 .addComponent(percentageThresholdCheck)
802 .addComponent(percentageThresholdInputBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
803 .addComponent(percentageThresholdTextTwo))
804 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
805 .addComponent(displayResultsLabel)
806 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
807 .addComponent(caseResultsRadioButton)
809 .addComponent(countResultsRadioButton)
810 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
811 .addComponent(dataSourcesLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
812 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
813 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
814 .addComponent(searchButton)
815 .addComponent(errorText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
816 .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
819 getContentPane().add(jPanel1, java.awt.BorderLayout.CENTER);
822 private void formWindowClosed(java.awt.event.WindowEvent evt) {
826 private void percentageThresholdCheckActionPerformed(java.awt.event.ActionEvent evt) {
827 if (this.percentageThresholdCheck.isSelected()) {
828 this.percentageThresholdInputBox.setEnabled(
true);
830 this.percentageThresholdInputBox.setEnabled(
false);
833 this.handleFrequencyPercentageState();
836 private void interCaseRadioActionPerformed(java.awt.event.ActionEvent evt) {
837 switchInnerPanel(interCasePanel);
840 private void intraCaseRadioActionPerformed(java.awt.event.ActionEvent evt) {
841 switchInnerPanel(intraCasePanel);
844 private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {
845 checkDataSourcesAndSearch();
849 private void caseResultsRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {
867 @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:",
868 "CommonAttributePanel.incompleteResults.continueText=\n\n Continue with search anyway?",
869 "CommonAttributePanel.incompleteResults.title=Search may be incomplete"
871 private void checkDataSourcesAndSearch() {
872 new SwingWorker<List<String>, Void>() {
875 protected List<String> doInBackground() throws Exception {
876 List<String> unCorrelatedDataSources =
new ArrayList<>();
877 if (!interCaseRadio.isSelected() || !CentralRepository.isEnabled() || CentralRepository.getInstance() == null) {
878 return unCorrelatedDataSources;
881 HashMap<DataSource, CorrelatedStatus> dataSourceCorrelationMap =
new HashMap<>();
882 String correlationEngineModuleName = CentralRepoIngestModuleFactory.getModuleName();
883 SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
884 List<CorrelationDataSource> correlatedDataSources = CentralRepository.getInstance().getDataSources();
885 List<IngestJobInfo> ingestJobs = skCase.getIngestJobs();
886 for (IngestJobInfo jobInfo : ingestJobs) {
888 DataSource dataSource = skCase.getDataSource(jobInfo.getObjectId());
889 String deviceID = dataSource.getDeviceId();
891 dataSourceCorrelationMap.putIfAbsent(dataSource, CorrelatedStatus.NOT_CORRELATED);
892 if (dataSourceCorrelationMap.get(dataSource) == CorrelatedStatus.NOT_CORRELATED) {
894 for (CorrelationDataSource correlatedDataSource : correlatedDataSources) {
895 if (deviceID.equals(correlatedDataSource.getDeviceID())) {
897 dataSourceCorrelationMap.put(dataSource, CorrelatedStatus.IN_CENTRAL_REPO);
902 if (dataSourceCorrelationMap.get(dataSource) == CorrelatedStatus.IN_CENTRAL_REPO) {
904 for (IngestModuleInfo ingestModuleInfo : jobInfo.getIngestModuleInfo()) {
905 if (correlationEngineModuleName.equals(ingestModuleInfo.getDisplayName())) {
906 dataSourceCorrelationMap.put(dataSource, CorrelatedStatus.CORRELATED);
913 for (DataSource dataSource : dataSourceCorrelationMap.keySet()) {
914 if (dataSourceCorrelationMap.get(dataSource) != CorrelatedStatus.CORRELATED) {
915 unCorrelatedDataSources.add(dataSource.getName());
918 return unCorrelatedDataSources;
922 protected void done() {
925 List<String> unProcessedDataSources =
get();
926 boolean performSearch =
true;
927 if (!unProcessedDataSources.isEmpty()) {
928 String warning = Bundle.CommonAttributePanel_incompleteResults_introText();
929 warning = unProcessedDataSources.stream().map((dataSource) ->
"\n - " + dataSource).reduce(warning, String::concat);
930 warning += Bundle.CommonAttributePanel_incompleteResults_continueText();
932 NotifyDescriptor descriptor =
new NotifyDescriptor.Confirmation(warning, Bundle.CommonAttributePanel_incompleteResults_title(), NotifyDescriptor.YES_NO_OPTION);
933 performSearch = DialogDisplayer.getDefault().notify(descriptor) == NotifyDescriptor.YES_OPTION;
936 if (interCaseRadio.isSelected() && caseResultsRadioButton.isSelected()) {
942 }
catch (InterruptedException | ExecutionException ex) {
943 LOGGER.log(Level.SEVERE,
"Unexpected exception while looking for common properties", ex);
953 private void percentageThresholdChanged() {
954 String percentageString = this.percentageThresholdInputBox.getText();
957 this.percentageThresholdValue = Integer.parseInt(percentageString);
959 }
catch (NumberFormatException ignored) {
960 this.percentageThresholdValue = -1;
963 this.handleFrequencyPercentageState();
970 private void updateErrorTextAndSearchButton() {
971 if (this.errorManager.anyErrors()) {
972 this.searchButton.setEnabled(
false);
974 this.errorText.setText(this.errorManager.getErrors().get(0));
975 this.errorText.setVisible(
true);
977 this.searchButton.setEnabled(
true);
978 this.errorText.setVisible(
false);
990 "# {0} - number of datasources",
991 "CommonAttributePanel.dataSourcesLabel.text=The current Central Repository contains {0} data source(s)."})
992 private void updatePercentageOptions(Long numberOfDataSources) {
993 boolean enabled = numberOfDataSources > 0L;
994 String numberOfDataSourcesText = enabled ? Bundle.CommonAttributePanel_dataSourcesLabel_text(numberOfDataSources) :
"";
995 this.dataSourcesLabel.setText(numberOfDataSourcesText);
996 this.percentageThresholdInputBox.setEnabled(enabled);
997 this.percentageThresholdCheck.setEnabled(enabled);
998 this.percentageThresholdCheck.setSelected(enabled);
999 this.percentageThresholdTextTwo.setEnabled(enabled);
1008 private void handleFrequencyPercentageState() {
1009 if (this.percentageThresholdValue > 0 && this.percentageThresholdValue <= 100) {
1010 this.errorManager.setError(UserInputErrorManager.FREQUENCY_PERCENTAGE_OUT_OF_RANGE_KEY,
false);
1013 this.errorManager.setError(UserInputErrorManager.FREQUENCY_PERCENTAGE_OUT_OF_RANGE_KEY,
true);
1015 this.updateErrorTextAndSearchButton();
1019 private javax.swing.JRadioButton caseResultsRadioButton;
1020 private javax.swing.JLabel commonItemSearchDescription;
1021 private javax.swing.JPanel containerPanel;
1022 private javax.swing.JRadioButton countResultsRadioButton;
1023 private javax.swing.JLabel dataSourcesLabel;
1024 private javax.swing.ButtonGroup displayResultsButtonGroup;
1025 private javax.swing.JLabel displayResultsLabel;
1026 private javax.swing.JLabel errorText;
1027 private javax.swing.JRadioButton interCaseRadio;
1028 private javax.swing.ButtonGroup interIntraButtonGroup;
1029 private javax.swing.JRadioButton intraCaseRadio;
1030 private javax.swing.JPanel jPanel1;
1031 private javax.swing.JCheckBox percentageThresholdCheck;
1032 private javax.swing.JTextField percentageThresholdInputBox;
1033 private javax.swing.JLabel percentageThresholdTextTwo;
1034 private javax.swing.JLabel scopeLabel;
1035 private javax.swing.JButton searchButton;
1042 void observeSubPanels() {
1043 intraCasePanel.addObserver(
this);
1044 interCasePanel.addObserver(
this);
1052 private void checkFileTypeCheckBoxState() {
1053 boolean validCheckBoxState =
true;
1054 if (CommonAttributePanel.this.interCaseRadio.isSelected()) {
1055 if (interCasePanel.fileCategoriesButtonIsSelected()) {
1056 validCheckBoxState = interCasePanel.pictureVideoCheckboxIsSelected() || interCasePanel.documentsCheckboxIsSelected();
1059 if (intraCasePanel.fileCategoriesButtonIsSelected()) {
1060 validCheckBoxState = intraCasePanel.pictureVideoCheckboxIsSelected() || intraCasePanel.documentsCheckboxIsSelected();
1063 if (validCheckBoxState) {
1064 this.errorManager.setError(UserInputErrorManager.NO_FILE_CATEGORIES_SELECTED_KEY,
false);
1066 this.errorManager.setError(UserInputErrorManager.NO_FILE_CATEGORIES_SELECTED_KEY,
true);
1068 this.updateErrorTextAndSearchButton();