diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/HistoryManager.java b/Core/src/org/sleuthkit/autopsy/coreutils/History.java similarity index 89% rename from Core/src/org/sleuthkit/autopsy/coreutils/HistoryManager.java rename to Core/src/org/sleuthkit/autopsy/coreutils/History.java index e1d415c5bb..564f18cba5 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/HistoryManager.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/History.java @@ -37,7 +37,7 @@ import javax.annotation.concurrent.ThreadSafe; * current/historical/future states */ @ThreadSafe -public class HistoryManager { +public class History { @GuardedBy("this") private final ObservableStack historyStack = new ObservableStack<>(); @@ -78,12 +78,12 @@ public class HistoryManager { return canRetreat.getReadOnlyProperty(); } - public HistoryManager(T initialState) { + public History(T initialState) { this(); currentState.set(initialState); } - public HistoryManager() { + public History() { canAdvance.bind(forwardStack.emptyProperty().not()); canRetreat.bind(historyStack.emptyProperty().not()); } @@ -112,15 +112,15 @@ public class HistoryManager { * @return the state retreated to, or null if there were no history states. */ synchronized public T retreat() { - final T peek = historyStack.pop(); + final T pop = historyStack.pop(); - if (peek != null && peek.equals(currentState.get()) == false) { + if (pop != null && pop.equals(currentState.get()) == false) { forwardStack.push(currentState.get()); - currentState.set(peek); - } else if (peek != null && peek.equals(currentState.get())) { + currentState.set(pop); + } else if (pop != null && pop.equals(currentState.get())) { return retreat(); } - return peek; + return pop; } /** @@ -129,12 +129,8 @@ public class HistoryManager { * by invoking the equals method. Throws away any forward states. * * @param newState the new state to advance to - * @throws IllegalArgumentException if the newState is null */ synchronized public void advance(T newState) throws IllegalArgumentException { - if (newState == null) { - throw new IllegalArgumentException("newState must be non-null"); - } if (currentState.equals(newState) == false) { if (currentState.get() != null) { historyStack.push(currentState.get()); @@ -149,7 +145,9 @@ public class HistoryManager { } public void clear() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + historyStack.clear(); + forwardStack.clear(); + currentState.set(null); } /** diff --git a/Core/src/org/sleuthkit/autopsy/timeline/HistoryManager.java b/Core/src/org/sleuthkit/autopsy/timeline/HistoryManager.java deleted file mode 100644 index cd7487c87f..0000000000 --- a/Core/src/org/sleuthkit/autopsy/timeline/HistoryManager.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * 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.timeline; - -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 - * - * @param the type of objects used to represent the - * current/historical/future states - */ -@ThreadSafe -public class HistoryManager { - - @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 HistoryManager(T initialState) { - this(); - currentState.set(initialState); - } - - public HistoryManager() { - 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 peek = historyStack.pop(); - - if (peek != null && peek.equals(currentState.get()) == false) { - forwardStack.push(currentState.get()); - currentState.set(peek); - } else if (peek != null && peek.equals(currentState.get())) { - return retreat(); - } - return peek; - } - - /** - * 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 the newState is null - */ - synchronized public void advance(T newState) throws IllegalArgumentException { - if (newState == null) { - throw new IllegalArgumentException("newState must be non-null"); - } - if (currentState.equals(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/timeline/TimeLineController.java b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java index bb333607c2..a536ecc66b 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java @@ -62,6 +62,7 @@ import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; import static org.sleuthkit.autopsy.casemodule.Case.Events.CURRENT_CASE; import static org.sleuthkit.autopsy.casemodule.Case.Events.DATA_SOURCE_ADDED; +import org.sleuthkit.autopsy.coreutils.History; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.timeline.events.FilteredEventsModel; @@ -170,7 +171,7 @@ public class TimeLineController { private final ZoomParams InitialZoomState; @GuardedBy("this") - private final HistoryManager historyManager = new HistoryManager<>(); + private final History historyManager = new History<>(); //all members should be access with the intrinsict lock of this object held //selected events (ie shown in the result viewer) diff --git a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/ImageAnalyzerController.java b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/ImageAnalyzerController.java index 6f172fbe79..d2100bcf78 100644 --- a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/ImageAnalyzerController.java +++ b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/ImageAnalyzerController.java @@ -63,6 +63,7 @@ import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.History; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imageanalyzer.datamodel.Category; import org.sleuthkit.autopsy.imageanalyzer.datamodel.DrawableAttribute; @@ -77,8 +78,6 @@ import org.sleuthkit.autopsy.imageanalyzer.gui.NoGroupsDialog; import org.sleuthkit.autopsy.imageanalyzer.gui.SummaryTablePane; import org.sleuthkit.autopsy.imageanalyzer.progress.ProgressAdapterBase; import org.sleuthkit.autopsy.ingest.IngestManager; -import org.sleuthkit.autopsy.timeline.HistoryManager; -import org.sleuthkit.autopsy.timeline.zooming.ZoomParams; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -93,71 +92,68 @@ import org.sleuthkit.datamodel.TskData; * Connects different parts of Eureka together and is hub for flow of control. */ public class ImageAnalyzerController implements FileUpdateListener { - + private static final Logger LOGGER = Logger.getLogger(ImageAnalyzerController.class.getName()); - + private final Region infoOverLayBackground = new Region() { { setBackground(new Background(new BackgroundFill(Color.GREY, CornerRadii.EMPTY, Insets.EMPTY))); setOpacity(.4); } }; - + private static ImageAnalyzerController instance; - + public static synchronized ImageAnalyzerController getDefault() { if (instance == null) { instance = new ImageAnalyzerController(); } return instance; } - + @GuardedBy("this") - private final HistoryManager historyManager = new HistoryManager<>(); - + private final History historyManager = new History<>(); + private final ReadOnlyBooleanWrapper listeningEnabled = new ReadOnlyBooleanWrapper(false); - + private final ReadOnlyIntegerWrapper queueSizeProperty = new ReadOnlyIntegerWrapper(0); - + private final ReadOnlyBooleanWrapper regroupDisabled = new ReadOnlyBooleanWrapper(false); - + private final ReadOnlyBooleanWrapper stale = new ReadOnlyBooleanWrapper(false); - + private final ReadOnlyBooleanWrapper metaDataCollapsed = new ReadOnlyBooleanWrapper(false); - + private final FileIDSelectionModel selectionModel = FileIDSelectionModel.getInstance(); - + private DBWorkerThread dbWorkerThread; - + private DrawableDB db; - + private final GroupManager groupManager = new GroupManager(this); - + private StackPane fullUIStackPane; - + private StackPane centralStackPane; - + private Node infoOverlay; - + public ReadOnlyBooleanProperty getMetaDataCollapsed() { return metaDataCollapsed.getReadOnlyProperty(); } - + public void setMetaDataCollapsed(Boolean metaDataCollapsed) { this.metaDataCollapsed.set(metaDataCollapsed); } - + private GroupViewState getViewState() { return historyManager.getCurrentState(); } - + public ReadOnlyBooleanProperty regroupDisabled() { return regroupDisabled.getReadOnlyProperty(); } - - - - + public ReadOnlyObjectProperty viewState() { return historyManager.currentState(); } @@ -173,28 +169,28 @@ public class ImageAnalyzerController implements FileUpdateListener { * an executor to submit async ui related background tasks to. */ final ExecutorService bgTaskExecutor = Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder().namingPattern("ui task -%d").build()); - + public synchronized FileIDSelectionModel getSelectionModel() { - + return selectionModel; } - + public GroupManager getGroupManager() { return groupManager; } - + public void setListeningEnabled(boolean enabled) { listeningEnabled.set(enabled); } - + ReadOnlyBooleanProperty listeningEnabled() { return listeningEnabled.getReadOnlyProperty(); } - + boolean isListeningEnabled() { return listeningEnabled.get(); } - + void setStale(Boolean b) { Platform.runLater(() -> { stale.set(b); @@ -203,37 +199,37 @@ public class ImageAnalyzerController implements FileUpdateListener { new PerCaseProperties(Case.getCurrentCase()).setConfigSetting(EurekaModule.MODULE_NAME, PerCaseProperties.STALE, b.toString()); } } - + public ReadOnlyBooleanProperty stale() { return stale.getReadOnlyProperty(); } - + boolean isStale() { return stale.get(); } - + private ImageAnalyzerController() { - + listeningEnabled.addListener((observable, oldValue, newValue) -> { if (newValue && !oldValue && Case.existsCurrentCase() && EurekaModule.isCaseStale(Case.getCurrentCase())) { queueTask(new CopyAnalyzedFiles()); } }); - + groupManager.getAnalyzedGroups().addListener((Observable o) -> { checkForGroups(); }); - + groupManager.getUnSeenGroups().addListener((Observable observable) -> { + //if there are unseen groups and none being viewed if (groupManager.getUnSeenGroups().size() > 0 && (getViewState() == null || getViewState().getGroup() == null)) { - - setViewState(GroupViewState.tile(groupManager.getUnSeenGroups().get(0))); + advance(GroupViewState.tile(groupManager.getUnSeenGroups().get(0))); } }); regroupDisabled.addListener((Observable observable) -> { checkForGroups(); }); - + IngestManager.getInstance().addIngestModuleEventListener((evt) -> { Platform.runLater(this::updateRegroupDisabled); }); @@ -257,7 +253,7 @@ public class ImageAnalyzerController implements FileUpdateListener { case SCHEDULED: case RUNNING: break; - + case FAILED: LOGGER.log(Level.WARNING, "task :" + task.getTitle() + " failed", task.getException()); case CANCELLED: @@ -270,11 +266,11 @@ public class ImageAnalyzerController implements FileUpdateListener { break; } }); - + synchronized (bgTasks) { bgTasks.add(task); } - + bgTaskExecutor.execute(task); } @@ -286,18 +282,20 @@ public class ImageAnalyzerController implements FileUpdateListener { return historyManager.getCanRetreat(); } - synchronized public void advance(GroupViewState viewState) { - historyManager.advance(viewState); + synchronized public void advance(GroupViewState newState) { + if (viewState().get() == null ||( viewState().get().getGroup() != newState.getGroup())) { + historyManager.advance(newState); + } } synchronized public GroupViewState advance() { return historyManager.advance(); } - + synchronized public GroupViewState retreat() { return historyManager.retreat(); } - + private void updateRegroupDisabled() { regroupDisabled.set(getFileUpdateQueueSizeProperty().get() > 0 || IngestManager.getInstance().isIngestRunning()); } @@ -309,7 +307,7 @@ public class ImageAnalyzerController implements FileUpdateListener { */ public final void checkForGroups() { if (groupManager.getAnalyzedGroups().isEmpty()) { - setViewState(null); + advance(null); if (IngestManager.getInstance().isIngestRunning()) { if (listeningEnabled.get() == false) { replaceNotification(fullUIStackPane, @@ -320,7 +318,7 @@ public class ImageAnalyzerController implements FileUpdateListener { new NoGroupsDialog("No groups are fully analyzed yet, but ingest is still ongoing. Please Wait.", new ProgressIndicator())); } - + } else if (getFileUpdateQueueSizeProperty().get() > 0) { replaceNotification(fullUIStackPane, new NoGroupsDialog("No groups are fully analyzed yet, but image / video data is still being populated. Please Wait.", @@ -328,7 +326,7 @@ public class ImageAnalyzerController implements FileUpdateListener { } else if (db != null && db.countAllFiles() <= 0) { // there are no files in db replaceNotification(fullUIStackPane, new NoGroupsDialog("There are no images/videos in the added datasources.")); - + } else if (!groupManager.isRegrouping()) { replaceNotification(centralStackPane, new NoGroupsDialog("There are no fully analyzed groups to display:" @@ -347,7 +345,7 @@ public class ImageAnalyzerController implements FileUpdateListener { clearNotification(); } } - + private void clearNotification() { //remove the ingest spinner if (fullUIStackPane != null) { @@ -358,26 +356,26 @@ public class ImageAnalyzerController implements FileUpdateListener { centralStackPane.getChildren().remove(infoOverlay); } } - + private void replaceNotification(StackPane stackPane, Node newNode) { clearNotification(); - + infoOverlay = new StackPane(infoOverLayBackground, newNode); if (stackPane != null) { stackPane.getChildren().add(infoOverlay); } } - + private void restartWorker() { if (dbWorkerThread != null) { dbWorkerThread.cancelAllTasks(); } dbWorkerThread = new DBWorkerThread(); - + getFileUpdateQueueSizeProperty().addListener((o) -> { Platform.runLater(this::updateRegroupDisabled); }); - + Thread th = new Thread(dbWorkerThread); th.setDaemon(false); // we want it to go away when it is done th.start(); @@ -389,7 +387,7 @@ public class ImageAnalyzerController implements FileUpdateListener { * @param c */ public synchronized void setCase(Case c) { - + this.db = DrawableDB.getDrawableDB(c.getCaseDirectory(), this); db.addUpdatedFileListener(this); setListeningEnabled(EurekaModule.isEnabledforCase(c)); @@ -398,7 +396,7 @@ public class ImageAnalyzerController implements FileUpdateListener { // if we add this line icons are made as files are analyzed rather than on demand. // db.addUpdatedFileListener(IconCache.getDefault()); restartWorker(); - + groupManager.setDB(db); SummaryTablePane.getDefault().handleCategoryChanged(Collections.EMPTY_LIST); } @@ -417,12 +415,12 @@ public class ImageAnalyzerController implements FileUpdateListener { for (final long fileId : fileIDs) { //get grouping(s) this file would be in Set groupsForFile = groupManager.getGroupKeysForFileID(fileId); - + for (GroupKey gk : groupsForFile) { groupManager.removeFromGroup(gk, fileId); } } - + break; case FILE_UPDATED: @@ -441,7 +439,7 @@ public class ImageAnalyzerController implements FileUpdateListener { //get grouping(s) this file would be in Set groupsForFile = groupManager.getGroupKeysForFileID(fileId); - + for (GroupKey gk : groupsForFile) { Grouping g = groupManager.getGroupForKey(gk); @@ -458,7 +456,7 @@ public class ImageAnalyzerController implements FileUpdateListener { } } } - + Category.fireChange(fileIDs); if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { TagUtils.fireChange(fileIDs); @@ -474,10 +472,9 @@ public class ImageAnalyzerController implements FileUpdateListener { LOGGER.info("resetting EurekaControler to initial state."); selectionModel.clearSelection(); Platform.runLater(() -> { - historyManager.clear(); }); - + EurekaToolbar.getDefault().reset(); groupManager.clear(); if (db != null) { @@ -498,21 +495,21 @@ public class ImageAnalyzerController implements FileUpdateListener { } dbWorkerThread.addTask(innerTask); } - + public DrawableFile getFileFromId(Long fileID) throws TskCoreException { return db.getFileFromID(fileID); } - + public void setStacks(StackPane fullUIStack, StackPane centralStack) { fullUIStackPane = fullUIStack; this.centralStackPane = centralStack; Platform.runLater(this::checkForGroups); } - + public final ReadOnlyIntegerProperty getFileUpdateQueueSizeProperty() { return queueSizeProperty.getReadOnlyProperty(); } - + public ReadOnlyIntegerProperty bgTaskQueueSizeProperty() { return bgTasks.sizeProperty(); } @@ -551,7 +548,7 @@ public class ImageAnalyzerController implements FileUpdateListener { workQueue.add(it); queueSizeProperty.set(workQueue.size()); } - + @Override public void run() { // nearly infinite loop waiting for tasks @@ -565,17 +562,17 @@ public class ImageAnalyzerController implements FileUpdateListener { if (it.cancelled == false) { it.run(); } - + queueSizeProperty.set(workQueue.size()); - + } catch (InterruptedException ex) { Exceptions.printStackTrace(ex); } - + } } } - + public SleuthkitCase getSleuthKitCase() throws IllegalStateException { if (Case.isCaseOpen()) { return Case.getCurrentCase().getSleuthkitCase(); @@ -588,13 +585,13 @@ public class ImageAnalyzerController implements FileUpdateListener { * Abstract base class for task to be done on {@link DBWorkerThread} */ static public abstract class InnerTask extends ProgressAdapterBase implements Runnable { - + protected volatile boolean cancelled = false; - + public void cancel() { updateState(Worker.State.CANCELLED); } - + protected boolean isCancelled() { return getState() == Worker.State.CANCELLED; } @@ -604,14 +601,14 @@ public class ImageAnalyzerController implements FileUpdateListener { * Abstract base class for tasks associated with an obj id in the database */ static private abstract class TaskWithID extends InnerTask { - + protected Long obj_id; // id of image or file public TaskWithID(Long id) { super(); this.obj_id = id; } - + public Long getId() { return obj_id; } @@ -625,7 +622,7 @@ public class ImageAnalyzerController implements FileUpdateListener { * of the update tasks. */ class MarkAllFilesAsAnalyzed extends InnerTask { - + @Override public void run() { db.markAllFilesAnalyzed(); @@ -637,9 +634,9 @@ public class ImageAnalyzerController implements FileUpdateListener { * task that updates one file in database with results from ingest */ class UpdateFile extends InnerTask { - + private final AbstractFile file; - + public UpdateFile(AbstractFile f) { super(); this.file = f; @@ -659,9 +656,9 @@ public class ImageAnalyzerController implements FileUpdateListener { * task that updates one file in database with results from ingest */ class RemoveFile extends InnerTask { - + private final AbstractFile file; - + public RemoveFile(AbstractFile f) { super(); this.file = f; @@ -684,16 +681,16 @@ public class ImageAnalyzerController implements FileUpdateListener { * adds them to the Drawable DB */ class CopyAnalyzedFiles extends InnerTask { - + final private String DRAWABLE_QUERY = "name LIKE '%." + StringUtils.join(EurekaModule.getAllSupportedExtensions(), "' or name LIKE '%.") + "'"; - + private ProgressHandle progressHandle = ProgressHandleFactory.createHandle("populating analyzed image/video database"); - + @Override public void run() { progressHandle.start(); updateMessage("populating analyzed image/video database"); - + try { //grap all files with supported mime types final List files = getSleuthKitCase().findAllFilesWhere(DRAWABLE_QUERY + " or tsk_files.obj_id in (select tsk_files.obj_id from tsk_files , blackboard_artifacts, blackboard_attributes" @@ -703,7 +700,7 @@ public class ImageAnalyzerController implements FileUpdateListener { + " and blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG.getTypeID() + " and blackboard_attributes.value_text in ('" + StringUtils.join(EurekaModule.getSupportedMimes(), "','") + "'))"); progressHandle.switchToDeterminate(files.size()); - + updateProgress(0.0); //do in transaction @@ -717,7 +714,7 @@ public class ImageAnalyzerController implements FileUpdateListener { } final Boolean hasMimeType = EurekaModule.hasSupportedMimeType(f); final boolean known = f.getKnown() == TskData.FileKnown.KNOWN; - + if (known) { db.removeFile(f.getId(), tr); //remove known files } else { @@ -737,38 +734,38 @@ public class ImageAnalyzerController implements FileUpdateListener { } } } - + units++; final int prog = units; progressHandle.progress(f.getName(), units); updateProgress(prog - 1 / (double) files.size()); updateMessage(f.getName()); } - + progressHandle.finish(); - + progressHandle = ProgressHandleFactory.createHandle("commiting image/video database"); updateMessage("commiting image/video database"); updateProgress(1.0); - + progressHandle.start(); db.commitTransaction(tr, true); - + } catch (TskCoreException ex) { Logger.getLogger(CopyAnalyzedFiles.class.getName()).log(Level.WARNING, "failed to transfer all database contents", ex); } catch (IllegalStateException ex) { Logger.getLogger(CopyAnalyzedFiles.class.getName()).log(Level.SEVERE, "Case was closed out from underneath CopyDataSource task", ex); } - + progressHandle.finish(); - + updateMessage( ""); updateProgress( -1.0); setStale(false); } - + } /** @@ -788,9 +785,9 @@ public class ImageAnalyzerController implements FileUpdateListener { */ // (name like '.jpg' or name like '.png' ...) final private String DRAWABLE_QUERY = "name LIKE '%." + StringUtils.join(EurekaModule.getAllSupportedExtensions(), "' or name LIKE '%.") + "'"; - + private ProgressHandle progressHandle = ProgressHandleFactory.createHandle("prepopulating image/video database"); - + public PrePopulateDataSourceFiles(Long id) { super(id); } @@ -830,7 +827,7 @@ public class ImageAnalyzerController implements FileUpdateListener { // updateProgress(prog - 1 / (double) files.size()); // updateMessage(f.getName()); } - + progressHandle.finish(); progressHandle = ProgressHandleFactory.createHandle("commiting image/video database"); // updateMessage("commiting image/video database"); @@ -838,13 +835,13 @@ public class ImageAnalyzerController implements FileUpdateListener { progressHandle.start(); db.commitTransaction(tr, false); - + } catch (TskCoreException ex) { Logger.getLogger(PrePopulateDataSourceFiles.class.getName()).log(Level.WARNING, "failed to transfer all database contents", ex); } catch (IllegalStateException ex) { Logger.getLogger(PrePopulateDataSourceFiles.class.getName()).log(Level.SEVERE, "Case was closed out from underneath CopyDataSource task", ex); } - + progressHandle.finish(); // updateMessage("");