diff --git a/Core/build.xml b/Core/build.xml
index 5d91ade7e1..df747ff257 100644
--- a/Core/build.xml
+++ b/Core/build.xml
@@ -72,6 +72,9 @@
+
+
+
diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties
index 22af0f87c8..9db5951f69 100644
--- a/Core/nbproject/project.properties
+++ b/Core/nbproject/project.properties
@@ -2,8 +2,15 @@ file.reference.activemq-all-5.11.1.jar=release/modules/ext/activemq-all-5.11.1.j
file.reference.apache-mime4j-core-0.8.2.jar=release\\modules\\ext\\apache-mime4j-core-0.8.2.jar
file.reference.apache-mime4j-dom-0.8.2.jar=release\\modules\\ext\\apache-mime4j-dom-0.8.2.jar
file.reference.asm-7.0.jar=release\\modules\\ext\\asm-7.0.jar
+file.reference.batik-awt-util-1.6.jar=release/modules/ext/batik-awt-util-1.6.jar
+file.reference.batik-dom-1.6.jar=release/modules/ext/batik-dom-1.6.jar
+file.reference.batik-svg-dom-1.6.jar=release/modules/ext/batik-svg-dom-1.6.jar
+file.reference.batik-svggen-1.6.jar=release/modules/ext/batik-svggen-1.6.jar
+file.reference.batik-util-1.6.jar=release/modules/ext/batik-util-1.6.jar
+file.reference.batik-xml-1.6.jar=release/modules/ext/batik-xml-1.6.jar
file.reference.bcmail-jdk15on-1.60.jar=release\\modules\\ext\\bcmail-jdk15on-1.60.jar
file.reference.bcpkix-jdk15on-1.60.jar=release\\modules\\ext\\bcpkix-jdk15on-1.60.jar
+file.reference.bcprov-ext-jdk15on-1.54.jar=release/modules/ext/bcprov-ext-jdk15on-1.54.jar
file.reference.bcprov-jdk15on-1.60.jar=release\\modules\\ext\\bcprov-jdk15on-1.60.jar
file.reference.boilerpipe-1.1.0.jar=release\\modules\\ext\\boilerpipe-1.1.0.jar
file.reference.c3p0-0.9.5.jar=release/modules/ext/c3p0-0.9.5.jar
@@ -17,14 +24,17 @@ file.reference.commons-io-2.6.jar=release\\modules\\ext\\commons-io-2.6.jar
file.reference.commons-lang3-3.8.1.jar=release\\modules\\ext\\commons-lang3-3.8.1.jar
file.reference.commons-pool2-2.4.2.jar=release/modules/ext/commons-pool2-2.4.2.jar
file.reference.cxf-rt-rs-client-3.3.0.jar=release\\modules\\ext\\cxf-rt-rs-client-3.3.0.jar
+file.reference.DatCon.jar=release/modules/ext/DatCon.jar
file.reference.dec-0.1.2.jar=release\\modules\\ext\\dec-0.1.2.jar
-file.reference.decodetect-core-0.3.jar=release\\modules\\ext\\decodetect-core-0.3.jar
+file.reference.decodetect-core-0.3.jar=release/modules/ext/decodetect-core-0.3.jar
file.reference.fontbox-2.0.13.jar=release\\modules\\ext\\fontbox-2.0.13.jar
file.reference.geoapi-3.0.1.jar=release\\modules\\ext\\geoapi-3.0.1.jar
file.reference.grib-4.5.5.jar=release\\modules\\ext\\grib-4.5.5.jar
file.reference.httpclient-4.5.6.jar=release\\modules\\ext\\httpclient-4.5.6.jar
file.reference.httpmime-4.5.6.jar=release\\modules\\ext\\httpmime-4.5.6.jar
file.reference.httpservices-4.5.5.jar=release\\modules\\ext\\httpservices-4.5.5.jar
+file.reference.icepdf-core-6.2.2.jar=release/modules/ext/icepdf-core-6.2.2.jar
+file.reference.icepdf-viewer-6.2.2.jar=release/modules/ext/icepdf-viewer-6.2.2.jar
file.reference.isoparser-1.1.22.jar=release\\modules\\ext\\isoparser-1.1.22.jar
file.reference.jackcess-2.2.0.jar=release\\modules\\ext\\jackcess-2.2.0.jar
file.reference.jackcess-encrypt-2.1.4.jar=release\\modules\\ext\\jackcess-encrypt-2.1.4.jar
@@ -32,6 +42,8 @@ file.reference.jackson-annotations-2.9.7.jar=release\\modules\\ext\\jackson-anno
file.reference.jackson-core-2.9.7.jar=release\\modules\\ext\\jackson-core-2.9.7.jar
file.reference.jackson-databind-2.9.7.jar=release\\modules\\ext\\jackson-databind-2.9.7.jar
file.reference.jai-imageio-core-1.4.0.jar=release\\modules\\ext\\jai-imageio-core-1.4.0.jar
+file.reference.jai_core-1.1.3.jar=release/modules/ext/jai_core-1.1.3.jar
+file.reference.jai_imageio-1.1.jar=release/modules/ext/jai_imageio-1.1.jar
file.reference.java-libpst-0.8.1.jar=release\\modules\\ext\\java-libpst-0.8.1.jar
file.reference.javax.activation-1.2.0.jar=release\\modules\\ext\\javax.activation-1.2.0.jar
file.reference.javax.annotation-api-1.3.2.jar=release\\modules\\ext\\javax.annotation-api-1.3.2.jar
@@ -50,7 +62,7 @@ file.reference.jsoup-1.11.3.jar=release\\modules\\ext\\jsoup-1.11.3.jar
file.reference.jul-to-slf4j-1.7.25.jar=release\\modules\\ext\\jul-to-slf4j-1.7.25.jar
file.reference.juniversalchardet-1.0.3.jar=release\\modules\\ext\\juniversalchardet-1.0.3.jar
file.reference.junrar-2.0.0.jar=release\\modules\\ext\\junrar-2.0.0.jar
-file.reference.jutf7-1.0.0.jar=release\\modules\\ext\\jutf7-1.0.0.jar
+file.reference.jutf7-1.0.0.jar=release/modules/ext/jutf7-1.0.0.jar
file.reference.jxmapviewer2-2.4.jar=release/modules/ext/jxmapviewer2-2.4.jar
file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone-2.7.0.jar
file.reference.libphonenumber-3.5.jar=release/modules/ext/libphonenumber-3.5.jar
diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml
index 79c518eeaa..bf917fc039 100644
--- a/Core/nbproject/project.xml
+++ b/Core/nbproject/project.xml
@@ -355,6 +355,14 @@
ext/commons-lang3-3.8.1.jar
release\modules\ext\commons-lang3-3.8.1.jar
+
+ ext/batik-xml-1.6.jar
+ release/modules/ext/batik-xml-1.6.jar
+
+
+ ext/jai_core-1.1.3.jar
+ release/modules/ext/jai_core-1.1.3.jar
+
ext/gax-grpc-1.44.0.jar
release/modules/ext/gax-grpc-1.44.0.jar
@@ -371,6 +379,10 @@
ext/opencensus-api-0.19.2.jar
release/modules/ext/opencensus-api-0.19.2.jar
+
+ ext/batik-svg-dom-1.6.jar
+ release/modules/ext/batik-svg-dom-1.6.jar
+
ext/gax-httpjson-0.61.0.jar
release/modules/ext/gax-httpjson-0.61.0.jar
@@ -479,6 +491,10 @@
ext/xmpcore-5.1.3.jar
release/modules/ext/xmpcore-5.1.3.jar
+
+ ext/batik-util-1.6.jar
+ release/modules/ext/batik-util-1.6.jar
+
ext/javax.activation-1.2.0.jar
release\modules\ext\javax.activation-1.2.0.jar
@@ -499,6 +515,10 @@
ext/jgraphx-4.1.0.jar
release/modules/ext/jgraphx-4.1.0.jar
+
+ ext/DatCon.jar
+ release/modules/ext/DatCon.jar
+
ext/java-libpst-0.8.1.jar
release\modules\ext\java-libpst-0.8.1.jar
@@ -535,10 +555,6 @@
ext/google-http-client-1.29.0.jar
release/modules/ext/google-http-client-1.29.0.jar
-
- ext/sleuthkit-postgresql-4.9.0.jar
- release/modules/ext/sleuthkit-postgresql-4.9.0.jar
-
ext/bcpkix-jdk15on-1.60.jar
release\modules\ext\bcpkix-jdk15on-1.60.jar
@@ -551,6 +567,10 @@
ext/slf4j-api-1.7.25.jar
release\modules\ext\slf4j-api-1.7.25.jar
+
+ ext/bcprov-ext-jdk15on-1.54.jar
+ release/modules/ext/bcprov-ext-jdk15on-1.54.jar
+
ext/google-cloud-core-1.70.0.jar
release/modules/ext/google-cloud-core-1.70.0.jar
@@ -619,6 +639,14 @@
ext/commons-validator-1.6.jar
release/modules/ext/commons-validator-1.6.jar
+
+ ext/sleuthkit-postgresql-4.9.0.jar
+ release/modules/ext/sleuthkit-postgresql-4.9.0.jar
+
+
+ ext/decodetect-core-0.3.jar
+ release/modules/ext/decodetect-core-0.3.jar
+
ext/jbig2-imageio-3.0.2.jar
release\modules\ext\jbig2-imageio-3.0.2.jar
@@ -667,6 +695,10 @@
ext/SparseBitSet-1.1.jar
release/modules/ext/SparseBitSet-1.1.jar
+
+ ext/batik-svggen-1.6.jar
+ release/modules/ext/batik-svggen-1.6.jar
+
ext/c3p0-0.9.5.jar
release/modules/ext/c3p0-0.9.5.jar
@@ -735,6 +767,10 @@
ext/postgresql-9.4.1211.jre7.jar
release/modules/ext/postgresql-9.4.1211.jre7.jar
+
+ ext/jai_imageio-1.1.jar
+ release/modules/ext/jai_imageio-1.1.jar
+
ext/httpclient-4.5.6.jar
release\modules\ext\httpclient-4.5.6.jar
@@ -747,6 +783,10 @@
ext/fontbox-2.0.13.jar
release\modules\ext\fontbox-2.0.13.jar
+
+ ext/icepdf-core-6.2.2.jar
+ release/modules/ext/icepdf-core-6.2.2.jar
+
ext/activemq-all-5.11.1.jar
release/modules/ext/activemq-all-5.11.1.jar
@@ -763,6 +803,10 @@
ext/dec-0.1.2.jar
release\modules\ext\dec-0.1.2.jar
+
+ ext/batik-dom-1.6.jar
+ release/modules/ext/batik-dom-1.6.jar
+
ext/google-http-client-jackson2-1.29.0.jar
release/modules/ext/google-http-client-jackson2-1.29.0.jar
@@ -779,6 +823,14 @@
ext/sevenzipjbinding-AllPlatforms.jar
release/modules/ext/sevenzipjbinding-AllPlatforms.jar
+
+ ext/jutf7-1.0.0.jar
+ release/modules/ext/jutf7-1.0.0.jar
+
+
+ ext/batik-awt-util-1.6.jar
+ release/modules/ext/batik-awt-util-1.6.jar
+
ext/google-api-services-translate-v2-rev20170525-1.27.0.jar
release/modules/ext/google-api-services-translate-v2-rev20170525-1.27.0.jar
@@ -787,6 +839,10 @@
ext/webp-imageio-sejda-0.1.0.jar
release/modules/ext/webp-imageio-sejda-0.1.0.jar
+
+ ext/icepdf-viewer-6.2.2.jar
+ release/modules/ext/icepdf-viewer-6.2.2.jar
+
ext/bcmail-jdk15on-1.60.jar
release\modules\ext\bcmail-jdk15on-1.60.jar
@@ -795,18 +851,6 @@
ext/vorbis-java-tika-0.8.jar
release\modules\ext\vorbis-java-tika-0.8.jar
-
- ext/decodetect-core-0.3.jar
- release/modules/ext/decodetect-core-0.3.jar
-
-
- ext/jutf7-1.0.0.jar
- release/modules/ext/jutf7-1.0.0.jar
-
-
- ext/DatCon.jar
- release/modules/ext/DatCon.jar
-
diff --git a/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceNode.java b/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceNode.java
index 25d7bf5519..8bf29e70ac 100644
--- a/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceNode.java
+++ b/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceNode.java
@@ -48,7 +48,8 @@ final class AccountDeviceInstanceNode extends AbstractNode {
this.account = accountDeviceInstanceKey.getAccountDeviceInstance().getAccount();
setName(account.getTypeSpecificID());
setDisplayName(getName());
- setIconBaseWithExtension(Utils.getIconFilePath(account.getAccountType()));
+ String iconPath = Utils.getIconFilePath(account.getAccountType());
+ this.setIconBaseWithExtension(iconPath != null && iconPath.charAt(0) == '/' ? iconPath.substring(1) : iconPath);
}
AccountDeviceInstance getAccountDeviceInstance() {
diff --git a/Core/src/org/sleuthkit/autopsy/communications/PinAccountsAction.java b/Core/src/org/sleuthkit/autopsy/communications/PinAccountsAction.java
index 52136d1b1a..34e6339b68 100644
--- a/Core/src/org/sleuthkit/autopsy/communications/PinAccountsAction.java
+++ b/Core/src/org/sleuthkit/autopsy/communications/PinAccountsAction.java
@@ -32,7 +32,7 @@ import org.openide.util.NbBundle;
final class PinAccountsAction extends AbstractCVTAction {
static private final ImageIcon ICON = ImageUtilities.loadImageIcon(
- "/org/sleuthkit/autopsy/communications/images/marker--plus.png", false);
+ "org/sleuthkit/autopsy/communications/images/marker--plus.png", false);
private static final String SINGULAR_TEXT = Bundle.PinAccountsAction_singularText();
private static final String PLURAL_TEXT = Bundle.PinAccountsAction_pluralText();
diff --git a/Core/src/org/sleuthkit/autopsy/communications/ResetAndPinAccountsAction.java b/Core/src/org/sleuthkit/autopsy/communications/ResetAndPinAccountsAction.java
index 385ac3348b..ee71508162 100644
--- a/Core/src/org/sleuthkit/autopsy/communications/ResetAndPinAccountsAction.java
+++ b/Core/src/org/sleuthkit/autopsy/communications/ResetAndPinAccountsAction.java
@@ -32,7 +32,7 @@ import org.openide.util.NbBundle;
final class ResetAndPinAccountsAction extends AbstractCVTAction {
private static final ImageIcon ICON = ImageUtilities.loadImageIcon(
- "/org/sleuthkit/autopsy/communications/images/marker--pin.png", false);
+ "org/sleuthkit/autopsy/communications/images/marker--pin.png", false);
private static final String SINGULAR_TEXT = Bundle.ResetAndPinAccountsAction_singularText();
private static final String PLURAL_TEXT = Bundle.ResetAndPinAccountsAction_pluralText();
diff --git a/Core/src/org/sleuthkit/autopsy/communications/UnpinAccountsAction.java b/Core/src/org/sleuthkit/autopsy/communications/UnpinAccountsAction.java
index 58ace503d9..0342d90310 100644
--- a/Core/src/org/sleuthkit/autopsy/communications/UnpinAccountsAction.java
+++ b/Core/src/org/sleuthkit/autopsy/communications/UnpinAccountsAction.java
@@ -32,7 +32,7 @@ import org.openide.util.NbBundle;
final class UnpinAccountsAction extends AbstractCVTAction {
static final private ImageIcon ICON = ImageUtilities.loadImageIcon(
- "/org/sleuthkit/autopsy/communications/images/marker--minus.png", false);
+ "org/sleuthkit/autopsy/communications/images/marker--minus.png", false);
private static final String SINGULAR_TEXT = Bundle.UnpinAccountsAction_singularText();
private static final String PLURAL_TEXT = Bundle.UnpinAccountsAction_pluralText();
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED
index c0a6f73aaf..0c33d92daf 100755
--- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED
+++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED
@@ -112,6 +112,8 @@ MessageContentViewer.attachmentsPanel.TabConstraints.tabTitle=Attachments
MessageContentViewer.viewInNewWindowButton.text=View in New Window
JPEGViewerDummy.jLabel1.text=You are looking at a JPEG file:
JPEGViewerDummy.jTextField1.text=jTextField1
+PDFViewer.encryptedDialog=This document is password protected.
+PDFViewer.errorDialog=An error occurred while opening this PDF document. Check the logs for more information. You may continue to use this feature on other PDF documents.
PListNode.KeyCol=Key
PListNode.TypeCol=Type
PListNode.ValueCol=Value
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java
index 1b0d048f35..0a50fb0ec9 100644
--- a/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java
+++ b/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java
@@ -50,7 +50,8 @@ public class FileViewer extends javax.swing.JPanel implements DataContentViewer
new PListViewer(),
new MediaFileViewer(),
new HtmlViewer(),
- new WindowsRegistryViewer()
+ new WindowsRegistryViewer(),
+ new PDFViewer()
};
private FileTypeViewer lastViewer;
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PDFViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PDFViewer.java
new file mode 100755
index 0000000000..52c6a93558
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PDFViewer.java
@@ -0,0 +1,192 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2020 Basis Technology Corp.
+ * Contact: carrier sleuthkit org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.sleuthkit.autopsy.contentviewers;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+import java.util.ResourceBundle;
+import java.util.concurrent.ExecutionException;
+import java.util.logging.Level;
+import javax.swing.JPanel;
+import javax.swing.SwingWorker;
+
+import org.openide.util.NbBundle;
+
+import org.sleuthkit.datamodel.AbstractFile;
+import org.sleuthkit.datamodel.ReadContentInputStream;
+import org.sleuthkit.autopsy.coreutils.Logger;
+import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
+
+import org.icepdf.core.exceptions.PDFException;
+import org.icepdf.core.exceptions.PDFSecurityException;
+import org.icepdf.core.pobjects.Document;
+
+import org.icepdf.ri.common.ComponentKeyBinding;
+import org.icepdf.ri.common.SwingController;
+import org.icepdf.ri.common.SwingViewBuilder;
+import org.icepdf.ri.common.views.DocumentViewControllerImpl;
+import org.icepdf.ri.common.views.DocumentViewModelImpl;
+import org.icepdf.ri.util.PropertiesManager;
+
+/**
+ * Application content viewer for PDF files.
+ */
+public class PDFViewer implements FileTypeViewer {
+
+ private static final Logger logger = Logger.getLogger(PDFViewer.class.getName());
+
+ private JPanel container;
+ private final PropertiesManager propsManager;
+
+ public PDFViewer() {
+ container = createNewContainer();
+ propsManager = getCustomProperties();
+ }
+
+ @Override
+ public List getSupportedMIMETypes() {
+ return Arrays.asList("application/pdf");
+ }
+
+ @Override
+ public void setFile(AbstractFile file) {
+ // The 'C' in IcePDFs MVC set up.
+ SwingController controller = new SwingController();
+
+ // Builder for the 'V' in IcePDFs MVC set up
+ SwingViewBuilder viewBuilder = new SwingViewBuilder(controller, propsManager);
+
+ // The 'V' in IcePDFs MVC set up.
+ JPanel icePdfPanel = viewBuilder.buildViewerPanel();
+
+ // This connects keyboard commands performed on the view to the controller.
+ // The only keyboard commands that the controller supports is Ctrl-C for
+ // copying selected text.
+ ComponentKeyBinding.install(controller, icePdfPanel);
+
+ // Ensure the preferredSize is in sync with the parent container.
+ icePdfPanel.setPreferredSize(this.container.getPreferredSize());
+
+ // Add the IcePDF view to the center of our container.
+ this.container.add(icePdfPanel, BorderLayout.CENTER);
+
+ // Document is the 'M' in IcePDFs MVC set up. Read the data needed to
+ // populate the model in the background.
+ new SwingWorker() {
+ @Override
+ protected Document doInBackground() throws PDFException, PDFSecurityException, IOException {
+ ReadContentInputStream stream = new ReadContentInputStream(file);
+ Document doc = new Document();
+ // This will read the stream into memory.
+ doc.setInputStream(stream, null);
+ return doc;
+ }
+
+ @Override
+ protected void done() {
+ // Customize the view selection modes on the EDT. Each of these
+ // will cause UI widgets to be updated.
+ try {
+ Document doc = get();
+ controller.openDocument(doc, null);
+ // This makes the PDF viewer appear as one continuous
+ // document, which is the default for most popular PDF viewers.
+ controller.setPageViewMode(DocumentViewControllerImpl.ONE_COLUMN_VIEW, true);
+ // This makes it possible to select text by left clicking and dragging.
+ controller.setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_TEXT_SELECTION);
+ } catch (InterruptedException ex) {
+ // Do nothing.
+ } catch (ExecutionException ex) {
+ Throwable exCause = ex.getCause();
+ if (exCause instanceof PDFSecurityException) {
+ showEncryptionDialog();
+ } else {
+ logger.log(Level.WARNING, String.format("PDF content viewer "
+ + "was unable to open document with id %d and name %s",
+ file.getId(), file.getName()), ex);
+ showErrorDialog();
+ }
+ }
+ }
+ }.execute();
+ }
+
+ @Override
+ public Component getComponent() {
+ return container;
+ }
+
+ @Override
+ public void resetComponent() {
+ container = createNewContainer();
+ }
+
+ // The container should have a BorderLayout otherwise the IcePDF panel may
+ // not be visible.
+ private JPanel createNewContainer() {
+ return new JPanel(new BorderLayout());
+ }
+
+ @Override
+ public boolean isSupported(AbstractFile file) {
+ return getSupportedMIMETypes().contains(file.getMIMEType());
+ }
+
+ /**
+ * Sets property values that will control how the view will be constructed
+ * in IcePDFs MVC set up.
+ */
+ private PropertiesManager getCustomProperties() {
+ Properties props = new Properties();
+
+ // See link for available properties. https://www.icesoft.org/wiki/display/PDF/Customizing+the+Viewer
+ props.setProperty(PropertiesManager.PROPERTY_SHOW_UTILITY_SAVE, "false");
+ props.setProperty(PropertiesManager.PROPERTY_SHOW_UTILITY_OPEN, "false");
+ props.setProperty(PropertiesManager.PROPERTY_SHOW_UTILITY_PRINT, "false");
+ props.setProperty(PropertiesManager.PROPERTY_SHOW_TOOLBAR_ANNOTATION, "false");
+ props.setProperty(PropertiesManager.PROPERTY_SHOW_UTILITYPANE_ANNOTATION, "false");
+
+ // This suppresses a pop-up, from IcePDF, that asks if you'd like to
+ // save configuration changes to disk.
+ props.setProperty("application.showLocalStorageDialogs", "false");
+
+ ResourceBundle defaultMessageBundle = ResourceBundle.getBundle(PropertiesManager.DEFAULT_MESSAGE_BUNDLE);
+ return new PropertiesManager(System.getProperties(), props, defaultMessageBundle);
+ }
+
+ @NbBundle.Messages({
+ "PDFViewer.errorDialog=An error occurred while opening this PDF document. "
+ + "Check the logs for more information. You may continue to use "
+ + "this feature on other PDF documents."
+ })
+ private void showErrorDialog() {
+ MessageNotifyUtil.Message.error(Bundle.PDFViewer_errorDialog());
+ }
+
+ @NbBundle.Messages({
+ "PDFViewer.encryptedDialog=This document is password protected."
+ })
+ private void showEncryptionDialog() {
+ MessageNotifyUtil.Message.error(Bundle.PDFViewer_encryptedDialog());
+ }
+}
diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java
index 15bc46a8da..c7ccf32099 100644
--- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java
+++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java
@@ -260,7 +260,7 @@ public class BlackboardArtifactNode extends AbstractContentNode counts = new HashMap<>();
+
+ AccountTypeResults() {
+ update();
+ }
+
+ /**
+ * Given the type name of the Account.Type, provides the count of those type.
+ * @param accountType The type name of the Account.Type.
+ * @return The number of results found for the given account type.
+ */
+ Long getCount(String accountType) {
+ return counts.get(accountType);
+ }
+
+ /**
+ * Retrieves an alphabetically organized list of all the account types.
+ * @return An alphabetically organized list of all the account types.
+ */
+ List getTypes() {
+ List types = new ArrayList<>(counts.keySet());
+ Collections.sort(types);
+ return types;
+ }
+
+ /**
+ * Queries the database and updates the counts for each account type.
+ */
+ private void update() {
+ String accountTypesInUseQuery
+ = "SELECT blackboard_attributes.value_text as account_type, COUNT(*) as count "
+ + " FROM blackboard_artifacts " //NON-NLS
+ + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
+ + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
+ + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
+ + getFilterByDataSourceClause()
+ + " GROUP BY blackboard_attributes.value_text ";
+
+ try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery(accountTypesInUseQuery);
+ ResultSet resultSet = executeQuery.getResultSet()) {
+
+ counts.clear();
+ while (resultSet.next()) {
+ String accountType = resultSet.getString("account_type");
+ Long count = resultSet.getLong("count");
+ counts.put(accountType, count);
+ }
+ } catch (TskCoreException | SQLException ex) {
+ LOGGER.log(Level.SEVERE, "Error querying for account_types", ex);
+ }
+ }
+ }
/**
* Creates child nodes for each account type in the db.
*/
private class AccountTypeFactory extends ObservingChildren {
-
+
/*
* The pcl is in this class because it has the easiest mechanisms to add
* and remove itself during its life cycles.
@@ -281,6 +344,7 @@ final public class Accounts implements AutopsyVisitableItem {
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
if (null != eventData
&& eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
+ accountTypeResults.update();
reviewStatusBus.post(eventData);
}
} catch (NoCurrentCaseException notUsed) {
@@ -324,37 +388,31 @@ final public class Accounts implements AutopsyVisitableItem {
@Override
protected boolean createKeys(List list) {
- String accountTypesInUseQuery
- = "SELECT DISTINCT blackboard_attributes.value_text as account_type "
- + " FROM blackboard_artifacts " //NON-NLS
- + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
- + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
- + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
- + getFilterByDataSourceClause();
-
- try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery(accountTypesInUseQuery);
- ResultSet resultSet = executeQuery.getResultSet()) {
- while (resultSet.next()) {
- String accountType = resultSet.getString("account_type");
- list.add(accountType);
- }
- } catch (TskCoreException | SQLException ex) {
- LOGGER.log(Level.SEVERE, "Error querying for account_types", ex);
- }
-
+ list.addAll(accountTypeResults.getTypes());
return true;
}
+
+ /**
+ * Registers the given node with the reviewStatusBus and returns
+ * the node wrapped in an array.
+ * @param node The node to be wrapped.
+ * @return The array containing this node.
+ */
+ private Node[] getNodeArr(Node node) {
+ reviewStatusBus.register(node);
+ return new Node[]{node};
+ }
@Override
protected Node[] createNodesForKey(String acountTypeName) {
if (Account.Type.CREDIT_CARD.getTypeName().equals(acountTypeName)) {
- return new Node[]{new CreditCardNumberAccountTypeNode()};
+ return getNodeArr(new CreditCardNumberAccountTypeNode());
} else {
try {
Account.Type accountType = skCase.getCommunicationsManager().getAccountType(acountTypeName);
- return new Node[]{new DefaultAccountTypeNode(accountType)};
+ return getNodeArr(new DefaultAccountTypeNode(accountType));
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error getting display name for account type. ", ex);
}
@@ -509,11 +567,14 @@ final public class Accounts implements AutopsyVisitableItem {
* no special behavior.
*/
final public class DefaultAccountTypeNode extends DisplayableItemNode {
-
+ private final Account.Type accountType;
+
private DefaultAccountTypeNode(Account.Type accountType) {
super(Children.create(new DefaultAccountFactory(accountType), true), Lookups.singleton(accountType));
- setName(accountType.getDisplayName());
- this.setIconBaseWithExtension(getIconFilePath(accountType)); //NON-NLS
+ this.accountType = accountType;
+ String iconPath = getIconFilePath(accountType);
+ this.setIconBaseWithExtension(iconPath != null && iconPath.charAt(0) == '/' ? iconPath.substring(1) : iconPath); //NON-NLS
+ updateName();
}
@Override
@@ -530,6 +591,24 @@ final public class Accounts implements AutopsyVisitableItem {
public String getItemType() {
return getClass().getName();
}
+
+
+ @Subscribe
+ void handleReviewStatusChange(ReviewStatusChangeEvent event) {
+ updateName();
+ }
+
+ @Subscribe
+ void handleDataAdded(ModuleDataEvent event) {
+ updateName();
+ }
+
+ /**
+ * Gets the latest counts for the account type and then updates the name.
+ */
+ public void updateName() {
+ setName(String.format("%s (%d)", accountType.getDisplayName(), accountTypeResults.getCount(accountType.getTypeName())));
+ }
}
/**
@@ -659,6 +738,23 @@ final public class Accounts implements AutopsyVisitableItem {
setName(Account.Type.CREDIT_CARD.getDisplayName());
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/credit-cards.png"); //NON-NLS
}
+
+ /**
+ * Gets the latest counts for the account type and then updates the name.
+ */
+ public void updateName() {
+ setName(String.format("%s (%d)", Account.Type.CREDIT_CARD.getDisplayName(), accountTypeResults.getCount(Account.Type.CREDIT_CARD.getTypeName())));
+ }
+
+ @Subscribe
+ void handleReviewStatusChange(ReviewStatusChangeEvent event) {
+ updateName();
+ }
+
+ @Subscribe
+ void handleDataAdded(ModuleDataEvent event) {
+ updateName();
+ }
@Override
public boolean isLeafTypeNode() {
diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryUiUtils.java b/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryUiUtils.java
index c9ad380a32..0a8f93fa92 100644
--- a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryUiUtils.java
+++ b/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryUiUtils.java
@@ -34,8 +34,8 @@ final class DiscoveryUiUtils {
private static final int ICON_SIZE = 16;
private static final String RED_CIRCLE_ICON_PATH = "org/sleuthkit/autopsy/images/red-circle-exclamation.png";
private static final String YELLOW_CIRCLE_ICON_PATH = "org/sleuthkit/autopsy/images/yellow-circle-yield.png";
- private static final String DELETE_ICON_PATH = "/org/sleuthkit/autopsy/images/file-icon-deleted.png";
- private static final String UNSUPPORTED_DOC_PATH = "/org/sleuthkit/autopsy/images/image-extraction-not-supported.png";
+ private static final String DELETE_ICON_PATH = "org/sleuthkit/autopsy/images/file-icon-deleted.png";
+ private static final String UNSUPPORTED_DOC_PATH = "org/sleuthkit/autopsy/images/image-extraction-not-supported.png";
private static final ImageIcon INTERESTING_SCORE_ICON = new ImageIcon(ImageUtilities.loadImage(YELLOW_CIRCLE_ICON_PATH, false));
private static final ImageIcon NOTABLE_SCORE_ICON = new ImageIcon(ImageUtilities.loadImage(RED_CIRCLE_ICON_PATH, false));
private static final ImageIcon DELETED_ICON = new ImageIcon(ImageUtilities.loadImage(DELETE_ICON_PATH, false));
diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java b/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java
index bc56968f99..e923d6dbd6 100755
--- a/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java
+++ b/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java
@@ -22,6 +22,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
+import javafx.util.Pair;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException;
@@ -75,11 +76,11 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter
*
* @param mapWaypoints List of filtered MapWaypoints.
*/
- abstract void handleFilteredWaypointSet(Set mapWaypoints);
+ abstract void handleFilteredWaypointSet(Set mapWaypoints, List> tracks);
@Override
public void process(List waypoints) {
- List