From 8df6dfb8f7f1e4afbe5ed874f8b4b9776f16ec1b Mon Sep 17 00:00:00 2001 From: millmanorama Date: Tue, 4 Sep 2018 09:46:10 +0200 Subject: [PATCH] pass controller to DrawableTagsManager constructor, ImageGalleryController keeps reference to Case object --- .../imagegallery/ImageGalleryController.java | 267 +++++++++--------- .../datamodel/DrawableTagsManager.java | 13 +- 2 files changed, 145 insertions(+), 135 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index f96a0a5b1a..e0f253e491 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -99,7 +99,7 @@ import org.sleuthkit.datamodel.TskData; * control. */ public final class ImageGalleryController { - + private static final Logger logger = Logger.getLogger(ImageGalleryController.class.getName()); private static ImageGalleryController instance; @@ -108,24 +108,24 @@ public final class ImageGalleryController { * not listen to speed up ingest */ private final SimpleBooleanProperty listeningEnabled = new SimpleBooleanProperty(false); - + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) private final ReadOnlyBooleanWrapper stale = new ReadOnlyBooleanWrapper(false); - + private final ReadOnlyBooleanWrapper metaDataCollapsed = new ReadOnlyBooleanWrapper(false); private final ReadOnlyDoubleWrapper thumbnailSize = new ReadOnlyDoubleWrapper(100); private final ReadOnlyBooleanWrapper regroupDisabled = new ReadOnlyBooleanWrapper(false); private final ReadOnlyIntegerWrapper dbTaskQueueSize = new ReadOnlyIntegerWrapper(0); - + private final FileIDSelectionModel selectionModel = new FileIDSelectionModel(this); - + private final History historyManager = new History<>(); private final UndoRedoManager undoManager = new UndoRedoManager(); private final GroupManager groupManager = new GroupManager(this); private final HashSetManager hashSetManager = new HashSetManager(); private final CategoryManager categoryManager = new CategoryManager(this); private DrawableTagsManager tagsManager; - + private Runnable showTree; private Toolbar toolbar; private StackPane fullUIStackPane; @@ -137,12 +137,17 @@ public final class ImageGalleryController { setOpacity(.4); } }; - + private ListeningExecutorService dbExecutor; - + + private Case autopsyCase; + + public Case getAutopsyCase() { + return autopsyCase; + } private SleuthkitCase sleuthKitCase; private DrawableDB db; - + public static synchronized ImageGalleryController getDefault() { if (instance == null) { try { @@ -153,71 +158,71 @@ public final class ImageGalleryController { } return instance; } - + public ReadOnlyBooleanProperty getMetaDataCollapsed() { return metaDataCollapsed.getReadOnlyProperty(); } - + public void setMetaDataCollapsed(Boolean metaDataCollapsed) { this.metaDataCollapsed.set(metaDataCollapsed); } - + public ReadOnlyDoubleProperty thumbnailSizeProperty() { return thumbnailSize.getReadOnlyProperty(); } - + public GroupViewState getViewState() { return historyManager.getCurrentState(); } - + public ReadOnlyBooleanProperty regroupDisabled() { return regroupDisabled.getReadOnlyProperty(); } - + public ReadOnlyObjectProperty viewState() { return historyManager.currentState(); } - + public FileIDSelectionModel getSelectionModel() { return selectionModel; } - + public GroupManager getGroupManager() { return groupManager; } - + synchronized public DrawableDB getDatabase() { return db; } - + public void setListeningEnabled(boolean enabled) { synchronized (listeningEnabled) { listeningEnabled.set(enabled); } } - + boolean isListeningEnabled() { synchronized (listeningEnabled) { return listeningEnabled.get(); } } - + @ThreadConfined(type = ThreadConfined.ThreadType.ANY) void setStale(Boolean b) { Platform.runLater(() -> { stale.set(b); }); } - + public ReadOnlyBooleanProperty stale() { return stale.getReadOnlyProperty(); } - + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) boolean isStale() { return stale.get(); } - + private ImageGalleryController() { // listener for the boolean property about when IG is listening / enabled @@ -231,40 +236,40 @@ public final class ImageGalleryController { //populate the db this.rebuildDB(); } - + } catch (NoCurrentCaseException ex) { logger.log(Level.WARNING, "Exception while getting open case.", ex); } }); - + groupManager.getAnalyzedGroups().addListener((Observable o) -> checkForGroups()); - + viewState().addListener((Observable observable) -> { //when the viewed group changes, clear the selection and the undo/redo history selectionModel.clearSelection(); undoManager.clear(); }); - + regroupDisabled.addListener(observable -> checkForGroups()); - + IngestManager ingestManager = IngestManager.getInstance(); PropertyChangeListener ingestEventHandler = propertyChangeEvent -> Platform.runLater(this::updateRegroupDisabled); - + ingestManager.addIngestModuleEventListener(ingestEventHandler); ingestManager.addIngestJobEventListener(ingestEventHandler); - + dbTaskQueueSize.addListener(obs -> this.updateRegroupDisabled()); } - + public ReadOnlyBooleanProperty getCanAdvance() { return historyManager.getCanAdvance(); } - + public ReadOnlyBooleanProperty getCanRetreat() { return historyManager.getCanRetreat(); } - + @ThreadConfined(type = ThreadConfined.ThreadType.ANY) public void advance(GroupViewState newState, boolean forceShowTree) { if (forceShowTree && showTree != null) { @@ -272,15 +277,15 @@ public final class ImageGalleryController { } historyManager.advance(newState); } - + public GroupViewState advance() { return historyManager.advance(); } - + public GroupViewState retreat() { return historyManager.retreat(); } - + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) private void updateRegroupDisabled() { regroupDisabled.set((dbTaskQueueSize.get() > 0) || IngestManager.getInstance().isIngestRunning()); @@ -313,7 +318,7 @@ public final class ImageGalleryController { replaceNotification(fullUIStackPane, new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg1())); } - + } else if (dbTaskQueueSize.get() > 0) { replaceNotification(fullUIStackPane, new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg3(), @@ -333,18 +338,18 @@ public final class ImageGalleryController { } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error counting files in drawable db.", ex); } - + } else if (false == groupManager.isRegrouping()) { replaceNotification(centralStackPane, new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg6())); } - + } else { Platform.runLater(this::clearNotification); } } } - + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) private void clearNotification() { //remove the ingest spinner @@ -356,11 +361,11 @@ public final class ImageGalleryController { centralStackPane.getChildren().remove(infoOverlay); } } - + private void replaceNotification(StackPane stackPane, Node newNode) { Platform.runLater(() -> { clearNotification(); - + infoOverlay = new StackPane(infoOverLayBackground, newNode); if (stackPane != null) { stackPane.getChildren().add(infoOverlay); @@ -379,9 +384,10 @@ public final class ImageGalleryController { if (null == theNewCase) { reset(); } else { + this.autopsyCase = theNewCase; this.sleuthKitCase = theNewCase.getSleuthkitCase(); this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), this); - + setListeningEnabled(ImageGalleryModule.isEnabledforCase(theNewCase)); setStale(ImageGalleryModule.isDrawableDBStale(theNewCase)); @@ -396,7 +402,7 @@ public final class ImageGalleryController { tagsManager.unregisterListener(groupManager); tagsManager.unregisterListener(categoryManager); } - tagsManager = new DrawableTagsManager(theNewCase.getServices().getTagsManager()); + tagsManager = new DrawableTagsManager(this); tagsManager.registerListener(groupManager); tagsManager.registerListener(categoryManager); shutDownDBExecutor(); @@ -420,21 +426,22 @@ public final class ImageGalleryController { */ public synchronized void reset() { logger.info("resetting ImageGalleryControler to initial state."); //NON-NLS + autopsyCase = null; selectionModel.clearSelection(); setListeningEnabled(false); ThumbnailCache.getDefault().clearCache(); historyManager.clear(); groupManager.reset(); - + tagsManager.unregisterListener(groupManager); tagsManager.unregisterListener(categoryManager); tagsManager = null; shutDownDBExecutor(); - + if (toolbar != null) { toolbar.reset(); } - + if (db != null) { db.closeDBCon(); } @@ -460,17 +467,17 @@ public final class ImageGalleryController { * @return list of data source object ids that are stale. */ Set getStaleDataSourceIds() { - + Set staleDataSourceIds = new HashSet<>(); // no current case open to check if ((null == getDatabase()) || (null == getSleuthKitCase())) { return staleDataSourceIds; } - + try { Map knownDataSourceIds = getDatabase().getDataSourceDbBuildStatus(); - + List dataSources = getSleuthKitCase().getDataSources(); Set caseDataSourceIds = new HashSet<>(); dataSources.forEach((dataSource) -> { @@ -491,15 +498,15 @@ public final class ImageGalleryController { staleDataSourceIds.add(id); } }); - + return staleDataSourceIds; } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Image Gallery failed to check if datasources table is stale.", ex); return staleDataSourceIds; } - + } - + synchronized private void shutDownDBExecutor() { if (dbExecutor != null) { dbExecutor.shutdownNow(); @@ -510,7 +517,7 @@ public final class ImageGalleryController { } } } - + private static ListeningExecutorService getNewDBExecutor() { return MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor( new ThreadFactoryBuilder().setNameFormat("DB-Worker-Thread-%d").build())); @@ -527,17 +534,17 @@ public final class ImageGalleryController { } incrementQueueSize(); dbExecutor.submit(bgTask).addListener(this::decrementQueueSize, MoreExecutors.directExecutor()); - + } - + private void incrementQueueSize() { Platform.runLater(() -> dbTaskQueueSize.set(dbTaskQueueSize.get() + 1)); } - + private void decrementQueueSize() { Platform.runLater(() -> dbTaskQueueSize.set(dbTaskQueueSize.get() - 1)); } - + @Nullable synchronized public DrawableFile getFileFromId(Long fileID) throws TskCoreException { if (Objects.isNull(db)) { @@ -546,13 +553,13 @@ public final class ImageGalleryController { } return db.getFileFromID(fileID); } - + public void setStacks(StackPane fullUIStack, StackPane centralStack) { fullUIStackPane = fullUIStack; this.centralStackPane = centralStack; Platform.runLater(this::checkForGroups); } - + public synchronized void setToolbar(Toolbar toolbar) { if (this.toolbar != null) { throw new IllegalStateException("Can not set the toolbar a second time!"); @@ -562,7 +569,7 @@ public final class ImageGalleryController { // RAMAN TBD: bind filterByDataSourceId to the data source dropdown in the toolbar. } - + public ReadOnlyDoubleProperty regroupProgress() { return groupManager.regroupProgress(); } @@ -579,34 +586,34 @@ public final class ImageGalleryController { IngestManager.getInstance().addIngestModuleEventListener(new IngestModuleEventListener()); Case.addPropertyChangeListener(new CaseEventListener()); } - + public HashSetManager getHashSetManager() { return hashSetManager; } - + public CategoryManager getCategoryManager() { return categoryManager; } - + public DrawableTagsManager getTagsManager() { return tagsManager; } - + public void setShowTree(Runnable showTree) { this.showTree = showTree; } - + public UndoRedoManager getUndoManager() { return undoManager; } - + public ReadOnlyIntegerProperty getDBTasksQueueSizeProperty() { return dbTaskQueueSize.getReadOnlyProperty(); } - + public synchronized SleuthkitCase getSleuthKitCase() { return sleuthKitCase; - + } /** @@ -615,56 +622,56 @@ public final class ImageGalleryController { @NbBundle.Messages({"ImageGalleryController.InnerTask.progress.name=progress", "ImageGalleryController.InnerTask.message.name=status"}) static public abstract class BackgroundTask implements Runnable, Cancellable { - + private final SimpleObjectProperty state = new SimpleObjectProperty<>(Worker.State.READY); private final SimpleDoubleProperty progress = new SimpleDoubleProperty(this, Bundle.ImageGalleryController_InnerTask_progress_name()); private final SimpleStringProperty message = new SimpleStringProperty(this, Bundle.ImageGalleryController_InnerTask_message_name()); - + protected BackgroundTask() { } - + public double getProgress() { return progress.get(); } - + public final void updateProgress(Double workDone) { this.progress.set(workDone); } - + public String getMessage() { return message.get(); } - + public final void updateMessage(String Status) { this.message.set(Status); } - + public SimpleDoubleProperty progressProperty() { return progress; } - + public SimpleStringProperty messageProperty() { return message; } - + public Worker.State getState() { return state.get(); } - + public ReadOnlyObjectProperty stateProperty() { return new ReadOnlyObjectWrapper<>(state.get()); } - + @Override public synchronized boolean cancel() { updateState(Worker.State.CANCELLED); return true; } - + protected void updateState(Worker.State newState) { state.set(newState); } - + protected synchronized boolean isCancelled() { return getState() == Worker.State.CANCELLED; } @@ -674,18 +681,18 @@ public final class ImageGalleryController { * Abstract base class for tasks associated with a file in the database */ static abstract class FileTask extends BackgroundTask { - + private final AbstractFile file; private final DrawableDB taskDB; - + public DrawableDB getTaskDB() { return taskDB; } - + public AbstractFile getFile() { return file; } - + public FileTask(AbstractFile f, DrawableDB taskDB) { super(); this.file = f; @@ -697,7 +704,7 @@ public final class ImageGalleryController { * task that updates one file in database with results from ingest */ static private class UpdateFileTask extends FileTask { - + UpdateFileTask(AbstractFile f, DrawableDB taskDB) { super(f, taskDB); } @@ -724,7 +731,7 @@ public final class ImageGalleryController { * task that updates one file in database with results from ingest */ static private class RemoveFileTask extends FileTask { - + RemoveFileTask(AbstractFile f, DrawableDB taskDB) { super(f, taskDB); } @@ -745,7 +752,7 @@ public final class ImageGalleryController { } } } - + @NbBundle.Messages({"BulkTask.committingDb.status=committing image/video database", "BulkTask.stopCopy.status=Stopping copy to drawable db task.", "BulkTask.errPopulating.errMsg=There was an error populating Image Gallery database."}) @@ -754,36 +761,36 @@ public final class ImageGalleryController { * a given data source, into the Image gallery DB. */ abstract static private class BulkTransferTask extends BackgroundTask { - + static private final String FILE_EXTENSION_CLAUSE = "(extension LIKE '" //NON-NLS + String.join("' OR extension LIKE '", FileTypeUtils.getAllSupportedExtensions()) //NON-NLS + "') "; - + static private final String MIMETYPE_CLAUSE = "(mime_type LIKE '" //NON-NLS + String.join("' OR mime_type LIKE '", FileTypeUtils.getAllSupportedMimeTypes()) //NON-NLS + "') "; - + final String DRAWABLE_QUERY; final String DATASOURCE_CLAUSE; - + final ImageGalleryController controller; final DrawableDB taskDB; final SleuthkitCase tskCase; final long dataSourceObjId; - + ProgressHandle progressHandle; private boolean taskCompletionStatus; - + BulkTransferTask(long dataSourceObjId, ImageGalleryController controller, DrawableDB taskDB, SleuthkitCase tskCase) { this.controller = controller; this.taskDB = taskDB; this.tskCase = tskCase; this.dataSourceObjId = dataSourceObjId; - + DATASOURCE_CLAUSE = " (data_source_obj_id = " + dataSourceObjId + ") "; - + DRAWABLE_QUERY = DATASOURCE_CLAUSE + " AND ( " @@ -811,24 +818,24 @@ public final class ImageGalleryController { List getFiles() throws TskCoreException { return tskCase.findAllFilesWhere(DRAWABLE_QUERY); } - + abstract void processFile(final AbstractFile f, DrawableDB.DrawableTransaction tr, CaseDbTransaction caseDBTransaction) throws TskCoreException; - + @Override public void run() { progressHandle = getInitialProgressHandle(); progressHandle.start(); updateMessage(Bundle.CopyAnalyzedFiles_populatingDb_status()); - + DrawableDB.DrawableTransaction drawableDbTransaction = null; CaseDbTransaction caseDbTransaction = null; try { //grab all files with supported extension or detected mime types final List files = getFiles(); progressHandle.switchToDeterminate(files.size()); - + taskDB.insertOrUpdateDataSource(dataSourceObjId, DrawableDB.DrawableDbBuildStatusEnum.IN_PROGRESS); - + updateProgress(0.0); taskCompletionStatus = true; int workDone = 0; @@ -841,27 +848,27 @@ public final class ImageGalleryController { logger.log(Level.WARNING, "Task cancelled or interrupted: not all contents may be transfered to drawable database."); //NON-NLS taskCompletionStatus = false; progressHandle.finish(); - + break; } - + processFile(f, drawableDbTransaction, caseDbTransaction); - + workDone++; progressHandle.progress(f.getName(), workDone); updateProgress(workDone - 1 / (double) files.size()); updateMessage(f.getName()); } - + progressHandle.finish(); progressHandle = ProgressHandle.createHandle(Bundle.BulkTask_committingDb_status()); updateMessage(Bundle.BulkTask_committingDb_status()); updateProgress(1.0); - + progressHandle.start(); caseDbTransaction.commit(); taskDB.commitTransaction(drawableDbTransaction, true); - + } catch (TskCoreException ex) { if (null != drawableDbTransaction) { taskDB.rollbackTransaction(drawableDbTransaction); @@ -889,9 +896,9 @@ public final class ImageGalleryController { } cleanup(taskCompletionStatus); } - + abstract ProgressHandle getInitialProgressHandle(); - + protected void setTaskCompletionStatus(boolean status) { taskCompletionStatus = status; } @@ -908,26 +915,26 @@ public final class ImageGalleryController { "CopyAnalyzedFiles.stopCopy.status=Stopping copy to drawable db task.", "CopyAnalyzedFiles.errPopulating.errMsg=There was an error populating Image Gallery database."}) private class CopyAnalyzedFiles extends BulkTransferTask { - + CopyAnalyzedFiles(long dataSourceObjId, ImageGalleryController controller, DrawableDB taskDB, SleuthkitCase tskCase) { super(dataSourceObjId, controller, taskDB, tskCase); } - + @Override protected void cleanup(boolean success) { // at the end of the task, set the stale status based on the // cumulative status of all data sources controller.setStale(isDataSourcesTableStale()); } - + @Override void processFile(AbstractFile f, DrawableDB.DrawableTransaction tr, CaseDbTransaction caseDbTransaction) throws TskCoreException { final boolean known = f.getKnown() == TskData.FileKnown.KNOWN; - + if (known) { taskDB.removeFile(f.getId(), tr); //remove known files } else { - + try { //supported mimetype => analyzed if (null != f.getMIMEType() && FileTypeUtils.hasDrawableMIMEType(f)) { @@ -947,7 +954,7 @@ public final class ImageGalleryController { } } } - + @Override @NbBundle.Messages({"CopyAnalyzedFiles.populatingDb.status=populating analyzed image/video database",}) ProgressHandle getInitialProgressHandle() { @@ -973,25 +980,25 @@ public final class ImageGalleryController { PrePopulateDataSourceFiles(long dataSourceObjId, ImageGalleryController controller, DrawableDB taskDB, SleuthkitCase tskCase) { super(dataSourceObjId, controller, taskDB, tskCase); } - + @Override protected void cleanup(boolean success) { } - + @Override void processFile(final AbstractFile f, DrawableDB.DrawableTransaction tr, CaseDbTransaction caseDBTransaction) { taskDB.insertFile(DrawableFile.create(f, false, false), tr, caseDBTransaction); } - + @Override @NbBundle.Messages({"PrePopulateDataSourceFiles.prepopulatingDb.status=prepopulating image/video database",}) ProgressHandle getInitialProgressHandle() { return ProgressHandle.createHandle(Bundle.PrePopulateDataSourceFiles_prepopulatingDb_status(), this); } } - + private class IngestModuleEventListener implements PropertyChangeListener { - + @Override public void propertyChange(PropertyChangeEvent evt) { if (RuntimeProperties.runningWithGUI() == false) { @@ -1022,7 +1029,7 @@ public final class ImageGalleryController { * getOldValue has fileID getNewValue has * {@link Abstractfile} */ - + AbstractFile file = (AbstractFile) evt.getNewValue(); // only process individual files in realtime on the node that is running the ingest @@ -1053,9 +1060,9 @@ public final class ImageGalleryController { } } } - + private class CaseEventListener implements PropertyChangeListener { - + @Override public void propertyChange(PropertyChangeEvent evt) { if (RuntimeProperties.runningWithGUI() == false) { @@ -1092,7 +1099,7 @@ public final class ImageGalleryController { } } break; - + case CONTENT_TAG_ADDED: final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) evt; if (getDatabase().isInDB(tagAddedEvent.getAddedTag().getContent().getId())) { @@ -1113,7 +1120,7 @@ public final class ImageGalleryController { * Listener for Ingest Job events. */ private class IngestJobEventListener implements PropertyChangeListener { - + @NbBundle.Messages({ "ImageGalleryController.dataSourceAnalyzed.confDlg.msg= A new data source was added and finished ingest.\n" + "The image / video database may be out of date. " @@ -1128,15 +1135,15 @@ public final class ImageGalleryController { // A remote node added a new data source and just finished ingest on it. //drawable db is stale, and if ImageGallery is open, ask user what to do setStale(true); - + SwingUtilities.invokeLater(() -> { if (isListeningEnabled() && ImageGalleryTopComponent.isImageGalleryOpen()) { - + int answer = JOptionPane.showConfirmDialog(ImageGalleryTopComponent.getTopComponent(), Bundle.ImageGalleryController_dataSourceAnalyzed_confDlg_msg(), Bundle.ImageGalleryController_dataSourceAnalyzed_confDlg_title(), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); - + switch (answer) { case JOptionPane.YES_OPTION: rebuildDB(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java index c183116e0f..c7c3d707b0 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java @@ -34,6 +34,7 @@ import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.DhsImageCategory; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; @@ -58,7 +59,7 @@ public final class DrawableTagsManager { private final TagName bookmarkTagName; /** - * Used to distribute {@link TagsChangeEvent}s + * Used to distribute TagsChangeEvents */ private final EventBus tagsEventBus = new AsyncEventBus( @@ -70,10 +71,10 @@ public final class DrawableTagsManager { }) .build())); - public DrawableTagsManager(TagsManager autopsyTagsManager) throws TskCoreException { - this.autopsyTagsManager = autopsyTagsManager; - followUpTagName = getTagName(NbBundle.getMessage(DrawableTagsManager.class, "DrawableTagsManager.followUp")); - bookmarkTagName = getTagName(NbBundle.getMessage(DrawableTagsManager.class, "DrawableTagsManager.bookMark")); + public DrawableTagsManager(ImageGalleryController controller) throws TskCoreException { + this.autopsyTagsManager = controller.getAutopsyCase().getServices().getTagsManager(); + followUpTagName = getTagName(Bundle.DrawableTagsManager_followUp()); + bookmarkTagName = getTagName(Bundle.DrawableTagsManager_bookMark()); } /** @@ -125,6 +126,8 @@ public final class DrawableTagsManager { * * @return All the TagNames that are not categories, in alphabetical order * by displayName. + * + * @throws org.sleuthkit.datamodel.TskCoreException */ public List getNonCategoryTagNames() throws TskCoreException {