diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/UnpackagePortableCaseDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/UnpackagePortableCaseDialog.java index 9e347c3809..3b86909953 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/UnpackagePortableCaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/UnpackagePortableCaseDialog.java @@ -351,7 +351,11 @@ class UnpackagePortableCaseDialog extends javax.swing.JDialog { private void unpackageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_unpackageButtonActionPerformed UnpackagePortableCaseProgressDialog dialog = new UnpackagePortableCaseProgressDialog(); dialog.unpackageCase(caseTextField.getText(), outputTextField.getText()); - validatePaths(); // The output folder now exists so we need to disable the unpackage button + if (dialog.isSuccess()) { + dispose(); + } else { + validatePaths(); // The output folder now exists so we need to disable the unpackage button + } }//GEN-LAST:event_unpackageButtonActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/UnpackagePortableCaseProgressDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/UnpackagePortableCaseProgressDialog.java index 25b7ae084b..5f0f318183 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/UnpackagePortableCaseProgressDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/UnpackagePortableCaseProgressDialog.java @@ -44,11 +44,11 @@ import org.sleuthkit.datamodel.TskCoreException; class UnpackagePortableCaseProgressDialog extends javax.swing.JDialog implements PropertyChangeListener { private UnpackageWorker worker; - + /** * Creates new form UnpackagePortableCaseProgressDialog */ - @NbBundle.Messages({"UnpackagePortableCaseProgressDialog.title.text=Unpackage Portable Case Progress",}) + @NbBundle.Messages({"UnpackagePortableCaseProgressDialog.title.text=Unpackage Portable Case Progress",}) UnpackagePortableCaseProgressDialog() { super((JFrame) WindowManager.getDefault().getMainWindow(), Bundle.UnpackagePortableCaseProgressDialog_title_text(), @@ -56,32 +56,45 @@ class UnpackagePortableCaseProgressDialog extends javax.swing.JDialog implements initComponents(); customizeComponents(); } - + private void customizeComponents() { cancelButton.setEnabled(true); okButton.setEnabled(false); progressBar.setIndeterminate(true); resultLabel.setText(""); // NON-NLS } - + /** * Unpackage the case - * - * @param packagedCase The compressed case - * @param outputFolder The output folder + * + * @param packagedCase The compressed case + * @param outputFolder The output folder */ void unpackageCase(String packagedCase, String outputFolder) { - + worker = new UnpackageWorker(packagedCase, outputFolder); worker.addPropertyChangeListener(this); worker.execute(); setLocationRelativeTo((JFrame) WindowManager.getDefault().getMainWindow()); this.setVisible(true); - + } - - @NbBundle.Messages({"UnpackagePortableCaseProgressDialog.propertyChange.success=Successfully unpacked case",}) + + /** + * Returns whether the unpackaging was completed successfully. + * + * @return True if unpackaging was completed successfully, false otherwise + */ + boolean isSuccess() { + if (worker == null) { + return false; + } else { + return worker.isSuccess(); + } + } + + @NbBundle.Messages({"UnpackagePortableCaseProgressDialog.propertyChange.success=Successfully unpacked case",}) @Override public void propertyChange(PropertyChangeEvent evt) { @@ -92,7 +105,7 @@ class UnpackagePortableCaseProgressDialog extends javax.swing.JDialog implements // Disable cancel button and enable ok cancelButton.setEnabled(false); okButton.setEnabled(true); - + if (worker.isSuccess()) { progressBar.setIndeterminate(false); progressBar.setValue(progressBar.getMaximum()); @@ -106,48 +119,47 @@ class UnpackagePortableCaseProgressDialog extends javax.swing.JDialog implements } } } - + /** * Swing worker to do the decompression. */ private class UnpackageWorker extends SwingWorker { - + private final String packagedCase; private final String outputFolder; - + private final AtomicBoolean success = new AtomicBoolean(); private String lastError = ""; - + UnpackageWorker(String packagedCase, String outputFolder) { this.packagedCase = packagedCase; this.outputFolder = outputFolder; this.success.set(false); } - + @NbBundle.Messages({ - "UnpackageWorker.doInBackground.errorFinding7zip=Could not locate 7-Zip executable", - "UnpackageWorker.doInBackground.errorCompressingCase=Error unpackaging case", - "UnpackageWorker.doInBackground.canceled=Unpackaging canceled by user", - }) + "UnpackageWorker.doInBackground.errorFinding7zip=Could not locate 7-Zip executable", + "UnpackageWorker.doInBackground.errorCompressingCase=Error unpackaging case", + "UnpackageWorker.doInBackground.canceled=Unpackaging canceled by user",}) @Override protected Void doInBackground() throws Exception { - + // Find 7-Zip File sevenZipExe = locate7ZipExecutable(); if (sevenZipExe == null) { setDisplayError(Bundle.UnpackageWorker_doInBackground_errorFinding7zip()); throw new TskCoreException("Error finding 7-Zip executable"); // NON-NLS } - + String outputFolderSwitch = "-o" + outputFolder; // NON-NLS ProcessBuilder procBuilder = new ProcessBuilder(); procBuilder.command( sevenZipExe.getAbsolutePath(), - "x", // Extract + "x", // Extract packagedCase, outputFolderSwitch ); - + try { Process process = procBuilder.start(); @@ -158,7 +170,7 @@ class UnpackagePortableCaseProgressDialog extends javax.swing.JDialog implements } Thread.sleep(200); } - + int exitCode = process.exitValue(); if (exitCode != 0) { // Save any errors so they can be logged @@ -181,63 +193,64 @@ class UnpackagePortableCaseProgressDialog extends javax.swing.JDialog implements success.set(true); return null; } - + @Override synchronized protected void done() { if (this.isCancelled()) { return; } - + try { get(); } catch (Exception ex) { Logger.getLogger(UnpackagePortableCaseProgressDialog.class.getName()).log(Level.SEVERE, "Error unpackaging portable case", ex); // NON-NLS } } - + /** * Save the error that should be displayed to the user - * + * * @param errorStr Error to be displayed in the UI */ private synchronized void setDisplayError(String errorStr) { lastError = errorStr; } - + /** * Gets the error to display to the user + * * @return Error to be displayed in the UI */ private synchronized String getDisplayError() { return lastError; } - - private boolean isSuccess() { + + protected boolean isSuccess() { return success.get(); } - + /** - * Locate the 7-Zip executable from the release folder. - * - * @return 7-Zip executable - */ - private File locate7ZipExecutable() { - if (!PlatformUtil.isWindowsOS()) { - return null; - } + * Locate the 7-Zip executable from the release folder. + * + * @return 7-Zip executable + */ + private File locate7ZipExecutable() { + if (!PlatformUtil.isWindowsOS()) { + return null; + } - String executableToFindName = Paths.get("7-Zip", "7z.exe").toString(); // NON-NLS - File exeFile = InstalledFileLocator.getDefault().locate(executableToFindName, UnpackagePortableCaseProgressDialog.class.getPackage().getName(), false); - if (null == exeFile) { - return null; - } + String executableToFindName = Paths.get("7-Zip", "7z.exe").toString(); // NON-NLS + File exeFile = InstalledFileLocator.getDefault().locate(executableToFindName, UnpackagePortableCaseProgressDialog.class.getPackage().getName(), false); + if (null == exeFile) { + return null; + } - if (!exeFile.canExecute()) { - return null; - } + if (!exeFile.canExecute()) { + return null; + } - return exeFile; - } + return exeFile; + } } /** diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties index aa2b4b9297..fca33fe6f4 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties @@ -1,7 +1,6 @@ -DataContentViewerOtherCases.selectAllMenuItem.text=Select All DataContentViewerOtherCases.showCaseDetailsMenuItem.text=Show Case Details DataContentViewerOtherCases.table.toolTip.text=Click column name to sort. Right-click on the table for more options. -DataContentViewerOtherCases.exportToCSVMenuItem.text=Export Selected Rows to CSV +DataContentViewerOtherCases.exportToCSVMenuItem.text=Export all Other Occurrences to CSV DataContentViewerOtherCases.showCommonalityMenuItem.text=Show Frequency DataContentViewerOtherCases.earliestCaseDate.text=Earliest Case Date DataContentViewerOtherCases.earliestCaseLabel.toolTipText= diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties-MERGED index 21c7b81c76..b2606170ed 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties-MERGED @@ -13,12 +13,11 @@ DataContentViewerOtherCases.dataSources.header.text=Data Source Name DataContentViewerOtherCases.earliestCaseNotAvailable=\ Not Enabled. DataContentViewerOtherCases.foundIn.text=Found %d instances in %d cases and %d data sources. DataContentViewerOtherCases.noOpenCase.errMsg=No open case available. -DataContentViewerOtherCases.selectAllMenuItem.text=Select All DataContentViewerOtherCases.showCaseDetailsMenuItem.text=Show Case Details DataContentViewerOtherCases.table.noArtifacts=Item has no attributes with which to search. DataContentViewerOtherCases.table.noResultsFound=No results found. DataContentViewerOtherCases.table.toolTip.text=Click column name to sort. Right-click on the table for more options. -DataContentViewerOtherCases.exportToCSVMenuItem.text=Export Selected Rows to CSV +DataContentViewerOtherCases.exportToCSVMenuItem.text=Export all Other Occurrences to CSV DataContentViewerOtherCases.showCommonalityMenuItem.text=Show Frequency DataContentViewerOtherCases.earliestCaseDate.text=Earliest Case Date DataContentViewerOtherCases.earliestCaseLabel.toolTipText= diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form index e20c9954ac..fd1b0b81b1 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form @@ -11,13 +11,6 @@ - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index 659a5a04e9..259831824c 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -141,9 +141,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi private void customizeComponents() { ActionListener actList = (ActionEvent e) -> { JMenuItem jmi = (JMenuItem) e.getSource(); - if (jmi.equals(selectAllMenuItem)) { - filesTable.selectAll(); - } else if (jmi.equals(showCaseDetailsMenuItem)) { + if (jmi.equals(showCaseDetailsMenuItem)) { showCaseDetails(filesTable.getSelectedRow()); } else if (jmi.equals(exportToCSVMenuItem)) { try { @@ -157,7 +155,6 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi }; exportToCSVMenuItem.addActionListener(actList); - selectAllMenuItem.addActionListener(actList); showCaseDetailsMenuItem.addActionListener(actList); showCommonalityMenuItem.addActionListener(actList); @@ -956,7 +953,6 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi private void initComponents() { rightClickPopupMenu = new javax.swing.JPopupMenu(); - selectAllMenuItem = new javax.swing.JMenuItem(); exportToCSVMenuItem = new javax.swing.JMenuItem(); showCaseDetailsMenuItem = new javax.swing.JMenuItem(); showCommonalityMenuItem = new javax.swing.JMenuItem(); @@ -986,9 +982,6 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi } }); - org.openide.awt.Mnemonics.setLocalizedText(selectAllMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.selectAllMenuItem.text")); // NOI18N - rightClickPopupMenu.add(selectAllMenuItem); - org.openide.awt.Mnemonics.setLocalizedText(exportToCSVMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.exportToCSVMenuItem.text")); // NOI18N rightClickPopupMenu.add(exportToCSVMenuItem); @@ -1130,7 +1123,6 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi private javax.swing.JScrollPane filesTableScrollPane; private javax.swing.JLabel foundInLabel; private javax.swing.JPopupMenu rightClickPopupMenu; - private javax.swing.JMenuItem selectAllMenuItem; private javax.swing.JMenuItem showCaseDetailsMenuItem; private javax.swing.JMenuItem showCommonalityMenuItem; private javax.swing.JPanel tableContainerPanel; diff --git a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InstanceCountNode.java b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InstanceCountNode.java index d3d1de26b8..5be8f8bae2 100644 --- a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InstanceCountNode.java +++ b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InstanceCountNode.java @@ -123,9 +123,9 @@ public final class InstanceCountNode extends DisplayableItemNode { final String NO_DESCR = Bundle.InstanceCountNode_createSheet_noDescription(); sheetSet.put(new NodeProperty<>(NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.nameColLbl"), NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.nameColLbl"), NO_DESCR, "")); - sheetSet.put(new NodeProperty<>(NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"), NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"), NO_DESCR, "")); - sheetSet.put(new NodeProperty<>(NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"), NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"), NO_DESCR, "")); - if (UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) { + if (UserPreferences.getHideSCOColumns() == false) { + sheetSet.put(new NodeProperty<>(NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"), NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"), NO_DESCR, "")); + sheetSet.put(new NodeProperty<>(NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"), NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"), NO_DESCR, "")); sheetSet.put(new NodeProperty<>(NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.count.name"), NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.count.name"), NO_DESCR, "")); } sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_instancesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_instancesColLbl(), NO_DESCR, this.getInstanceCount())); diff --git a/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.java b/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.java index fe66b2fa6e..0cad213cd4 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.java @@ -108,7 +108,7 @@ public final class AccountsBrowser extends JPanel implements ExplorerManager.Pro accountDeviceInstances.add(((AccountDeviceInstanceNode) node).getAccountDeviceInstance()); filter = ((AccountDeviceInstanceNode)node).getFilter(); } - relationshipBrowser.setSelectionInfo(new SelectionInfo(accountDeviceInstances, filter)); + relationshipBrowser.setSelectionInfo(new SelectionInfo(accountDeviceInstances, new HashSet<>(), filter)); } }); diff --git a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java index 027f2f285a..10732c630f 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java @@ -914,23 +914,24 @@ final public class VisualizationPanel extends JPanel { Object[] selectionCells = graph.getSelectionCells(); if (selectionCells.length > 0) { mxICell[] selectedCells = Arrays.asList(selectionCells).toArray(new mxCell[selectionCells.length]); - HashSet deviceInstances = new HashSet<>(); + HashSet selectedNodes = new HashSet<>(); + HashSet selectedEdges = new HashSet<>(); for (mxICell cell : selectedCells) { if (cell.isEdge()) { mxICell source = (mxICell) graph.getModel().getTerminal(cell, true); mxICell target = (mxICell) graph.getModel().getTerminal(cell, false); - deviceInstances.add(((AccountDeviceInstanceKey) source.getValue()).getAccountDeviceInstance()); - deviceInstances.add(((AccountDeviceInstanceKey) target.getValue()).getAccountDeviceInstance()); + selectedEdges.add(new SelectionInfo.GraphEdge(((AccountDeviceInstanceKey) source.getValue()).getAccountDeviceInstance(), + ((AccountDeviceInstanceKey) target.getValue()).getAccountDeviceInstance())); } else if (cell.isVertex()) { - deviceInstances.add(((AccountDeviceInstanceKey) cell.getValue()).getAccountDeviceInstance()); + selectedNodes.add(((AccountDeviceInstanceKey) cell.getValue()).getAccountDeviceInstance()); } } - relationshipBrowser.setSelectionInfo(new SelectionInfo(deviceInstances, currentFilter)); + relationshipBrowser.setSelectionInfo(new SelectionInfo(selectedNodes, selectedEdges, currentFilter)); } else { - relationshipBrowser.setSelectionInfo(new SelectionInfo(Collections.EMPTY_SET, currentFilter)); + relationshipBrowser.setSelectionInfo(new SelectionInfo(new HashSet<>(), new HashSet<>(), currentFilter)); } } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties b/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties index 970f5474a4..701a7b1261 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties @@ -1,13 +1,11 @@ ContactDetailsPane.nameLabel.text=Placeholder SummaryViewer.countsPanel.border.title=Counts -SummaryViewer.emailLabel.text=Emails: SummaryViewer.contactsLabel.text=Contacts: -SummaryViewer.attachmentsLabel.text=Attachments: +SummaryViewer.attachmentsLabel.text=Media Attachments: OutlineViewPanel.messageLabel.text= SummaryViewer.messagesDataLabel.text=messages SummaryViewer.callLogsDataLabel.text=callLogs SummaryViewer.contactsDataLabel.text=contacts -SummaryViewer.emailDataLabel.text=emails SummaryViewer.attachmentsDataLabel.text=attachments SummaryViewer.messagesLabel.text=Messages: SummaryViewer.callLogsLabel.text=Call Logs: diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties-MERGED index 75c26378b3..f82411bf9d 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties-MERGED @@ -11,7 +11,7 @@ ContactsViewer_columnHeader_Name=Name ContactsViewer_columnHeader_Phone=Phone ContactsViewer_noContacts_message= ContactsViewer_tabTitle=Contacts -MediaViewer_Name=Media +MediaViewer_Name=Media Attachments MessageNode_Node_Property_Attms=Attachments MessageNode_Node_Property_Date=Date MessageNode_Node_Property_From=From @@ -27,17 +27,16 @@ MessageViewer_columnHeader_To=To MessageViewer_no_messages= MessageViewer_tabTitle=Messages MessageViewer_viewMessage_all=All +MessageViewer_viewMessage_calllogs=Call Logs MessageViewer_viewMessage_selected=Selected MessageViewer_viewMessage_unthreaded=Unthreaded SummaryViewer.countsPanel.border.title=Counts -SummaryViewer.emailLabel.text=Emails: SummaryViewer.contactsLabel.text=Contacts: -SummaryViewer.attachmentsLabel.text=Attachments: +SummaryViewer.attachmentsLabel.text=Media Attachments: OutlineViewPanel.messageLabel.text= SummaryViewer.messagesDataLabel.text=messages SummaryViewer.callLogsDataLabel.text=callLogs SummaryViewer.contactsDataLabel.text=contacts -SummaryViewer.emailDataLabel.text=emails SummaryViewer.attachmentsDataLabel.text=attachments SummaryViewer.messagesLabel.text=Messages: SummaryViewer.callLogsLabel.text=Call Logs: diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsChildNodeFactory.java index 07f98c613b..28666c8fdd 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsChildNodeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsChildNodeFactory.java @@ -68,36 +68,28 @@ final class ContactsChildNodeFactory extends ChildFactory{ */ @Override protected boolean createKeys(List list) { - CommunicationsManager communicationManager; - try { - communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager(); - } catch (NoCurrentCaseException | TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to get communications manager from case.", ex); //NON-NLS - return false; - } if(selectionInfo == null) { return true; } final Set relationshipSources; - try { - relationshipSources = communicationManager.getRelationshipSources(selectionInfo.getAccountDevicesInstances(), selectionInfo.getCommunicationsFilter()); - - relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> { - - BlackboardArtifact bba = (BlackboardArtifact) content; - BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID()); - - if (fromID == TSK_CONTACT) { - list.add(bba); - } - }); - + relationshipSources = selectionInfo.getRelationshipSources(); } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to get relationship sources.", ex); //NON-NLS + logger.log(Level.SEVERE, "Failed to load relationship sources.", ex); //NON-NLS + return false; } + + relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> { + + BlackboardArtifact bba = (BlackboardArtifact) content; + BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID()); + + if (fromID == TSK_CONTACT) { + list.add(bba); + } + }); return true; } diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java index 03412a0263..07e6223a03 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java @@ -59,7 +59,7 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM private final ModifiableProxyLookup proxyLookup; @Messages({ - "MediaViewer_Name=Media" + "MediaViewer_Name=Media Attachments" }) /** * Creates new form ThumbnailViewer @@ -113,20 +113,17 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM @Override public void setSelectionInfo(SelectionInfo info) { - final Set relationshipSources; - - CommunicationsManager communicationManager; + Set relationshipSources; Set artifactList = new HashSet<>(); try { - communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager(); - relationshipSources = communicationManager.getRelationshipSources(info.getAccountDevicesInstances(), info.getCommunicationsFilter()); + relationshipSources = info.getRelationshipSources(); relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> { artifactList.add((BlackboardArtifact) content); }); - } catch (TskCoreException | NoCurrentCaseException ex) { + } catch (TskCoreException ex) { logger.log(Level.WARNING, "Unable to update selection." , ex); } diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java index cc67e10fbd..d34bc084da 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java @@ -48,6 +48,7 @@ import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; class MessageNode extends BlackboardArtifactNode { public static final String UNTHREADED_ID = ""; + public static final String CALL_LOG_ID = ""; private static final Logger logger = Logger.getLogger(MessageNode.class.getName()); @@ -87,9 +88,14 @@ class MessageNode extends BlackboardArtifactNode { sheetSet.put(new NodeProperty<>("Type", Bundle.MessageNode_Node_Property_Type(), "", getDisplayName())); //NON-NLS - sheetSet.put(new NodeProperty<>("ThreadID", "ThreadID","",threadID == null ? UNTHREADED_ID : threadID)); //NON-NLS + final BlackboardArtifact artifact = getArtifact(); + if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()) { + sheetSet.put(new NodeProperty<>("ThreadID", "ThreadID","",CALL_LOG_ID)); //NON-NLS + } else { + sheetSet.put(new NodeProperty<>("ThreadID", "ThreadID","",threadID == null ? UNTHREADED_ID : threadID)); //NON-NLS + } BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID()); if (null != fromID) { diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java index ad8d5eb7b3..4c7be60e80 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java @@ -82,7 +82,8 @@ public class MessageViewer extends JPanel implements RelationshipsViewer { "MessageViewer_no_messages=", "MessageViewer_viewMessage_all=All", "MessageViewer_viewMessage_selected=Selected", - "MessageViewer_viewMessage_unthreaded=Unthreaded",}) + "MessageViewer_viewMessage_unthreaded=Unthreaded", + "MessageViewer_viewMessage_calllogs=Call Logs"}) /** * Creates new form MessageViewer @@ -228,7 +229,11 @@ public class MessageViewer extends JPanel implements RelationshipsViewer { if (!subject.isEmpty()) { threadNameLabel.setText(subject); } else { - threadNameLabel.setText(Bundle.MessageViewer_viewMessage_unthreaded()); + if (threadIDList.contains(MessageNode.CALL_LOG_ID)) { + threadNameLabel.setText(Bundle.MessageViewer_viewMessage_calllogs()); + } else { + threadNameLabel.setText(Bundle.MessageViewer_viewMessage_unthreaded()); + } } showMessagesPane(); diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesChildNodeFactory.java index 726fba4341..5039ce225e 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesChildNodeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesChildNodeFactory.java @@ -70,24 +70,20 @@ public class MessagesChildNodeFactory extends ChildFactory{ @Override protected boolean createKeys(List list) { - CommunicationsManager communicationManager; - - try { - communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager(); - } catch (NoCurrentCaseException | TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to get communications manager from case.", ex); //NON-NLS - return false; - } if(selectionInfo == null) { return true; } - + final Set relationshipSources; + try { + relationshipSources = selectionInfo.getRelationshipSources(); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Failed to load relationship sources.", ex); //NON-NLS + return false; + } try { - - relationshipSources = communicationManager.getRelationshipSources(selectionInfo.getAccountDevicesInstances(), selectionInfo.getCommunicationsFilter()); for(Content content: relationshipSources) { if( !(content instanceof BlackboardArtifact)){ continue; @@ -102,10 +98,16 @@ public class MessagesChildNodeFactory extends ChildFactory{ continue; } - // We want all artifacts that do not have "threadIDs" to appear as one thread in the UI + // We want email and message artifacts that do not have "threadIDs" to appear as one thread in the UI // To achive this assign any artifact that does not have a threadID // the "UNTHREADED_ID" - String artifactThreadID = MessageNode.UNTHREADED_ID; + // All call logs will default to a single call logs thread + String artifactThreadID; + if (fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG) { + artifactThreadID = MessageNode.CALL_LOG_ID; + } else { + artifactThreadID = MessageNode.UNTHREADED_ID; + } BlackboardAttribute attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID)); if(attribute != null) { @@ -119,7 +121,7 @@ public class MessagesChildNodeFactory extends ChildFactory{ } } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to get relationship sources.", ex); //NON-NLS + logger.log(Level.SEVERE, "Failed to load artifacts for relationship sources.", ex); //NON-NLS } return true; diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/SelectionInfo.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/SelectionInfo.java index 16c92b3b94..45ece0a5be 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/SelectionInfo.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/SelectionInfo.java @@ -40,7 +40,8 @@ public final class SelectionInfo { private static final Logger logger = Logger.getLogger(SelectionInfo.class.getName()); - private final Set accountDeviceInstances; + private final Set selectedNodes; + private final Set selectedEdges; private final CommunicationsFilter communicationFilter; private final Set accounts; @@ -50,26 +51,38 @@ public final class SelectionInfo { /** * Wraps the details of the currently selected accounts. * - * @param accountDeviceInstances Selected accountDecivedInstances + * @param selectedNodes Selected AccountDeviceInstances + * @param selectedEdges Selected pairs of AccountDeviceInstances * @param communicationFilter Currently selected communications filters */ - public SelectionInfo(Set accountDeviceInstances, CommunicationsFilter communicationFilter) { - this.accountDeviceInstances = accountDeviceInstances; + public SelectionInfo(Set selectedNodes, Set selectedEdges, + CommunicationsFilter communicationFilter) { + this.selectedNodes = selectedNodes; + this.selectedEdges = selectedEdges; this.communicationFilter = communicationFilter; accounts = new HashSet<>(); - accountDeviceInstances.forEach((instance) -> { + selectedNodes.forEach((instance) -> { accounts.add(instance.getAccount()); }); } /** - * Returns the currently selected accountDeviceInstances + * Returns the currently selected nodes * * @return Set of AccountDeviceInstance */ - public Set getAccountDevicesInstances() { - return accountDeviceInstances; + public Set getSelectedNodes() { + return selectedNodes; + } + + /** + * Returns the currently selected edges + * + * @return Set of GraphEdge objects + */ + public Set getSelectedEdges() { + return selectedEdges; } /** @@ -85,28 +98,50 @@ public final class SelectionInfo { return accounts; } + /** + * Get the set of relationship sources from the case database + * + * @return the relationship sources (may be empty) + * @throws TskCoreException + */ + Set getRelationshipSources() throws TskCoreException { + + CommunicationsManager communicationManager; + try { + communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager(); + } catch (NoCurrentCaseException ex) { + throw new TskCoreException("Failed to get current case", ex); + } + + Set relationshipSources = new HashSet<>(); + try { + // Add all nodes + relationshipSources.addAll(communicationManager.getRelationshipSources(getSelectedNodes(), getCommunicationsFilter())); + + // Add all edges. For edges, the relationship has to include both endpoints + for (SelectionInfo.GraphEdge edge : getSelectedEdges()) { + relationshipSources.addAll(communicationManager.getRelationshipSources(edge.getStartNode(), + edge.getEndNode(), getCommunicationsFilter())); + } + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Failed to get relationships from case database.", ex); //NON-NLS + + } + return relationshipSources; + } + public Set getArtifacts() { if(accountArtifacts == null) { accountArtifacts = new HashSet<>(); - CommunicationsManager communicationManager; + try { - communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager(); - } catch (NoCurrentCaseException | TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to get communications manager from case.", ex); //NON-NLS - return null; - } - - final Set relationshipSources; - - try { - relationshipSources = communicationManager.getRelationshipSources(getAccountDevicesInstances(), getCommunicationsFilter()); - + final Set relationshipSources = getRelationshipSources(); relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> { accountArtifacts.add((BlackboardArtifact) content); }); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to get relationship sources.", ex); //NON-NLS + logger.log(Level.SEVERE, "Failed to load relationship sources.", ex); //NON-NLS + return accountArtifacts; } } @@ -182,4 +217,24 @@ public final class SelectionInfo { } } + /** + * Utility class to represent an edge from the graph visualization. + */ + public static class GraphEdge { + AccountDeviceInstance startNode; + AccountDeviceInstance endNode; + + public GraphEdge(AccountDeviceInstance startNode, AccountDeviceInstance endNode) { + this.startNode = startNode; + this.endNode = endNode; + } + + public AccountDeviceInstance getStartNode() { + return startNode; + } + + public AccountDeviceInstance getEndNode() { + return endNode; + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/SummaryViewer.form b/Core/src/org/sleuthkit/autopsy/communications/relationships/SummaryViewer.form index c789e2c0cd..85ddc8a2c8 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/SummaryViewer.form +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/SummaryViewer.form @@ -11,7 +11,7 @@ - + @@ -38,21 +38,19 @@ - - + - + - - + @@ -60,11 +58,6 @@ - - - - - @@ -81,8 +74,8 @@ - - + + @@ -90,13 +83,6 @@ - - - - - - - @@ -153,13 +139,6 @@ - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/SummaryViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/SummaryViewer.java index 464fb137f8..5602152ba2 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/SummaryViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/SummaryViewer.java @@ -47,8 +47,7 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi "SummaryViewer_CaseRefNameColumn_Title=Case Name", "SummaryViewer_CentralRepository_Message=", "SummaryViewer_Creation_Date_Title=Creation Date", - "SummeryViewer_FileRef_Message=",}) /** * Creates new form SummaryViewer @@ -71,7 +70,7 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.SummaryViewer_CaseRefNameColumn_Title()); clearControls(); - + caseReferencesPanel.hideOutlineView(Bundle.SummaryViewer_CentralRepository_Message()); fileReferencesPanel.hideOutlineView(Bundle.SummeryViewer_FileRef_Message()); } @@ -100,7 +99,7 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi if (info.getAccounts().size() != 1) { setEnabled(false); clearControls(); - + fileReferencesPanel.hideOutlineView(Bundle.SummeryViewer_FileRef_Message()); } else { SelectionSummary summaryDetails = info.getSummary(); @@ -108,9 +107,8 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi attachmentsDataLabel.setText(Integer.toString(summaryDetails.getAttachmentCnt())); callLogsDataLabel.setText(Integer.toString(summaryDetails.getCallLogCnt())); contactsDataLabel.setText(Integer.toString(summaryDetails.getContactsCnt())); - emailDataLabel.setText(Integer.toString(summaryDetails.getEmailCnt())); - messagesDataLabel.setText(Integer.toString(summaryDetails.getMessagesCnt())); - + messagesDataLabel.setText(Integer.toString(summaryDetails.getMessagesCnt() + summaryDetails.getEmailCnt())); + fileReferencesPanel.showOutlineView(); fileReferencesPanel.setNode(new AbstractNode(Children.create(new AccountSourceContentChildNodeFactory(info.getAccounts()), true))); @@ -136,7 +134,6 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi attachmentsLabel.setEnabled(enabled); callLogsLabel.setEnabled(enabled); contactsLabel.setEnabled(enabled); - emailLabel.setEnabled(enabled); messagesLabel.setEnabled(enabled); caseReferencesPanel.setEnabled(enabled); fileReferencesPanel.setEnabled(enabled); @@ -150,7 +147,6 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi attachmentsDataLabel.setText(""); callLogsDataLabel.setText(""); contactsDataLabel.setText(""); - emailDataLabel.setText(""); messagesDataLabel.setText(""); fileReferencesPanel.setNode(new AbstractNode(Children.LEAF)); @@ -188,7 +184,6 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi java.awt.GridBagConstraints gridBagConstraints; countsPanel = new javax.swing.JPanel(); - emailLabel = new javax.swing.JLabel(); contactsLabel = new javax.swing.JLabel(); messagesLabel = new javax.swing.JLabel(); callLogsLabel = new javax.swing.JLabel(); @@ -197,7 +192,6 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi messagesDataLabel = new javax.swing.JLabel(); callLogsDataLabel = new javax.swing.JLabel(); contactsDataLabel = new javax.swing.JLabel(); - emailDataLabel = new javax.swing.JLabel(); fileReferencesPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel(); caseReferencesPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel(); @@ -205,8 +199,6 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi countsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.countsPanel.border.title"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(emailLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.emailLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(contactsLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.contactsLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(messagesLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.messagesLabel.text")); // NOI18N @@ -223,8 +215,6 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi org.openide.awt.Mnemonics.setLocalizedText(contactsDataLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.contactsDataLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(emailDataLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.emailDataLabel.text")); // NOI18N - javax.swing.GroupLayout countsPanelLayout = new javax.swing.GroupLayout(countsPanel); countsPanel.setLayout(countsPanelLayout); countsPanelLayout.setHorizontalGroup( @@ -232,28 +222,22 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi .addGroup(countsPanelLayout.createSequentialGroup() .addContainerGap() .addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(attachmentsLabel) .addComponent(messagesLabel) .addComponent(callLogsLabel) .addComponent(contactsLabel) - .addComponent(emailLabel)) + .addComponent(attachmentsLabel)) .addGap(18, 18, 18) .addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(emailDataLabel) + .addComponent(attachmentsDataLabel) .addComponent(contactsDataLabel) .addComponent(callLogsDataLabel) - .addComponent(messagesDataLabel) - .addComponent(attachmentsDataLabel)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(messagesDataLabel)) + .addContainerGap(959, Short.MAX_VALUE)) ); countsPanelLayout.setVerticalGroup( countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(countsPanelLayout.createSequentialGroup() .addGap(7, 7, 7) - .addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(attachmentsLabel) - .addComponent(attachmentsDataLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(messagesLabel) .addComponent(messagesDataLabel)) @@ -267,8 +251,8 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi .addComponent(contactsDataLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(emailLabel) - .addComponent(emailDataLabel)) + .addComponent(attachmentsLabel) + .addComponent(attachmentsDataLabel)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); @@ -311,8 +295,6 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi private javax.swing.JLabel contactsDataLabel; private javax.swing.JLabel contactsLabel; private javax.swing.JPanel countsPanel; - private javax.swing.JLabel emailDataLabel; - private javax.swing.JLabel emailLabel; private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel fileReferencesPanel; private javax.swing.JLabel messagesDataLabel; private javax.swing.JLabel messagesLabel; diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java index 8c4f8b40de..1cf987d132 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java @@ -83,26 +83,16 @@ final class ThreadChildNodeFactory extends ChildFactory { */ @Override protected boolean createKeys(List list) { - CommunicationsManager communicationManager; - try { - communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager(); - } catch (NoCurrentCaseException | TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to get communications manager from case.", ex); //NON-NLS - return false; - } - if(selectionInfo == null) { return true; } - - final Set relationshipSources; - + try { - relationshipSources = communicationManager.getRelationshipSources(selectionInfo.getAccountDevicesInstances(), selectionInfo.getCommunicationsFilter()); - + final Set relationshipSources = selectionInfo.getRelationshipSources(); createRootMessageKeys(list, relationshipSources) ; } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to get relationship sources.", ex); //NON-NLS + logger.log(Level.SEVERE, "Failed to load relationship sources.", ex); //NON-NLS + return false; } return true; @@ -133,10 +123,16 @@ final class ThreadChildNodeFactory extends ChildFactory { || fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG || fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) { - // We want all artifacts that do not have "threadIDs" to appear as one thread in the UI + // We want email and message artifacts that do not have "threadIDs" to appear as one thread in the UI // To achive this assign any artifact that does not have a threadID // the "UNTHREADED_ID" - String threadID = MessageNode.UNTHREADED_ID; + // All call logs will default to a single call logs thread + String threadID; + if (fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG) { + threadID = MessageNode.CALL_LOG_ID; + } else { + threadID = MessageNode.UNTHREADED_ID; + } BlackboardAttribute attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID)); if(attribute != null) { @@ -180,13 +176,46 @@ final class ThreadChildNodeFactory extends ChildFactory { if (attribute != null) { return new ThreadNode(bba, attribute.getValueString(), preferredAction); } else { - // Only one of these should occur. - return new UnthreadedNode(); + if (bba.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()) { + return new CallLogNode(); + } else { + // Only one of these should occur. + return new UnthreadedNode(); + } } } /** - * An this node represents the "unthreaded" thread. + * This node represents the "call log" thread. + */ + final class CallLogNode extends AbstractNode { + /** + * Construct an instance of a CallLogNode. + */ + CallLogNode() { + super(Children.LEAF); + setDisplayName("Call Logs"); + this.setIconBaseWithExtension("org/sleuthkit/autopsy/communications/images/unthreaded.png" ); + } + + @Override + protected Sheet createSheet() { + Sheet sheet = super.createSheet(); + Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES); + if (sheetSet == null) { + sheetSet = Sheet.createPropertiesSet(); + sheet.put(sheetSet); + } + + // Give this node a threadID of "CALL_LOG_ID" + sheetSet.put(new NodeProperty<>("ThreadID", "ThreadID","",MessageNode.CALL_LOG_ID)); + + return sheet; + } + } + + /** + * This node represents the "unthreaded" thread. */ final class UnthreadedNode extends AbstractNode { /** diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadNode.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadNode.java index f398b94757..013730a097 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadNode.java @@ -25,7 +25,7 @@ import org.openide.nodes.Sheet; import org.sleuthkit.datamodel.BlackboardArtifact; /** - * An AbstractNode subclass which wraps a MessagNode object. Doing this allows + * An AbstractNode subclass which wraps a MessageNode object. Doing this allows * for the reuse of the createSheet and other function from MessageNode, but * also some customizing of how a ThreadNode is shown. */ diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED index b9f5986b41..ff3341b60f 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED @@ -42,11 +42,15 @@ MediaFileViewer.toolTip=Displays supported multimedia files (images, videos, aud MediaPlayerPanel.noSupport=File not supported. MediaPlayerPanel.timeFormat=%02d:%02d:%02d MediaPlayerPanel.unknownTime=Unknown +MediaViewImagePanel.createTagOption=Create +MediaViewImagePanel.deleteTagOption=Delete MediaViewImagePanel.errorLabel.OOMText=Could not load file into Media View: insufficent memory. MediaViewImagePanel.errorLabel.text=Could not load file into Media View. MediaViewImagePanel.exportSaveText=Save +MediaViewImagePanel.exportTagOption=Export MediaViewImagePanel.externalViewerButton.text=Open in External Viewer Ctrl+E MediaViewImagePanel.fileChooserTitle=Choose a save location +MediaViewImagePanel.hideTagOption=Hide MediaViewImagePanel.successfulExport=Tagged image was successfully saved. MediaViewImagePanel.unsuccessfulExport=Unable to export tagged image to disk. MediaViewVideoPanel.pauseButton.text=\u25ba diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java index 746c16c4c0..0e1b9c9fb1 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java @@ -83,8 +83,10 @@ import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagRegion; import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagCreator; import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTag; import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagsGroup; +import org.sleuthkit.autopsy.corelibs.OpenCvLoader; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.datamodel.AbstractFile; @@ -116,7 +118,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan private final ProgressBar progressBar = new ProgressBar(); private final MaskerPane maskerPane = new MaskerPane(); - private final JPopupMenu popupMenu = new JPopupMenu(); + private final JPopupMenu imageTaggingOptions = new JPopupMenu(); private final JMenuItem createTagMenuItem; private final JMenuItem deleteTagMenuItem; private final JMenuItem hideTagsMenuItem; @@ -158,6 +160,12 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan /** * Creates new form MediaViewImagePanel */ + @NbBundle.Messages({ + "MediaViewImagePanel.createTagOption=Create", + "MediaViewImagePanel.deleteTagOption=Delete", + "MediaViewImagePanel.hideTagOption=Hide", + "MediaViewImagePanel.exportTagOption=Export" + }) public MediaViewImagePanel() { initComponents(); fxInited = org.sleuthkit.autopsy.core.Installer.isJavaFxInited(); @@ -166,29 +174,35 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan exportChooser.setDialogTitle(Bundle.MediaViewImagePanel_fileChooserTitle()); //Build popupMenu when Tags Menu button is pressed. - createTagMenuItem = new JMenuItem("Create"); + createTagMenuItem = new JMenuItem(Bundle.MediaViewImagePanel_createTagOption()); createTagMenuItem.addActionListener((event) -> createTag()); - popupMenu.add(createTagMenuItem); + imageTaggingOptions.add(createTagMenuItem); - popupMenu.add(new JSeparator()); + imageTaggingOptions.add(new JSeparator()); - deleteTagMenuItem = new JMenuItem("Delete"); + deleteTagMenuItem = new JMenuItem(Bundle.MediaViewImagePanel_deleteTagOption()); deleteTagMenuItem.addActionListener((event) -> deleteTag()); - popupMenu.add(deleteTagMenuItem); + imageTaggingOptions.add(deleteTagMenuItem); - popupMenu.add(new JSeparator()); + imageTaggingOptions.add(new JSeparator()); - hideTagsMenuItem = new JMenuItem("Hide"); + hideTagsMenuItem = new JMenuItem(Bundle.MediaViewImagePanel_hideTagOption()); hideTagsMenuItem.addActionListener((event) -> showOrHideTags()); - popupMenu.add(hideTagsMenuItem); + imageTaggingOptions.add(hideTagsMenuItem); - popupMenu.add(new JSeparator()); + imageTaggingOptions.add(new JSeparator()); - exportTagsMenuItem = new JMenuItem("Export"); + exportTagsMenuItem = new JMenuItem(Bundle.MediaViewImagePanel_exportTagOption()); exportTagsMenuItem.addActionListener((event) -> exportTags()); - popupMenu.add(exportTagsMenuItem); + imageTaggingOptions.add(exportTagsMenuItem); - popupMenu.setPopupSize(300, 150); + imageTaggingOptions.setPopupSize(300, 150); + + //Disable image tagging for non-windows users or upon failure to load OpenCV. + if (!PlatformUtil.isWindowsOS() || !OpenCvLoader.hasOpenCvLoaded()) { + tagsMenu.setEnabled(false); + imageTaggingOptions.setEnabled(false); + } if (fxInited) { Platform.runLater(new Runnable() { @@ -893,7 +907,9 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan } private void tagsMenuMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_tagsMenuMousePressed - popupMenu.show(tagsMenu, -300 + tagsMenu.getWidth(), tagsMenu.getHeight() + 3); + if (imageTaggingOptions.isEnabled()) { + imageTaggingOptions.show(tagsMenu, -300 + tagsMenu.getWidth(), tagsMenu.getHeight() + 3); + } }//GEN-LAST:event_tagsMenuMousePressed /** diff --git a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java index c18d8b0f96..0d2bfa90d3 100644 --- a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java +++ b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java @@ -73,12 +73,12 @@ public final class UserPreferences { private static final int LOG_FILE_NUM_INT = 10; public static final String GROUP_ITEMS_IN_TREE_BY_DATASOURCE = "GroupItemsInTreeByDataSource"; //NON-NLS public static final String SHOW_ONLY_CURRENT_USER_TAGS = "ShowOnlyCurrentUserTags"; - public static final String HIDE_CENTRAL_REPO_COMMENTS_AND_OCCURRENCES = "HideCentralRepoCommentsAndOccurrences"; + public static final String HIDE_SCO_COLUMNS = "HideCentralRepoCommentsAndOccurrences"; //The key for this setting pre-dates the settings current functionality //NON-NLS public static final String DISPLAY_TRANSLATED_NAMES = "DisplayTranslatedNames"; public static final String EXTERNAL_HEX_EDITOR_PATH = "ExternalHexEditorPath"; public static final String SOLR_MAX_JVM_SIZE = "SolrMaxJVMSize"; public static final String RESULTS_TABLE_PAGE_SIZE = "ResultsTablePageSize"; - + // Prevent instantiation. private UserPreferences() { } @@ -187,11 +187,11 @@ public final class UserPreferences { public static void setDisplayTimesInLocalTime(boolean value) { preferences.putBoolean(DISPLAY_TIMES_IN_LOCAL_TIME, value); } - + public static String getTimeZoneForDisplays() { return preferences.get(TIME_ZONE_FOR_DISPLAYS, TimeZone.GMT_ZONE.getID()); } - + public static void setTimeZoneForDisplays(String timeZone) { preferences.put(TIME_ZONE_FOR_DISPLAYS, timeZone); } @@ -224,11 +224,10 @@ public final class UserPreferences { return preferences.getBoolean(SHOW_ONLY_CURRENT_USER_TAGS, false); } - /** * Set the user preference which identifies whether tags should be shown for * only the current user or all users. - * + * * @param value - true for just the current user, false for all users */ public static void setShowOnlyCurrentUserTags(boolean value) { @@ -236,33 +235,31 @@ public final class UserPreferences { } /** - * Get the user preference which identifies whether the Central Repository - * should be called to get comments and occurrences for the (C)omments and - * (O)ccurrences columns in the result view. - * - * @return True if hiding Central Repository data for comments and - * occurrences; otherwise false. + * Get the user preference which identifies whether the (S)core, (C)omments, + * and (O)ccurrences columns should be populated and displayed in the result + * view. + * + * @return True if hiding SCO columns; otherwise false. */ - public static boolean hideCentralRepoCommentsAndOccurrences() { - return preferences.getBoolean(HIDE_CENTRAL_REPO_COMMENTS_AND_OCCURRENCES, false); + public static boolean getHideSCOColumns() { + return preferences.getBoolean(HIDE_SCO_COLUMNS, false); } - /** - * Set the user preference which identifies whether the Central Repository - * should be called to get comments and occurrences for the (C)omments and - * (O)ccurrences columns in the result view. - * + * Set the user preference which identifies whether the (S)core, (C)omments, + * and (O)ccurrences columns should be populated and displayed in the result + * view. + * * @param value The value of which to assign to the user preference. */ - public static void setHideCentralRepoCommentsAndOccurrences(boolean value) { - preferences.putBoolean(HIDE_CENTRAL_REPO_COMMENTS_AND_OCCURRENCES, value); + public static void setHideSCOColumns(boolean value) { + preferences.putBoolean(HIDE_SCO_COLUMNS, value); } - + public static void setDisplayTranslatedFileNames(boolean value) { preferences.putBoolean(DISPLAY_TRANSLATED_NAMES, value); } - + public static boolean displayTranslatedFileNames() { return preferences.getBoolean(DISPLAY_TRANSLATED_NAMES, false); } @@ -336,12 +333,12 @@ public final class UserPreferences { public static void setIndexingServerPort(int port) { preferences.putInt(INDEXING_SERVER_PORT, port); } - - public static void setTextTranslatorName(String textTranslatorName){ + + public static void setTextTranslatorName(String textTranslatorName) { preferences.put(TEXT_TRANSLATOR_NAME, textTranslatorName); } - - public static String getTextTranslatorName(){ + + public static String getTextTranslatorName() { return preferences.get(TEXT_TRANSLATOR_NAME, null); } @@ -482,7 +479,7 @@ public final class UserPreferences { public static void setLogFileCount(int count) { preferences.putInt(MAX_NUM_OF_LOG_FILE, count); } - + /** * Get the maximum JVM heap size (in MB) for the embedded Solr server. * @@ -521,17 +518,17 @@ public final class UserPreferences { /** * Set the HdX path. - * + * * @param executablePath User-inputted path to HxD executable */ public static void setExternalHexEditorPath(String executablePath) { preferences.put(EXTERNAL_HEX_EDITOR_PATH, executablePath); } - + /** * Retrieves the HdXEditor path set by the User. If not found, the default * will be the default install location of HxD. - * + * * @return Path to HdX */ public static String getExternalHexEditorPath() { diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index fae74a30ac..98fb254131 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -153,10 +153,7 @@ ViewPreferencesPanel.currentSessionSettingsPanel.border.title=Current Session Se ViewPreferencesPanel.hideRejectedResultsCheckbox.text=Hide rejected results ViewPreferencesPanel.selectFileLabel.text=When selecting a file: ViewPreferencesPanel.globalSettingsPanel.border.title=Global Settings -ViewPreferencesPanel.commentsOccurencesColumnWrapAroundText.text=to reduce loading times ViewPreferencesPanel.translateTextLabel.text=Translate text: -ViewPreferencesPanel.commentsOccurencesColumnsCheckbox.text=C(omments) and O(ccurences) columns -ViewPreferencesPanel.centralRepoLabel.text=Do not use Central Repository for: ViewPreferencesPanel.hideOtherUsersTagsLabel.text=Hide other users' tags in the: ViewPreferencesPanel.hideOtherUsersTagsCheckbox.text=Tags area in the tree ViewPreferencesPanel.useAnotherTimeRadioButton.text=Use another time zone @@ -218,3 +215,6 @@ DataResultViewerTable.pageLabel.text=Page: ViewPreferencesPanel.maxResultsLabel.text=Maximum number of Results to show in table: ViewPreferencesPanel.maxResultsLabel.toolTipText=\nSetting this value to 0 will display all results in the results table.\n
Note that setting this value to 0 may result in poor UI responsiveness when there are large numbers of results.\n DataResultViewerTable.exportCSVButton.text=Save table as CSV +ViewPreferencesPanel.scoColumnsCheckbox.text=S(core), C(omments), and O(ccurrences) +ViewPreferencesPanel.scoColumnsWrapAroundText.text=to reduce loading times +ViewPreferencesPanel.scoColumnsLabel.text=Do not add columns for: diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED index b0e36da986..d60a979fe3 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED @@ -207,10 +207,7 @@ ViewPreferencesPanel.currentSessionSettingsPanel.border.title=Current Session Se ViewPreferencesPanel.hideRejectedResultsCheckbox.text=Hide rejected results ViewPreferencesPanel.selectFileLabel.text=When selecting a file: ViewPreferencesPanel.globalSettingsPanel.border.title=Global Settings -ViewPreferencesPanel.commentsOccurencesColumnWrapAroundText.text=to reduce loading times ViewPreferencesPanel.translateTextLabel.text=Translate text: -ViewPreferencesPanel.commentsOccurencesColumnsCheckbox.text=C(omments) and O(ccurences) columns -ViewPreferencesPanel.centralRepoLabel.text=Do not use Central Repository for: ViewPreferencesPanel.hideOtherUsersTagsLabel.text=Hide other users' tags in the: ViewPreferencesPanel.hideOtherUsersTagsCheckbox.text=Tags area in the tree ViewPreferencesPanel.useAnotherTimeRadioButton.text=Use another time zone @@ -272,3 +269,6 @@ DataResultViewerTable.pageLabel.text=Page: ViewPreferencesPanel.maxResultsLabel.text=Maximum number of Results to show in table: ViewPreferencesPanel.maxResultsLabel.toolTipText=\nSetting this value to 0 will display all results in the results table.\n
Note that setting this value to 0 may result in poor UI responsiveness when there are large numbers of results.\n DataResultViewerTable.exportCSVButton.text=Save table as CSV +ViewPreferencesPanel.scoColumnsCheckbox.text=S(core), C(omments), and O(ccurrences) +ViewPreferencesPanel.scoColumnsWrapAroundText.text=to reduce loading times +ViewPreferencesPanel.scoColumnsLabel.text=Do not add columns for: diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.form b/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.form index 1e3c9cbf5e..f604a6257e 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.form @@ -100,7 +100,7 @@ - + @@ -129,11 +129,11 @@ - + - + @@ -185,11 +185,11 @@ - + - + - + @@ -353,22 +353,22 @@
- + - + - + - + - + @@ -400,10 +400,10 @@
- + - + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.java index 3bc034467b..93aadeed65 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.java @@ -80,9 +80,7 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { dataSourcesHideSlackCheckbox.setSelected(UserPreferences.hideSlackFilesInDataSourcesTree()); viewsHideSlackCheckbox.setSelected(UserPreferences.hideSlackFilesInViewsTree()); - commentsOccurencesColumnsCheckbox.setEnabled(EamDb.isEnabled()); - commentsOccurencesColumnWrapAroundText.setEnabled(EamDb.isEnabled()); - commentsOccurencesColumnsCheckbox.setSelected(UserPreferences.hideCentralRepoCommentsAndOccurrences()); + scoColumnsCheckbox.setSelected(UserPreferences.getHideSCOColumns()); hideOtherUsersTagsCheckbox.setSelected(UserPreferences.showOnlyCurrentUserTags()); fileNameTranslationColumnCheckbox.setSelected(UserPreferences.displayTranslatedFileNames()); @@ -119,7 +117,7 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { UserPreferences.setHideSlackFilesInDataSourcesTree(dataSourcesHideSlackCheckbox.isSelected()); UserPreferences.setHideSlackFilesInViewsTree(viewsHideSlackCheckbox.isSelected()); UserPreferences.setShowOnlyCurrentUserTags(hideOtherUsersTagsCheckbox.isSelected()); - UserPreferences.setHideCentralRepoCommentsAndOccurrences(commentsOccurencesColumnsCheckbox.isSelected()); + UserPreferences.setHideSCOColumns(scoColumnsCheckbox.isSelected()); UserPreferences.setDisplayTranslatedFileNames(fileNameTranslationColumnCheckbox.isSelected()); UserPreferences.setResultsTablePageSize((int)maxResultsSpinner.getValue()); @@ -168,12 +166,12 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { useAnotherTimeRadioButton = new javax.swing.JRadioButton(); hideOtherUsersTagsCheckbox = new javax.swing.JCheckBox(); hideOtherUsersTagsLabel = new javax.swing.JLabel(); - centralRepoLabel = new javax.swing.JLabel(); - commentsOccurencesColumnsCheckbox = new javax.swing.JCheckBox(); + scoColumnsLabel = new javax.swing.JLabel(); + scoColumnsCheckbox = new javax.swing.JCheckBox(); jScrollPane1 = new javax.swing.JScrollPane(); timeZoneList = new javax.swing.JList<>(); translateTextLabel = new javax.swing.JLabel(); - commentsOccurencesColumnWrapAroundText = new javax.swing.JLabel(); + scoColumnsWrapAroundText = new javax.swing.JLabel(); fileNameTranslationColumnCheckbox = new javax.swing.JCheckBox(); maxResultsLabel = new javax.swing.JLabel(); maxResultsSpinner = new javax.swing.JSpinner(); @@ -266,13 +264,13 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { org.openide.awt.Mnemonics.setLocalizedText(hideOtherUsersTagsLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.hideOtherUsersTagsLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(centralRepoLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.centralRepoLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(scoColumnsLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.scoColumnsLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(commentsOccurencesColumnsCheckbox, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.commentsOccurencesColumnsCheckbox.text")); // NOI18N - commentsOccurencesColumnsCheckbox.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); - commentsOccurencesColumnsCheckbox.addActionListener(new java.awt.event.ActionListener() { + org.openide.awt.Mnemonics.setLocalizedText(scoColumnsCheckbox, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.scoColumnsCheckbox.text")); // NOI18N + scoColumnsCheckbox.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + scoColumnsCheckbox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - commentsOccurencesColumnsCheckboxActionPerformed(evt); + scoColumnsCheckboxActionPerformed(evt); } }); @@ -285,7 +283,7 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { org.openide.awt.Mnemonics.setLocalizedText(translateTextLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.translateTextLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(commentsOccurencesColumnWrapAroundText, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.commentsOccurencesColumnWrapAroundText.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(scoColumnsWrapAroundText, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.scoColumnsWrapAroundText.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(fileNameTranslationColumnCheckbox, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.fileNameTranslationColumnCheckbox.text")); // NOI18N fileNameTranslationColumnCheckbox.addActionListener(new java.awt.event.ActionListener() { @@ -315,7 +313,7 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { .addGap(10, 10, 10) .addComponent(hideOtherUsersTagsCheckbox)) .addGroup(globalSettingsPanelLayout.createSequentialGroup() - .addComponent(centralRepoLabel) + .addComponent(scoColumnsLabel) .addGap(135, 135, 135) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 272, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(hideOtherUsersTagsLabel) @@ -337,10 +335,10 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { .addComponent(viewsHideKnownCheckbox)))) .addGroup(globalSettingsPanelLayout.createSequentialGroup() .addGap(10, 10, 10) - .addComponent(commentsOccurencesColumnsCheckbox)) + .addComponent(scoColumnsCheckbox)) .addGroup(globalSettingsPanelLayout.createSequentialGroup() .addGap(32, 32, 32) - .addComponent(commentsOccurencesColumnWrapAroundText))) + .addComponent(scoColumnsWrapAroundText))) .addGap(18, 18, 18) .addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(displayTimeLabel) @@ -382,11 +380,11 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(hideOtherUsersTagsCheckbox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(centralRepoLabel) + .addComponent(scoColumnsLabel) .addGap(3, 3, 3) - .addComponent(commentsOccurencesColumnsCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(scoColumnsCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(commentsOccurencesColumnWrapAroundText)) + .addComponent(scoColumnsWrapAroundText)) .addGroup(globalSettingsPanelLayout.createSequentialGroup() .addComponent(selectFileLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -523,13 +521,13 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { } }//GEN-LAST:event_timeZoneListValueChanged - private void commentsOccurencesColumnsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_commentsOccurencesColumnsCheckboxActionPerformed + private void scoColumnsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scoColumnsCheckboxActionPerformed if (immediateUpdates) { - UserPreferences.setHideCentralRepoCommentsAndOccurrences(commentsOccurencesColumnsCheckbox.isSelected()); + UserPreferences.setHideSCOColumns(scoColumnsCheckbox.isSelected()); } else { firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); } - }//GEN-LAST:event_commentsOccurencesColumnsCheckboxActionPerformed + }//GEN-LAST:event_scoColumnsCheckboxActionPerformed private void hideOtherUsersTagsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hideOtherUsersTagsCheckboxActionPerformed if (immediateUpdates) { @@ -631,9 +629,6 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel centralRepoLabel; - private javax.swing.JLabel commentsOccurencesColumnWrapAroundText; - private javax.swing.JCheckBox commentsOccurencesColumnsCheckbox; private javax.swing.JPanel currentCaseSettingsPanel; private javax.swing.JPanel currentSessionSettingsPanel; private javax.swing.JCheckBox dataSourcesHideKnownCheckbox; @@ -651,6 +646,9 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { private javax.swing.JRadioButton keepCurrentViewerRadioButton; private javax.swing.JLabel maxResultsLabel; private javax.swing.JSpinner maxResultsSpinner; + private javax.swing.JCheckBox scoColumnsCheckbox; + private javax.swing.JLabel scoColumnsLabel; + private javax.swing.JLabel scoColumnsWrapAroundText; private javax.swing.JLabel selectFileLabel; private javax.swing.JList timeZoneList; private javax.swing.JLabel translateTextLabel; diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index 97922760c5..c2ed64987e 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -22,7 +22,6 @@ package org.sleuthkit.autopsy.coreutils; import com.google.common.collect.ImmutableSortedSet; -import com.google.common.io.Files; import java.awt.Image; import java.awt.image.BufferedImage; import java.io.BufferedInputStream; @@ -122,7 +121,7 @@ public class ImageUtils { } DEFAULT_THUMBNAIL = tempImage; boolean tempFfmpegLoaded = false; - if (OpenCvLoader.isOpenCvLoaded()) { + if (OpenCvLoader.hasOpenCvLoaded()) { try { if (System.getProperty("os.arch").equals("amd64") || System.getProperty("os.arch").equals("x86_64")) { //NON-NLS System.loadLibrary("opencv_ffmpeg248_64"); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java index 9c49f867c4..eeacf491bf 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java @@ -199,7 +199,7 @@ public abstract class AbstractAbstractFileNode extends A //Set the tooltip this.setShortDescription(content.getName()); updateSheet(new NodeProperty<>(ORIGINAL_NAME.toString(), ORIGINAL_NAME.toString(), NO_DESCR, content.getName())); - } else if (eventType.equals(NodeSpecificEvents.SCO_AVAILABLE.toString())) { + } else if (eventType.equals(NodeSpecificEvents.SCO_AVAILABLE.toString()) && !UserPreferences.getHideSCOColumns()) { SCOData scoData = (SCOData) evt.getNewValue(); if (scoData.getScoreAndDescription() != null) { updateSheet(new NodeProperty<>(SCORE.toString(), SCORE.toString(), scoData.getScoreAndDescription().getRight(), scoData.getScoreAndDescription().getLeft())); @@ -207,8 +207,7 @@ public abstract class AbstractAbstractFileNode extends A if (scoData.getComment() != null) { updateSheet(new NodeProperty<>(COMMENT.toString(), COMMENT.toString(), NO_DESCR, scoData.getComment())); } - if (scoData.getCountAndDescription() != null - && !UserPreferences.hideCentralRepoCommentsAndOccurrences()) { + if (scoData.getCountAndDescription() != null) { updateSheet(new NodeProperty<>(OCCURRENCES.toString(), OCCURRENCES.toString(), scoData.getCountAndDescription().getRight(), scoData.getCountAndDescription().getLeft())); } } @@ -325,10 +324,12 @@ public abstract class AbstractAbstractFileNode extends A } // Create place holders for S C O - properties.add(new NodeProperty<>(SCORE.toString(), SCORE.toString(), VALUE_LOADING, "")); - properties.add(new NodeProperty<>(COMMENT.toString(), COMMENT.toString(), VALUE_LOADING, "")); - if (EamDb.isEnabled() && UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) { - properties.add(new NodeProperty<>(OCCURRENCES.toString(), OCCURRENCES.toString(), VALUE_LOADING, "")); + if (!UserPreferences.getHideSCOColumns()) { + properties.add(new NodeProperty<>(SCORE.toString(), SCORE.toString(), VALUE_LOADING, "")); + properties.add(new NodeProperty<>(COMMENT.toString(), COMMENT.toString(), VALUE_LOADING, "")); + if (EamDb.isEnabled()) { + properties.add(new NodeProperty<>(OCCURRENCES.toString(), OCCURRENCES.toString(), VALUE_LOADING, "")); + } } // Get the SCO columns data in a background task @@ -393,10 +394,11 @@ public abstract class AbstractAbstractFileNode extends A @NbBundle.Messages({ "AbstractAbstractFileNode.createSheet.count.displayName=O", "AbstractAbstractFileNode.createSheet.count.hashLookupNotRun.description=Hash lookup had not been run on this file when the column was populated", - "# {0} - occurenceCount", - "AbstractAbstractFileNode.createSheet.count.description=There were {0} datasource(s) found with occurences of the MD5 correlation value"}) + "# {0} - occurrenceCount", + "AbstractAbstractFileNode.createSheet.count.description=There were {0} datasource(s) found with occurrences of the MD5 correlation value"}) @Override - protected Pair getCountPropertyAndDescription(CorrelationAttributeInstance.Type attributeType, String attributeValue, String defaultDescription) { + protected Pair getCountPropertyAndDescription(CorrelationAttributeInstance.Type attributeType, String attributeValue, + String defaultDescription) { Long count = -1L; //The column renderer will not display negative values, negative value used when count unavailble to preserve sorting String description = defaultDescription; try { @@ -535,7 +537,7 @@ public abstract class AbstractAbstractFileNode extends A @Override protected CorrelationAttributeInstance getCorrelationAttributeInstance() { CorrelationAttributeInstance attribute = null; - if (EamDb.isEnabled() && !UserPreferences.hideCentralRepoCommentsAndOccurrences()) { + if (EamDb.isEnabled() && !UserPreferences.getHideSCOColumns()) { attribute = EamArtifactUtil.getInstanceFromContent(content); } return attribute; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index cfd5d47108..0ea8b04660 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -152,7 +152,7 @@ public class BlackboardArtifactNode extends AbstractContentNode(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), scoData.getScoreAndDescription().getRight(), scoData.getScoreAndDescription().getLeft())); @@ -160,8 +160,7 @@ public class BlackboardArtifactNode extends AbstractContentNode(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), NO_DESCR, scoData.getComment())); } - if (scoData.getCountAndDescription() != null - && !UserPreferences.hideCentralRepoCommentsAndOccurrences()) { + if (scoData.getCountAndDescription() != null) { updateSheet(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), scoData.getCountAndDescription().getRight(), scoData.getCountAndDescription().getLeft())); } } @@ -364,10 +363,12 @@ public class BlackboardArtifactNode extends AbstractContentNode(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), VALUE_LOADING, "")); - sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), VALUE_LOADING, "")); - if (EamDb.isEnabled() && UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) { - sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), VALUE_LOADING, "")); + if (!UserPreferences.getHideSCOColumns()) { + sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), VALUE_LOADING, "")); + sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), VALUE_LOADING, "")); + if (EamDb.isEnabled()) { + sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), VALUE_LOADING, "")); + } } // Get the SCO columns data in a background task @@ -747,7 +748,7 @@ public class BlackboardArtifactNode extends AbstractContentNode - + - + @@ -78,6 +78,9 @@ + + + diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportWizardPortableCaseOptionsVisualPanel.java b/Core/src/org/sleuthkit/autopsy/report/ReportWizardPortableCaseOptionsVisualPanel.java index 789478b2ec..f721f26bf9 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportWizardPortableCaseOptionsVisualPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportWizardPortableCaseOptionsVisualPanel.java @@ -119,6 +119,7 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel { }); org.openide.awt.Mnemonics.setLocalizedText(compressCheckbox, org.openide.util.NbBundle.getMessage(ReportWizardPortableCaseOptionsVisualPanel.class, "ReportWizardPortableCaseOptionsVisualPanel.compressCheckbox.text")); // NOI18N + compressCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(ReportWizardPortableCaseOptionsVisualPanel.class, "ReportWizardPortableCaseOptionsVisualPanel.compressCheckbox.toolTipText")); // NOI18N compressCheckbox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { compressCheckboxActionPerformed(evt); @@ -147,10 +148,10 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel { .addContainerGap() .addComponent(compressCheckbox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(chunkSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 99, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(chunkSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 187, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(errorLabel) - .addContainerGap(97, Short.MAX_VALUE)) + .addContainerGap(41, Short.MAX_VALUE)) .addComponent(listPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); jPanel1Layout.setVerticalGroup( diff --git a/CoreLibs/src/org/sleuthkit/autopsy/corelibs/OpenCvLoader.java b/CoreLibs/src/org/sleuthkit/autopsy/corelibs/OpenCvLoader.java index 0027203cd7..3e61fac4a1 100644 --- a/CoreLibs/src/org/sleuthkit/autopsy/corelibs/OpenCvLoader.java +++ b/CoreLibs/src/org/sleuthkit/autopsy/corelibs/OpenCvLoader.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2018 Basis Technology Corp. + * Copyright 2018-2019 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,36 +18,45 @@ */ package org.sleuthkit.autopsy.corelibs; +import java.util.logging.Level; +import java.util.logging.Logger; import org.opencv.core.Core; public final class OpenCvLoader { - private static final boolean OPEN_CV_LOADED; + private static final Logger LOGGER = Logger.getLogger(OpenCvLoader.class.getName()); + private static boolean openCvLoaded; private static UnsatisfiedLinkError exception = null; static { - boolean tempOpenCvLoaded = false; try { System.loadLibrary(Core.NATIVE_LIBRARY_NAME); - tempOpenCvLoaded = true; - } catch (UnsatisfiedLinkError e) { - tempOpenCvLoaded = false; - exception = e; //save relevant error for throwing at appropriate time + openCvLoaded = true; + } catch (UnsatisfiedLinkError ex) { + LOGGER.log(Level.WARNING, "Unable to load OpenCV", ex); + exception = ex; //save relevant error for throwing at appropriate time + openCvLoaded = false; + } catch (SecurityException ex) { + LOGGER.log(Level.WARNING, "Unable to load OpenCV", ex); + openCvLoaded = false; } - OPEN_CV_LOADED = tempOpenCvLoaded; + } /** * Return whether or not the OpenCV library has been loaded. * * @return - true if the opencv library is loaded or false if it is not - * @throws UnsatisfiedLinkError - A COPY of the exception that prevented OpenCV from loading. - * Note that the stack trace in the exception can be confusing because it refers to a - * past invocation. + * @throws UnsatisfiedLinkError - A COPY of the exception that prevented + * OpenCV from loading. Note that the stack trace in the exception can be + * confusing because it refers to a past invocation. + * + * @deprecated Use hasOpenCvLoaded instead. */ + @Deprecated public static boolean isOpenCvLoaded() throws UnsatisfiedLinkError { - if (!OPEN_CV_LOADED) { - //exception should never be null if the open cv isn't loaded but just in case + if (!openCvLoaded) { + //exception should never be null if the open cv isn't loaded but just in case if (exception != null) { throw exception; } else { @@ -55,6 +64,15 @@ public final class OpenCvLoader { } } - return OPEN_CV_LOADED; + return openCvLoaded; + } + + /** + * Return whether OpenCV library has been loaded. + * + * @return true if OpenCV library was loaded, false if not. + */ + public static boolean hasOpenCvLoaded() { + return openCvLoaded; } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties-MERGED b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties-MERGED index 91e2bebd08..82f3439279 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties-MERGED +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties-MERGED @@ -52,8 +52,8 @@ AutoIngestSettingsPanel.lbTestMultiUserText.text=Test Multi-User Case Creation a AutoIngestSettingsPanel.lbMultiUserResult.text= AutoIngestSettingsPanel.lbTestResultText.text= AutoIngestSettingsPanel.validationErrMsg.outputPathNotSpecified=Output folder must be set -AutoIngestSettingsPanel.PathInvalid=Case output directory path is not valid -AutoIngestSettingsPanel.CheckPermissions=Ensure that the user account {0} has write permissions in this folder +AutoIngestSettingsPanel.PathInvalid=Path is not valid +AutoIngestSettingsPanel.CheckPermissions=Check permissions. AutoIngestSettingsPanel.Success=Success AutoIngestSettingsPanel.TestRunning=Test in progress... AutoIngestSettingsPanel.servicesDown=Some of the Multi User services are down diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/Bundle.properties-MERGED b/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/Bundle.properties-MERGED index 4256a2a349..9b2baa6467 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/Bundle.properties-MERGED +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/Bundle.properties-MERGED @@ -3,5 +3,7 @@ ObjectDetectionFileIngestModule.classifierDetection.text=Classifier detected {0} # {0} - classifierDir ObjectDetectionFileIngestModule.noClassifiersFound.message=No classifiers were found in {0}, object detection will not be executed. ObjectDetectionFileIngestModule.noClassifiersFound.subject=No classifiers found. +ObjectDetectionFileIngestModule.notWindowsError=This module is only available on Windows. +ObjectDetectionFileIngestModule.openCVNotLoaded=OpenCV was not loaded, but is required to run. ObjectDetectionModuleFactory.moduleDescription.text=Use object classifiers to identify objects in pictures. ObjectDetectionModuleFactory.moduleName.text=Object Detection diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java b/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java index 003a35a46d..e5d342aef8 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java @@ -65,14 +65,32 @@ public class ObjectDetectectionFileIngestModule extends FileIngestModuleAdapter private Blackboard blackboard; @Messages({"ObjectDetectionFileIngestModule.noClassifiersFound.subject=No classifiers found.", - "# {0} - classifierDir", "ObjectDetectionFileIngestModule.noClassifiersFound.message=No classifiers were found in {0}, object detection will not be executed."}) + "# {0} - classifierDir", "ObjectDetectionFileIngestModule.noClassifiersFound.message=No classifiers were found in {0}, object detection will not be executed.", + "ObjectDetectionFileIngestModule.openCVNotLoaded=OpenCV was not loaded, but is required to run.", + "ObjectDetectionFileIngestModule.notWindowsError=This module is only available on Windows." + }) @Override public void startUp(IngestJobContext context) throws IngestModule.IngestModuleException { jobId = context.getJobId(); File classifierDir = new File(PlatformUtil.getObjectDetectionClassifierPath()); classifiers = new HashMap<>(); + + if(!PlatformUtil.isWindowsOS()) { + //Pop-up that catches IngestModuleException will automatically indicate + //the name of the module before the message. + String errorMsg = Bundle.ObjectDetectionFileIngestModule_notWindowsError(); + logger.log(Level.SEVERE, errorMsg); + throw new IngestModule.IngestModuleException(errorMsg); + } + + if(!OpenCvLoader.hasOpenCvLoaded()) { + String errorMsg = Bundle.ObjectDetectionFileIngestModule_openCVNotLoaded(); + logger.log(Level.SEVERE, errorMsg); + throw new IngestModule.IngestModuleException(errorMsg); + } + //Load all classifiers found in PlatformUtil.getObjectDetectionClassifierPath() - if (OpenCvLoader.isOpenCvLoaded() && classifierDir.exists() && classifierDir.isDirectory()) { + if (classifierDir.exists() && classifierDir.isDirectory()) { for (File classifier : classifierDir.listFiles()) { if (classifier.isFile() && FilenameUtils.getExtension(classifier.getName()).equalsIgnoreCase("xml")) { classifiers.put(classifier.getName(), new CascadeClassifier(classifier.getAbsolutePath())); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableAttribute.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableAttribute.java index 8c42e851a9..8e20ebba6e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableAttribute.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableAttribute.java @@ -24,6 +24,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.function.Function; +import java.util.logging.Level; import java.util.stream.Collectors; import javafx.beans.property.ReadOnlyStringWrapper; import javafx.beans.property.StringProperty; @@ -32,6 +33,7 @@ import javafx.scene.image.Image; import javafx.scene.image.ImageView; import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.datamodel.TagName; @@ -59,20 +61,22 @@ import org.sleuthkit.datamodel.TagName; "DrawableAttribute.mimeType=MIME type"}) public class DrawableAttribute> { - public final static DrawableAttribute MD5_HASH = - new DrawableAttribute<>(AttributeName.MD5_HASH, Bundle.DrawableAttribute_md5hash(), + private static final Logger logger = Logger.getLogger(DrawableAttribute.class.getName()); + + public final static DrawableAttribute MD5_HASH + = new DrawableAttribute<>(AttributeName.MD5_HASH, Bundle.DrawableAttribute_md5hash(), false, "icon-hashtag.png", // NON-NLS f -> Collections.singleton(f.getMd5Hash())); - public final static DrawableAttribute NAME = - new DrawableAttribute<>(AttributeName.NAME, Bundle.DrawableAttribute_name(), + public final static DrawableAttribute NAME + = new DrawableAttribute<>(AttributeName.NAME, Bundle.DrawableAttribute_name(), true, "folder-rename.png", //NON-NLS f -> Collections.singleton(f.getName())); - public final static DrawableAttribute ANALYZED = - new DrawableAttribute<>(AttributeName.ANALYZED, Bundle.DrawableAttribute_analyzed(), + public final static DrawableAttribute ANALYZED + = new DrawableAttribute<>(AttributeName.ANALYZED, Bundle.DrawableAttribute_analyzed(), true, "", f -> Collections.singleton(f.isAnalyzed())); @@ -85,89 +89,89 @@ public class DrawableAttribute> { * //TODO: this has lead to awkward hard to maintain code, and little * advantage. move categories into DrawableDB? */ - public final static DrawableAttribute CATEGORY = - new DrawableAttribute(AttributeName.CATEGORY, Bundle.DrawableAttribute_category(), + public final static DrawableAttribute CATEGORY + = new DrawableAttribute(AttributeName.CATEGORY, Bundle.DrawableAttribute_category(), false, "category-icon.png", //NON-NLS f -> Collections.singleton(f.getCategory())) { - @Override - public Node getGraphicForValue(DhsImageCategory val) { - return val.getGraphic(); - } - }; + @Override + public Node getGraphicForValue(DhsImageCategory val) { + return val.getGraphic(); + } + }; - public final static DrawableAttribute TAGS = - new DrawableAttribute<>(AttributeName.TAGS, Bundle.DrawableAttribute_tags(), + public final static DrawableAttribute TAGS + = new DrawableAttribute<>(AttributeName.TAGS, Bundle.DrawableAttribute_tags(), false, "tag_red.png", //NON-NLS DrawableFile::getTagNames); - public final static DrawableAttribute PATH = - new DrawableAttribute<>(AttributeName.PATH, Bundle.DrawableAttribute_path(), + public final static DrawableAttribute PATH + = new DrawableAttribute<>(AttributeName.PATH, Bundle.DrawableAttribute_path(), true, "folder_picture.png", //NON-NLS f -> Collections.singleton(f.getDrawablePath())); - public final static DrawableAttribute CREATED_TIME = - new DrawableAttribute<>(AttributeName.CREATED_TIME, Bundle.DrawableAttribute_createdTime(), + public final static DrawableAttribute CREATED_TIME + = new DrawableAttribute<>(AttributeName.CREATED_TIME, Bundle.DrawableAttribute_createdTime(), true, "clock--plus.png", //NON-NLS f -> Collections.singleton(ContentUtils.getStringTime(f.getCrtime(), f.getAbstractFile()))); - public final static DrawableAttribute MODIFIED_TIME = - new DrawableAttribute<>(AttributeName.MODIFIED_TIME, Bundle.DrawableAttribute_modifiedTime(), + public final static DrawableAttribute MODIFIED_TIME + = new DrawableAttribute<>(AttributeName.MODIFIED_TIME, Bundle.DrawableAttribute_modifiedTime(), true, "clock--pencil.png", //NON-NLS f -> Collections.singleton(ContentUtils.getStringTime(f.getMtime(), f.getAbstractFile()))); - public final static DrawableAttribute MAKE = - new DrawableAttribute<>(AttributeName.MAKE, Bundle.DrawableAttribute_cameraMake(), + public final static DrawableAttribute MAKE + = new DrawableAttribute<>(AttributeName.MAKE, Bundle.DrawableAttribute_cameraMake(), true, "camera.png", //NON-NLS f -> Collections.singleton(f.getMake())); - public final static DrawableAttribute MODEL = - new DrawableAttribute<>(AttributeName.MODEL, Bundle.DrawableAttribute_cameraModel(), + public final static DrawableAttribute MODEL + = new DrawableAttribute<>(AttributeName.MODEL, Bundle.DrawableAttribute_cameraModel(), true, "camera.png", //NON-NLS f -> Collections.singleton(f.getModel())); - public final static DrawableAttribute HASHSET = - new DrawableAttribute<>(AttributeName.HASHSET, Bundle.DrawableAttribute_hashSet(), + public final static DrawableAttribute HASHSET + = new DrawableAttribute<>(AttributeName.HASHSET, Bundle.DrawableAttribute_hashSet(), true, "hashset_hits.png", //NON-NLS DrawableFile::getHashSetNamesUnchecked); - public final static DrawableAttribute OBJ_ID = - new DrawableAttribute<>(AttributeName.OBJ_ID, Bundle.DrawableAttribute_intObjID(), + public final static DrawableAttribute OBJ_ID + = new DrawableAttribute<>(AttributeName.OBJ_ID, Bundle.DrawableAttribute_intObjID(), true, "", f -> Collections.singleton(f.getId())); - public final static DrawableAttribute WIDTH = - new DrawableAttribute<>(AttributeName.WIDTH, Bundle.DrawableAttribute_width(), + public final static DrawableAttribute WIDTH + = new DrawableAttribute<>(AttributeName.WIDTH, Bundle.DrawableAttribute_width(), false, "arrow-resize.png", //NON-NLS f -> Collections.singleton(f.getWidth())); - public final static DrawableAttribute HEIGHT = - new DrawableAttribute<>(AttributeName.HEIGHT, Bundle.DrawableAttribute_height(), + public final static DrawableAttribute HEIGHT + = new DrawableAttribute<>(AttributeName.HEIGHT, Bundle.DrawableAttribute_height(), false, "arrow-resize-090.png", //NON-NLS f -> Collections.singleton(f.getHeight())); - public final static DrawableAttribute MIME_TYPE = - new DrawableAttribute<>(AttributeName.MIME_TYPE, Bundle.DrawableAttribute_mimeType(), + public final static DrawableAttribute MIME_TYPE + = new DrawableAttribute<>(AttributeName.MIME_TYPE, Bundle.DrawableAttribute_mimeType(), false, "mime_types.png", //NON-NLS f -> Collections.singleton(f.getMIMEType())); - final private static List< DrawableAttribute> groupables = - Arrays.asList(PATH, HASHSET, CATEGORY, TAGS, MAKE, MODEL, MIME_TYPE); + final private static List< DrawableAttribute> groupables + = Arrays.asList(PATH, HASHSET, CATEGORY, TAGS, MAKE, MODEL, MIME_TYPE); - final private static List> values = - Arrays.asList(NAME, ANALYZED, CATEGORY, TAGS, PATH, CREATED_TIME, + final private static List> values + = Arrays.asList(NAME, ANALYZED, CATEGORY, TAGS, PATH, CREATED_TIME, MODIFIED_TIME, MD5_HASH, HASHSET, MAKE, MODEL, OBJ_ID, WIDTH, HEIGHT, MIME_TYPE); private final Function> extractor; @@ -226,9 +230,17 @@ public class DrawableAttribute> { } public Collection getValue(DrawableFile f) { - return extractor.apply(f).stream() - .filter(value -> (value != null && value.toString().isEmpty()== false) ) - .collect(Collectors.toSet()); + try { + return extractor.apply(f).stream() + .filter(value -> (value != null && value.toString().isEmpty() == false)) + .collect(Collectors.toSet()); + } catch (Exception ex) { + /* There is a catch-all here because the code in the try block executes third-party + library calls that throw unchecked exceptions. See JIRA-5144, where an IllegalStateException + was thrown because a file's MIME type was incorrectly identified as a picture type. */ + logger.log(Level.WARNING, "Exception while getting image attributes", ex); //NON-NLS + return Collections.EMPTY_SET; + } } public static enum AttributeName {