diff --git a/.gitignore b/.gitignore
index 7fe49ad362..b89812646f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -66,6 +66,7 @@ genfiles.properties
*~
/netbeans-plat
/docs/doxygen/doxygen_docs
+/docs/doxygen-user/user-docs
/jdiff-javadocs/*
/jdiff-logs/*
/gen_version.txt
@@ -74,3 +75,5 @@ Core/src/org/sleuthkit/autopsy/casemodule/docs/QuickStart.html
Core/src/org/sleuthkit/autopsy/casemodule/docs/screenshot.png
/test/script/myconfig.xml
/test/script/*/*.xml
+.DS_Store
+.*.swp
diff --git a/Core/build.xml b/Core/build.xml
index 9dd720c2d6..2d313a2de7 100644
--- a/Core/build.xml
+++ b/Core/build.xml
@@ -6,33 +6,10 @@
Builds, tests, and runs the project org.sleuthkit.autopsy.core
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -53,12 +30,7 @@
-
-
-
-
-
diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ColorUtilities.java b/Core/src/org/sleuthkit/autopsy/coreutils/ColorUtilities.java
new file mode 100644
index 0000000000..d51e919df7
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/coreutils/ColorUtilities.java
@@ -0,0 +1,38 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2013 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.coreutils;
+
+import javafx.scene.paint.Color;
+
+/**
+ *
+ */
+public class ColorUtilities {
+
+ private ColorUtilities() {
+ }
+
+ public static String getRGBCode(Color color) {
+ return String.format("#%02X%02X%02X%02X",
+ (int) (color.getRed() * 255),
+ (int) (color.getGreen() * 255),
+ (int) (color.getBlue() * 255),
+ (int) (color.getOpacity() * 255));
+ }
+}
diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/History.java b/Core/src/org/sleuthkit/autopsy/coreutils/History.java
new file mode 100644
index 0000000000..6ef81b1e38
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/coreutils/History.java
@@ -0,0 +1,198 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2014 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.coreutils;
+
+import java.util.Objects;
+import javafx.beans.property.Property;
+import javafx.beans.property.ReadOnlyBooleanProperty;
+import javafx.beans.property.ReadOnlyBooleanWrapper;
+import javafx.beans.property.ReadOnlyObjectProperty;
+import javafx.beans.property.ReadOnlyObjectWrapper;
+import javafx.beans.property.SimpleListProperty;
+import javafx.collections.FXCollections;
+import javax.annotation.concurrent.GuardedBy;
+import javax.annotation.concurrent.ThreadSafe;
+
+/**
+ * A basic history implementation. Keeps a history (and forward) stack of state
+ * objects of type . exposes current state and availability of
+ * advance/retreat operations via methods and JFX {@link Property}s. Null is not
+ * a valid state, and will only be the current state before the first call to
+ * advance.
+ *
+ * @param the type of objects used to represent the
+ * current/historical/future states
+ */
+@ThreadSafe
+public class History {
+
+ @GuardedBy("this")
+ private final ObservableStack historyStack = new ObservableStack<>();
+
+ @GuardedBy("this")
+ private final ObservableStack forwardStack = new ObservableStack<>();
+
+ @GuardedBy("this")
+ private final ReadOnlyObjectWrapper currentState = new ReadOnlyObjectWrapper<>();
+
+ @GuardedBy("this")
+ private final ReadOnlyBooleanWrapper canAdvance = new ReadOnlyBooleanWrapper();
+
+ @GuardedBy("this")
+ private final ReadOnlyBooleanWrapper canRetreat = new ReadOnlyBooleanWrapper();
+
+ synchronized public T getCurrentState() {
+ return currentState.get();
+ }
+
+ synchronized public boolean canAdvance() {
+ return canAdvance.get();
+ }
+
+ synchronized public boolean canRetreat() {
+ return canRetreat.get();
+ }
+
+ synchronized public ReadOnlyObjectProperty currentState() {
+ return currentState.getReadOnlyProperty();
+ }
+
+ synchronized public ReadOnlyBooleanProperty getCanAdvance() {
+ return canAdvance.getReadOnlyProperty();
+ }
+
+ synchronized public ReadOnlyBooleanProperty getCanRetreat() {
+ return canRetreat.getReadOnlyProperty();
+ }
+
+ public History(T initialState) {
+ this();
+ currentState.set(initialState);
+ }
+
+ public History() {
+ canAdvance.bind(forwardStack.emptyProperty().not());
+ canRetreat.bind(historyStack.emptyProperty().not());
+ }
+
+ /**
+ * advance through the forward states by one, and put the current state in
+ * the history. Is a no-op if there are no forward states.
+ *
+ * @return the state advanced to, or null if there were no forward states.
+ */
+ synchronized public T advance() {
+ final T peek = forwardStack.peek();
+
+ if (peek != null && peek.equals(currentState.get()) == false) {
+ historyStack.push(currentState.get());
+ currentState.set(peek);
+ forwardStack.pop();
+ }
+ return peek;
+ }
+
+ /**
+ * retreat through the history states by one, and add the current state to
+ * the forward states. Is a no-op if there are no history states.
+ *
+ * @return the state retreated to, or null if there were no history states.
+ */
+ synchronized public T retreat() {
+ final T pop = historyStack.pop();
+
+ if (pop != null && pop.equals(currentState.get()) == false) {
+ forwardStack.push(currentState.get());
+ currentState.set(pop);
+ return pop;
+ } else if (pop != null && pop.equals(currentState.get())) {
+ return retreat();
+ }
+ return pop;
+ }
+
+ /**
+ * put the current state in the history and advance to the given state. It
+ * is a no-op if the current state is equal to the given state as determined
+ * by invoking the equals method. Throws away any forward states.
+ *
+ * @param newState the new state to advance to
+ * @throws IllegalArgumentException if newState == null
+ */
+ synchronized public void advance(T newState) throws IllegalArgumentException {
+
+ if (newState != null && Objects.equals(currentState.get(), newState) == false) {
+ if (currentState.get() != null) {
+ historyStack.push(currentState.get());
+ }
+ currentState.set(newState);
+ if (newState.equals(forwardStack.peek())) {
+ forwardStack.pop();
+ } else {
+ forwardStack.clear();
+ }
+ }
+ }
+
+ public void clear() {
+ historyStack.clear();
+ forwardStack.clear();
+ currentState.set(null);
+ }
+
+ /**
+ * A simple extension to SimpleListProperty to add a stack api
+ *
+ * TODO: this really should not extend SimpleListProperty but should
+ * delegate to an appropriate observable implementation while implementing
+ * the {@link Deque} interface
+ */
+ private static class ObservableStack extends SimpleListProperty {
+
+ public ObservableStack() {
+ super(FXCollections.synchronizedObservableList(FXCollections.observableArrayList()));
+ }
+
+ public void push(T item) {
+ synchronized (this) {
+ add(0, item);
+ }
+ }
+
+ public T pop() {
+ synchronized (this) {
+ if (isEmpty()) {
+ return null;
+ } else {
+ return remove(0);
+ }
+ }
+ }
+
+ public T peek() {
+ synchronized (this) {
+ if (isEmpty()) {
+ return null;
+ } else {
+ return get(0);
+ }
+ }
+ }
+ }
+}
diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/LoggedTask.java b/Core/src/org/sleuthkit/autopsy/coreutils/LoggedTask.java
new file mode 100644
index 0000000000..9bc3f09d27
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/coreutils/LoggedTask.java
@@ -0,0 +1,75 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2013-14 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.coreutils;
+
+import java.util.concurrent.ExecutionException;
+import java.util.logging.Level;
+import javafx.concurrent.Task;
+import org.openide.util.Cancellable;
+
+/**
+ * extension of Task that logs state changes
+ */
+public abstract class LoggedTask extends Task implements Cancellable {
+
+ private static final Logger LOGGER = Logger.getLogger(LoggedTask.class.getName());
+
+ private final boolean logStateChanges;
+
+ public LoggedTask(String taskName, boolean logStateChanges) {
+ updateTitle(taskName);
+ this.logStateChanges = logStateChanges;
+ }
+
+ @Override
+ protected void cancelled() {
+ super.cancelled();
+ if (logStateChanges) {
+ LOGGER.log(Level.WARNING, "{0} cancelled!", getTitle());
+ }
+ }
+
+ @Override
+ protected void failed() {
+ super.failed();
+ LOGGER.log(Level.SEVERE, getTitle() + " failed!", getException());
+
+ }
+
+ @Override
+ protected void scheduled() {
+ super.scheduled();
+ if (logStateChanges) {
+ LOGGER.log(Level.INFO, "{0} scheduled", getTitle());
+ }
+ }
+
+ @Override
+ protected void succeeded() {
+ super.succeeded();
+ try {
+ get();
+ } catch (InterruptedException | ExecutionException ex) {
+ LOGGER.log(Level.SEVERE, getTitle() + " threw unexpected exception: ", ex);
+ }
+ if (logStateChanges) {
+ LOGGER.log(Level.INFO, "{0} succeeded", getTitle());
+ }
+ }
+}
diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ThreadConfined.java b/Core/src/org/sleuthkit/autopsy/coreutils/ThreadConfined.java
new file mode 100644
index 0000000000..5527c01b26
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/coreutils/ThreadConfined.java
@@ -0,0 +1,22 @@
+package org.sleuthkit.autopsy.coreutils;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD})
+@Inherited
+@Documented
+public @interface ThreadConfined {
+
+ ThreadType type();
+
+ public enum ThreadType {
+
+ ANY, UI, JFX, AWT, NOT_UI
+ }
+}
diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties
index 017c40bc15..74fbc9b59c 100755
--- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties
+++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties
@@ -62,3 +62,4 @@ InterestingItemDefsPanel.rulePathFilterTextField.text=
InterestingItemDefsPanel.rulePathPanel.border.title=Path
InterestingItemDefsPanel.rulePathFilterRegexCheckBox.text=Regex
InterestingItemDefsPanel.ignoreKnownFilesCheckbox.text=Ignore Known Files
+FilesIdentifierIngestJobSettingsPanel.border.title=Select interesting files sets to enable during ingest:
diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesIdentifierIngestJobSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesIdentifierIngestJobSettingsPanel.form
index ec9fb17f55..f36b0434a9 100755
--- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesIdentifierIngestJobSettingsPanel.form
+++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesIdentifierIngestJobSettingsPanel.form
@@ -1,6 +1,15 @@