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 setMaximumSize(
new java.awt.Dimension(499, 646));
644 setMinimumSize(
new java.awt.Dimension(499, 646));
646 addWindowListener(
new java.awt.event.WindowAdapter() {
647 public void windowClosed(java.awt.event.WindowEvent evt) {
648 formWindowClosed(evt);
652 jPanel1.setMaximumSize(
new java.awt.Dimension(499, 646));
653 jPanel1.setMinimumSize(
new java.awt.Dimension(499, 646));
654 jPanel1.setPreferredSize(
new java.awt.Dimension(499, 646));
655 jPanel1.setRequestFocusEnabled(
false);
657 org.openide.awt.Mnemonics.setLocalizedText(commonItemSearchDescription,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.commonItemSearchDescription.text"));
658 commonItemSearchDescription.setFocusable(
false);
660 org.openide.awt.Mnemonics.setLocalizedText(scopeLabel,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.scopeLabel.text"));
661 scopeLabel.setFocusable(
false);
663 interIntraButtonGroup.add(intraCaseRadio);
664 intraCaseRadio.setSelected(
true);
665 org.openide.awt.Mnemonics.setLocalizedText(intraCaseRadio,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.intraCaseRadio.text"));
666 intraCaseRadio.addActionListener(
new java.awt.event.ActionListener() {
667 public void actionPerformed(java.awt.event.ActionEvent evt) {
668 intraCaseRadioActionPerformed(evt);
672 interIntraButtonGroup.add(interCaseRadio);
673 org.openide.awt.Mnemonics.setLocalizedText(interCaseRadio,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonFilesPanel.jRadioButton2.text"));
674 interCaseRadio.addActionListener(
new java.awt.event.ActionListener() {
675 public void actionPerformed(java.awt.event.ActionEvent evt) {
676 interCaseRadioActionPerformed(evt);
680 containerPanel.setBackground(
new java.awt.Color(0, 0, 0));
681 containerPanel.setOpaque(
false);
682 containerPanel.setPreferredSize(
new java.awt.Dimension(477, 326));
684 javax.swing.GroupLayout containerPanelLayout =
new javax.swing.GroupLayout(containerPanel);
685 containerPanel.setLayout(containerPanelLayout);
686 containerPanelLayout.setHorizontalGroup(
687 containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
688 .addGap(0, 0, Short.MAX_VALUE)
690 containerPanelLayout.setVerticalGroup(
691 containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
692 .addGap(0, 326, Short.MAX_VALUE)
695 org.openide.awt.Mnemonics.setLocalizedText(percentageThresholdCheck,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.percentageThresholdCheck.text_1_1"));
696 percentageThresholdCheck.addActionListener(
new java.awt.event.ActionListener() {
697 public void actionPerformed(java.awt.event.ActionEvent evt) {
698 percentageThresholdCheckActionPerformed(evt);
702 percentageThresholdInputBox.setHorizontalAlignment(javax.swing.JTextField.TRAILING);
703 percentageThresholdInputBox.setText(
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.percentageThresholdInputBox.text"));
704 percentageThresholdInputBox.setMaximumSize(
new java.awt.Dimension(40, 24));
705 percentageThresholdInputBox.setMinimumSize(
new java.awt.Dimension(40, 24));
706 percentageThresholdInputBox.setPreferredSize(
new java.awt.Dimension(40, 24));
708 org.openide.awt.Mnemonics.setLocalizedText(percentageThresholdTextTwo,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.percentageThresholdTextTwo.text_1"));
709 percentageThresholdTextTwo.setMaximumSize(
new java.awt.Dimension(260, 16));
711 org.openide.awt.Mnemonics.setLocalizedText(dataSourcesLabel,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.dataSourcesLabel.text"));
713 errorText.setForeground(
new java.awt.Color(255, 0, 0));
714 org.openide.awt.Mnemonics.setLocalizedText(errorText,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.errorText.text"));
715 errorText.setVerticalAlignment(javax.swing.SwingConstants.TOP);
717 org.openide.awt.Mnemonics.setLocalizedText(searchButton,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.searchButton.text"));
718 searchButton.setEnabled(
false);
719 searchButton.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
720 searchButton.setMaximumSize(
new java.awt.Dimension(100, 25));
721 searchButton.setMinimumSize(
new java.awt.Dimension(100, 25));
722 searchButton.setPreferredSize(
new java.awt.Dimension(100, 25));
723 searchButton.addActionListener(
new java.awt.event.ActionListener() {
724 public void actionPerformed(java.awt.event.ActionEvent evt) {
725 searchButtonActionPerformed(evt);
729 displayResultsButtonGroup.add(caseResultsRadioButton);
730 caseResultsRadioButton.setSelected(
true);
731 org.openide.awt.Mnemonics.setLocalizedText(caseResultsRadioButton,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.caseResultsRadioButton.text"));
732 caseResultsRadioButton.addActionListener(
new java.awt.event.ActionListener() {
733 public void actionPerformed(java.awt.event.ActionEvent evt) {
734 caseResultsRadioButtonActionPerformed(evt);
738 displayResultsButtonGroup.add(countResultsRadioButton);
739 org.openide.awt.Mnemonics.setLocalizedText(countResultsRadioButton,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.countResultsRadioButton.text"));
741 org.openide.awt.Mnemonics.setLocalizedText(displayResultsLabel,
org.openide.util.NbBundle.getMessage(CommonAttributePanel.class,
"CommonAttributePanel.displayResultsLabel.text_2"));
743 javax.swing.GroupLayout jPanel1Layout =
new javax.swing.GroupLayout(jPanel1);
744 jPanel1.setLayout(jPanel1Layout);
745 jPanel1Layout.setHorizontalGroup(
746 jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
747 .addGroup(jPanel1Layout.createSequentialGroup()
749 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
750 .addGroup(jPanel1Layout.createSequentialGroup()
751 .addComponent(dataSourcesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
753 .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
754 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
755 .addGroup(jPanel1Layout.createSequentialGroup()
757 .addComponent(intraCaseRadio, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
758 .addComponent(scopeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
760 .addGroup(jPanel1Layout.createSequentialGroup()
761 .addComponent(percentageThresholdCheck, javax.swing.GroupLayout.DEFAULT_SIZE, 184, Short.MAX_VALUE)
763 .addComponent(percentageThresholdInputBox, javax.swing.GroupLayout.PREFERRED_SIZE, 40, javax.swing.GroupLayout.PREFERRED_SIZE)
764 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
765 .addComponent(percentageThresholdTextTwo, javax.swing.GroupLayout.DEFAULT_SIZE, 247, Short.MAX_VALUE)
767 .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
768 .addComponent(errorText)
770 .addComponent(searchButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
772 .addGroup(jPanel1Layout.createSequentialGroup()
773 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
774 .addComponent(commonItemSearchDescription, javax.swing.GroupLayout.Alignment.LEADING)
775 .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel1Layout.createSequentialGroup()
777 .addComponent(interCaseRadio, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
779 .addGroup(jPanel1Layout.createSequentialGroup()
780 .addComponent(containerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
781 .addContainerGap())))
782 .addGroup(jPanel1Layout.createSequentialGroup()
784 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
785 .addGroup(jPanel1Layout.createSequentialGroup()
786 .addComponent(caseResultsRadioButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
788 .addComponent(countResultsRadioButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
790 .addGroup(jPanel1Layout.createSequentialGroup()
792 .addComponent(displayResultsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE)
793 .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
795 jPanel1Layout.setVerticalGroup(
796 jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
797 .addGroup(jPanel1Layout.createSequentialGroup()
799 .addComponent(commonItemSearchDescription, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
800 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
801 .addComponent(scopeLabel)
802 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
803 .addComponent(intraCaseRadio)
804 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
805 .addComponent(interCaseRadio)
806 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
807 .addComponent(containerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
808 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
809 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
810 .addComponent(percentageThresholdCheck)
811 .addComponent(percentageThresholdInputBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
812 .addComponent(percentageThresholdTextTwo, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
813 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
814 .addComponent(displayResultsLabel)
815 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
816 .addComponent(caseResultsRadioButton)
818 .addComponent(countResultsRadioButton)
819 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
820 .addComponent(dataSourcesLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
821 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
822 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
823 .addComponent(searchButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
824 .addComponent(errorText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
828 getContentPane().add(jPanel1, java.awt.BorderLayout.CENTER);
831 private void formWindowClosed(java.awt.event.WindowEvent evt) {
835 private void percentageThresholdCheckActionPerformed(java.awt.event.ActionEvent evt) {
836 if (this.percentageThresholdCheck.isSelected()) {
837 this.percentageThresholdInputBox.setEnabled(
true);
839 this.percentageThresholdInputBox.setEnabled(
false);
842 this.handleFrequencyPercentageState();
845 private void interCaseRadioActionPerformed(java.awt.event.ActionEvent evt) {
846 switchInnerPanel(interCasePanel);
849 private void intraCaseRadioActionPerformed(java.awt.event.ActionEvent evt) {
850 switchInnerPanel(intraCasePanel);
853 private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {
854 checkDataSourcesAndSearch();
858 private void caseResultsRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {
876 @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:",
877 "CommonAttributePanel.incompleteResults.continueText=\n\n Continue with search anyway?",
878 "CommonAttributePanel.incompleteResults.title=Search may be incomplete"
880 private void checkDataSourcesAndSearch() {
881 new SwingWorker<List<String>, Void>() {
884 protected List<String> doInBackground() throws Exception {
885 List<String> unCorrelatedDataSources =
new ArrayList<>();
886 if (!interCaseRadio.isSelected() || !CentralRepository.isEnabled() || CentralRepository.getInstance() == null) {
887 return unCorrelatedDataSources;
890 HashMap<DataSource, CorrelatedStatus> dataSourceCorrelationMap =
new HashMap<>();
891 String correlationEngineModuleName = CentralRepoIngestModuleFactory.getModuleName();
892 SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
893 List<CorrelationDataSource> correlatedDataSources = CentralRepository.getInstance().getDataSources();
894 List<IngestJobInfo> ingestJobs = skCase.getIngestJobs();
895 for (IngestJobInfo jobInfo : ingestJobs) {
897 DataSource dataSource = skCase.getDataSource(jobInfo.getObjectId());
898 String deviceID = dataSource.getDeviceId();
900 dataSourceCorrelationMap.putIfAbsent(dataSource, CorrelatedStatus.NOT_CORRELATED);
901 if (dataSourceCorrelationMap.get(dataSource) == CorrelatedStatus.NOT_CORRELATED) {
903 for (CorrelationDataSource correlatedDataSource : correlatedDataSources) {
904 if (deviceID.equals(correlatedDataSource.getDeviceID())) {
906 dataSourceCorrelationMap.put(dataSource, CorrelatedStatus.IN_CENTRAL_REPO);
911 if (dataSourceCorrelationMap.get(dataSource) == CorrelatedStatus.IN_CENTRAL_REPO) {
913 for (IngestModuleInfo ingestModuleInfo : jobInfo.getIngestModuleInfo()) {
914 if (correlationEngineModuleName.equals(ingestModuleInfo.getDisplayName())) {
915 dataSourceCorrelationMap.put(dataSource, CorrelatedStatus.CORRELATED);
922 for (DataSource dataSource : dataSourceCorrelationMap.keySet()) {
923 if (dataSourceCorrelationMap.get(dataSource) != CorrelatedStatus.CORRELATED) {
924 unCorrelatedDataSources.add(dataSource.getName());
927 return unCorrelatedDataSources;
931 protected void done() {
934 List<String> unProcessedDataSources =
get();
935 boolean performSearch =
true;
936 if (!unProcessedDataSources.isEmpty()) {
937 String warning = Bundle.CommonAttributePanel_incompleteResults_introText();
938 warning = unProcessedDataSources.stream().map((dataSource) ->
"\n - " + dataSource).reduce(warning, String::concat);
939 warning += Bundle.CommonAttributePanel_incompleteResults_continueText();
941 NotifyDescriptor descriptor =
new NotifyDescriptor.Confirmation(warning, Bundle.CommonAttributePanel_incompleteResults_title(), NotifyDescriptor.YES_NO_OPTION);
942 performSearch = DialogDisplayer.getDefault().notify(descriptor) == NotifyDescriptor.YES_OPTION;
945 if (interCaseRadio.isSelected() && caseResultsRadioButton.isSelected()) {
951 }
catch (InterruptedException | ExecutionException ex) {
952 LOGGER.log(Level.SEVERE,
"Unexpected exception while looking for common properties", ex);
962 private void percentageThresholdChanged() {
963 String percentageString = this.percentageThresholdInputBox.getText();
966 this.percentageThresholdValue = Integer.parseInt(percentageString);
968 }
catch (NumberFormatException ignored) {
969 this.percentageThresholdValue = -1;
972 this.handleFrequencyPercentageState();
979 private void updateErrorTextAndSearchButton() {
980 if (this.errorManager.anyErrors()) {
981 this.searchButton.setEnabled(
false);
983 this.errorText.setText(this.errorManager.getErrors().get(0));
984 this.errorText.setVisible(
true);
986 this.searchButton.setEnabled(
true);
987 this.errorText.setVisible(
false);
999 "# {0} - number of datasources",
1000 "CommonAttributePanel.dataSourcesLabel.text=The current Central Repository contains {0} data source(s)."})
1001 private void updatePercentageOptions(Long numberOfDataSources) {
1002 boolean enabled = numberOfDataSources > 0L;
1003 String numberOfDataSourcesText = enabled ? Bundle.CommonAttributePanel_dataSourcesLabel_text(numberOfDataSources) :
"";
1004 this.dataSourcesLabel.setText(numberOfDataSourcesText);
1005 this.percentageThresholdInputBox.setEnabled(enabled);
1006 this.percentageThresholdCheck.setEnabled(enabled);
1007 this.percentageThresholdCheck.setSelected(enabled);
1008 this.percentageThresholdTextTwo.setEnabled(enabled);
1017 private void handleFrequencyPercentageState() {
1018 if (this.percentageThresholdValue > 0 && this.percentageThresholdValue <= 100) {
1019 this.errorManager.setError(UserInputErrorManager.FREQUENCY_PERCENTAGE_OUT_OF_RANGE_KEY,
false);
1022 this.errorManager.setError(UserInputErrorManager.FREQUENCY_PERCENTAGE_OUT_OF_RANGE_KEY,
true);
1024 this.updateErrorTextAndSearchButton();
1028 private javax.swing.JRadioButton caseResultsRadioButton;
1029 private javax.swing.JLabel commonItemSearchDescription;
1030 private javax.swing.JPanel containerPanel;
1031 private javax.swing.JRadioButton countResultsRadioButton;
1032 private javax.swing.JLabel dataSourcesLabel;
1033 private javax.swing.ButtonGroup displayResultsButtonGroup;
1034 private javax.swing.JLabel displayResultsLabel;
1035 private javax.swing.JLabel errorText;
1036 private javax.swing.JRadioButton interCaseRadio;
1037 private javax.swing.ButtonGroup interIntraButtonGroup;
1038 private javax.swing.JRadioButton intraCaseRadio;
1039 private javax.swing.JPanel jPanel1;
1040 private javax.swing.JCheckBox percentageThresholdCheck;
1041 private javax.swing.JTextField percentageThresholdInputBox;
1042 private javax.swing.JLabel percentageThresholdTextTwo;
1043 private javax.swing.JLabel scopeLabel;
1044 private javax.swing.JButton searchButton;
1051 void observeSubPanels() {
1052 intraCasePanel.addObserver(
this);
1053 interCasePanel.addObserver(
this);
1061 private void checkFileTypeCheckBoxState() {
1062 boolean validCheckBoxState =
true;
1063 if (CommonAttributePanel.this.interCaseRadio.isSelected()) {
1064 if (interCasePanel.fileCategoriesButtonIsSelected()) {
1065 validCheckBoxState = interCasePanel.pictureVideoCheckboxIsSelected() || interCasePanel.documentsCheckboxIsSelected();
1068 if (intraCasePanel.fileCategoriesButtonIsSelected()) {
1069 validCheckBoxState = intraCasePanel.pictureVideoCheckboxIsSelected() || intraCasePanel.documentsCheckboxIsSelected();
1072 if (validCheckBoxState) {
1073 this.errorManager.setError(UserInputErrorManager.NO_FILE_CATEGORIES_SELECTED_KEY,
false);
1075 this.errorManager.setError(UserInputErrorManager.NO_FILE_CATEGORIES_SELECTED_KEY,
true);
1077 this.updateErrorTextAndSearchButton();