From 13ad8aaaeb07bcdb55cf209f55e0d0ffd2d6829d Mon Sep 17 00:00:00 2001 From: jmillman Date: Fri, 19 Jun 2015 17:20:35 -0400 Subject: [PATCH] remove uneeded notification code; let event handlers do it all. optionalize DrawableView --- Core/nbproject/project.xml | 1 + .../actions/AddDrawableTagAction.java | 3 - .../actions/CategorizeAction.java | 33 +- .../actions/DeleteFollowUpTagAction.java | 11 +- .../datamodel/CategoryManager.java | 3 +- .../imagegallery/grouping/GroupManager.java | 26 +- .../imagegallery/gui/DrawableTile.java | 16 +- .../imagegallery/gui/DrawableView.java | 13 +- .../imagegallery/gui/DrawableViewBase.java | 301 ++++++++++-------- .../imagegallery/gui/MetaDataPane.java | 114 ++++--- .../imagegallery/gui/SlideShowView.java | 81 +++-- 11 files changed, 341 insertions(+), 261 deletions(-) diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index ac5f32a1ac..463e1c1903 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -192,6 +192,7 @@ org.sleuthkit.autopsy.coreutils org.sleuthkit.autopsy.datamodel org.sleuthkit.autopsy.directorytree + org.sleuthkit.autopsy.events org.sleuthkit.autopsy.externalresults org.sleuthkit.autopsy.filesearch org.sleuthkit.autopsy.ingest diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java index be9343f4de..3c115d9134 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java @@ -82,9 +82,6 @@ public class AddDrawableTagAction extends AddTagAction { LOGGER.log(Level.SEVERE, "Error tagging result", ex); JOptionPane.showMessageDialog(null, "Unable to tag " + fileID + ".", "Tagging Error", JOptionPane.ERROR_MESSAGE); } - -// //make sure rest of ui hears category change. -// controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } return null; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 067a5cf967..afe2b3bb5d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -19,7 +19,6 @@ package org.sleuthkit.autopsy.imagegallery.actions; import java.util.HashSet; -import java.util.List; import java.util.Set; import java.util.logging.Level; import javafx.event.ActionEvent; @@ -34,11 +33,7 @@ import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; -import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -127,33 +122,25 @@ public class CategorizeAction extends AddTagAction { @Override public void run() { - final GroupManager groupManager = controller.getGroupManager(); final CategoryManager categoryManager = controller.getCategoryManager(); final DrawableTagsManager tagsManager = controller.getTagsManager(); try { DrawableFile file = controller.getFileFromId(fileID); //drawable db - Category oldCat = file.getCategory(); - // remove file from old category group - groupManager.removeFromGroup(new GroupKey(DrawableAttribute.CATEGORY, oldCat), fileID); //memory - - //remove old category tag if necessary - List allContentTags = tagsManager.getContentTagsByContent(file); //tsk db - - //JMTODO: move this to CategoryManager - for (ContentTag ct : allContentTags) { - if (CategoryManager.isCategoryTagName(ct.getName())) { - tagsManager.deleteContentTag(ct); //tsk db -// categoryManager.decrementCategoryCount(Category.fromDisplayName(ct.getName().getDisplayName())); //memory/drawable db - } - } -// categoryManager.incrementCategoryCount(Category.fromDisplayName(tagName.getDisplayName())); //memory/drawable db if (tagName != categoryManager.getTagName(Category.ZERO)) { // no tags for cat-0 tagsManager.addContentTag(file, tagName, comment); //tsk db + } else { + tagsManager.getContentTagsByContent(file).stream() + .filter(tag -> CategoryManager.isCategoryTagName(tag.getName())) + .forEach((ct) -> { + try { + tagsManager.deleteContentTag(ct); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Error removing old categories result", ex); + } + }); } -// //make sure rest of ui hears category change. -// groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); //memory/ui } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error categorizing result", ex); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index aab8a9c827..74082fcd1c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -26,10 +26,7 @@ import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -50,23 +47,17 @@ public class DeleteFollowUpTagAction extends Action { @Override protected Void doInBackground() throws Exception { - final GroupManager groupManager = controller.getGroupManager(); final DrawableTagsManager tagsManager = controller.getTagsManager(); try { final TagName followUpTagName = tagsManager.getFollowUpTagName(); - // remove file from old category group - groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, followUpTagName), fileID); - + List contentTagsByContent = tagsManager.getContentTagsByContent(file); for (ContentTag ct : contentTagsByContent) { if (ct.getName().getDisplayName().equals(followUpTagName.getDisplayName())) { tagsManager.deleteContentTag(ct); } } - - //make sure rest of ui hears category change. -// groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index b6a11d2b25..466278f588 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -224,6 +224,7 @@ public class CategoryManager { } + @Subscribe public void handleTagAdded(ContentTagAddedEvent event) { ContentTag addedTag = event.getAddedTag(); if (isCategoryTagName(addedTag.getName())) { @@ -253,7 +254,7 @@ public class CategoryManager { fireChange(Collections.singleton(addedTag.getId()), newCat); } } - + @Subscribe public void handleTagDeleted(ContentTagDeletedEvent event) { ContentTag deleted = event.getDeletedTag(); if (isCategoryTagName(deleted.getName())) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 733baf2813..9ac899742c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -279,8 +279,12 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { if (groupKey.getAttribute() != DrawableAttribute.CATEGORY) { if (group.fileIds().isEmpty()) { Platform.runLater(() -> { - analyzedGroups.remove(group); - unSeenGroups.remove(group); + if (analyzedGroups.contains(group)) { + analyzedGroups.remove(group); + } + if (unSeenGroups.contains(group)) { + unSeenGroups.remove(group); + } }); } } @@ -535,10 +539,12 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { @Subscribe public void handleTagAdded(ContentTagAddedEvent evt) { - final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getAddedTag().getName()); - final long fileID = evt.getAddedTag().getContent().getId(); - DrawableGroup g = getGroupForKey(groupKey); - addFileToGroup(g, groupKey, fileID); + if (groupBy == DrawableAttribute.TAGS || groupBy == DrawableAttribute.CATEGORY) { + final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getAddedTag().getName()); + final long fileID = evt.getAddedTag().getContent().getId(); + DrawableGroup g = getGroupForKey(groupKey); + addFileToGroup(g, groupKey, fileID); + } } @@ -554,9 +560,11 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { @Subscribe public void handleTagDeleted(ContentTagDeletedEvent evt) { - final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getDeletedTag().getName()); - final long fileID = evt.getDeletedTag().getContent().getId(); - DrawableGroup g = removeFromGroup(groupKey, fileID); + if (groupBy == DrawableAttribute.TAGS || groupBy == DrawableAttribute.CATEGORY) { + final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getDeletedTag().getName()); + final long fileID = evt.getDeletedTag().getContent().getId(); + DrawableGroup g = removeFromGroup(groupKey, fileID); + } } @Override diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java index 75332ba158..96f05dd9c1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java @@ -33,6 +33,7 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import static org.sleuthkit.autopsy.imagegallery.gui.DrawableViewBase.globalSelectionModel; +import org.sleuthkit.datamodel.AbstractContent; /** * GUI component that represents a single image as a tile with an icon, a label, @@ -109,15 +110,20 @@ public class DrawableTile extends DrawableViewBase { @Override protected Runnable getContentUpdateRunnable() { - Image image = getFile().getThumbnail(); + if (getFile().isPresent()) { + Image image = getFile().get().getThumbnail(); - return () -> { - imageView.setImage(image); - }; + return () -> { + imageView.setImage(image); + }; + } else { + return () -> { //no-op + }; + } } @Override protected String getTextForLabel() { - return getFile().getName(); + return getFile().map(AbstractContent::getName).orElse(""); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java index 9b442273d1..e4e6faf1de 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java @@ -1,6 +1,8 @@ package org.sleuthkit.autopsy.imagegallery.gui; import com.google.common.eventbus.Subscribe; +import java.util.Collection; +import java.util.Optional; import java.util.logging.Level; import javafx.application.Platform; import javafx.scene.layout.Border; @@ -51,11 +53,11 @@ public interface DrawableView { Region getCategoryBorderRegion(); - DrawableFile getFile(); + Optional> getFile(); void setFile(final Long fileID); - Long getFileID(); + Optional getFileID(); /** * update the visual representation of the category of the assigned file. @@ -78,7 +80,10 @@ public interface DrawableView { default boolean hasHashHit() { try { - return getFile().getHashHitSetNames().isEmpty() == false; + return getFile().map(DrawableFile::getHashHitSetNames) + .map((Collection t) -> t.isEmpty() == false) + .orElse(false); + } catch (NullPointerException ex) { // I think this happens when we're in the process of removing images from the view while // also trying to update it? @@ -113,7 +118,7 @@ public interface DrawableView { @ThreadConfined(type = ThreadConfined.ThreadType.ANY) default Category updateCategoryBorder() { if (getFile() != null) { - final Category category = getFile().getCategory(); + final Category category = getFile().map(DrawableFile::getCategory).orElse(Category.ZERO); final Border border = hasHashHit() && (category == Category.ZERO) ? HASH_BORDER : getCategoryBorder(category); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index ea88d2dfbb..a1ee32a108 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -23,6 +23,8 @@ import com.google.common.eventbus.Subscribe; import java.util.ArrayList; import java.util.Collection; import java.util.Objects; +import static java.util.Objects.nonNull; +import java.util.Optional; import java.util.logging.Level; import javafx.application.Platform; import javafx.beans.Observable; @@ -130,9 +132,33 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie static private ContextMenu contextMenu; - private DrawableFile file; + volatile private Optional> fileOpt = Optional.empty(); - private Long fileID; + volatile private Optional fileIDOpt = Optional.empty(); + + @Override + public Optional getFileID() { + return fileIDOpt; + } + + @Override + public Optional> getFile() { + if (fileIDOpt.isPresent()) { + if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { + return fileOpt; + } else { + try { + fileOpt = Optional.of(ImageGalleryController.getDefault().getFileFromId(fileIDOpt.get())); + } catch (TskCoreException ex) { + Logger.getAnonymousLogger().log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileIDOpt.get(), ex); + fileOpt = Optional.empty(); + } + return fileOpt; + } + } else { + return Optional.empty(); + } + } /** * the groupPane this {@link DrawableViewBase} is embedded in @@ -158,43 +184,44 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Override public void handle(MouseEvent t) { + getFile().ifPresent(file -> { + final long fileID = file.getId(); + switch (t.getButton()) { + case PRIMARY: + if (t.getClickCount() == 1) { + if (t.isControlDown()) { - switch (t.getButton()) { - case PRIMARY: - if (t.getClickCount() == 1) { - if (t.isControlDown()) { - globalSelectionModel.toggleSelection(fileID); - } else { - groupPane.makeSelection(t.isShiftDown(), fileID); + globalSelectionModel.toggleSelection(fileID); + } else { + groupPane.makeSelection(t.isShiftDown(), fileID); + } + } else if (t.getClickCount() > 1) { + groupPane.activateSlideShowViewer(fileID); } - } else if (t.getClickCount() > 1) { - groupPane.activateSlideShowViewer(fileID); - } - break; - case SECONDARY: - - if (t.getClickCount() == 1) { - if (globalSelectionModel.isSelected(fileID) == false) { - groupPane.makeSelection(false, fileID); + break; + case SECONDARY: + if (t.getClickCount() == 1) { + if (globalSelectionModel.isSelected(fileID) == false) { + groupPane.makeSelection(false, fileID); + } } - } + if (contextMenu != null) { + contextMenu.hide(); + } + final ContextMenu groupContextMenu = groupPane.getContextMenu(); + if (groupContextMenu != null) { + groupContextMenu.hide(); + } + contextMenu = buildContextMenu(file); + contextMenu.show(DrawableViewBase.this, t.getScreenX(), t.getScreenY()); + break; + } + }); - if (contextMenu != null) { - contextMenu.hide(); - } - final ContextMenu groupContextMenu = groupPane.getContextMenu(); - if (groupContextMenu != null) { - groupContextMenu.hide(); - } - contextMenu = buildContextMenu(); - contextMenu.show(DrawableViewBase.this, t.getScreenX(), t.getScreenY()); - - break; - } t.consume(); } - private ContextMenu buildContextMenu() { + private ContextMenu buildContextMenu(DrawableFile file) { final ArrayList menuItems = new ArrayList<>(); menuItems.add(new CategorizeAction(controller).getPopupMenu()); @@ -213,13 +240,13 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie MenuItem contentViewer = new MenuItem("Show Content Viewer"); contentViewer.setOnAction((ActionEvent t) -> { SwingUtilities.invokeLater(() -> { - new NewWindowViewAction("Show Content Viewer", new FileNode(getFile().getAbstractFile())).actionPerformed(null); + new NewWindowViewAction("Show Content Viewer", new FileNode(file.getAbstractFile())).actionPerformed(null); }); }); menuItems.add(contentViewer); MenuItem externalViewer = new MenuItem("Open in External Viewer"); - final ExternalViewerAction externalViewerAction = new ExternalViewerAction("Open in External Viewer", new FileNode(getFile().getAbstractFile())); + final ExternalViewerAction externalViewerAction = new ExternalViewerAction("Open in External Viewer", new FileNode(file.getAbstractFile())); externalViewer.setDisable(externalViewerAction.isEnabled() == false); externalViewer.setOnAction((ActionEvent t) -> { @@ -259,116 +286,106 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @SuppressWarnings("deprecation") protected void initialize() { followUpToggle.setOnAction((ActionEvent event) -> { - if (followUpToggle.isSelected() == true) { - try { - final TagName followUpTagName = controller.getTagsManager().getFollowUpTagName(); - globalSelectionModel.clearAndSelect(fileID); - new AddDrawableTagAction(controller).addTag(followUpTagName, ""); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); + getFile().ifPresent(file -> { + if (followUpToggle.isSelected() == true) { + try { + final TagName followUpTagName = controller.getTagsManager().getFollowUpTagName(); + globalSelectionModel.clearAndSelect(file.getId()); + new AddDrawableTagAction(controller).addTag(followUpTagName, ""); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); + } + } else { + new DeleteFollowUpTagAction(controller, file).handle(event); } - } else { - new DeleteFollowUpTagAction(controller, file).handle(event); - } + }); }); } - @Override - public DrawableFile getFile() { - if (fileID != null) { - if (file == null || file.getId() != fileID) { - try { - file = ImageGalleryController.getDefault().getFileFromId(fileID); - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileID, ex); - file = null; - } - } - return file; - } else { - return null; - } - } - - protected boolean hasFollowUp() throws TskCoreException { - String followUpTagName = getController().getTagsManager().getFollowUpTagName().getDisplayName(); - Collection tagNames = DrawableAttribute.TAGS.getValue(getFile()); - return tagNames.stream().anyMatch((tn) -> tn.getDisplayName().equals(followUpTagName)); - } - - @Override - synchronized public Long getFileID() { - return fileID; - } - - synchronized protected void updateFollowUpIcon() { - if (file != null) { + protected boolean hasFollowUp() { + if (getFile().isPresent()) { try { - boolean hasFollowUp = hasFollowUp(); - Platform.runLater(() -> { - followUpImageView.setImage(hasFollowUp ? followUpIcon : followUpGray); - followUpToggle.setSelected(hasFollowUp); - }); + TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); + Collection tagNames = DrawableAttribute.TAGS.getValue(getFile().get()); + return tagNames.stream().anyMatch((tn) -> tn.equals(followUpTagName)); } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); + LOGGER.log(Level.WARNING, "failed to get follow up tag name ", ex); + return true; } + } else { + return false; } } @Override - synchronized public void setFile(final Long fileID) { - if (Objects.equals(fileID, this.fileID) == false) { - this.fileID = fileID; - disposeContent(); - - if (this.fileID == null || Case.isCaseOpen() == false) { - if (registered == true) { - getController().getCategoryManager().unregisterListener(this); - getController().getTagsManager().unregisterListener(this); - registered = false; - } - file = null; - Platform.runLater(() -> { - clearContent(); - }); - } else { - if (registered == false) { - getController().getCategoryManager().registerListener(this); - getController().getTagsManager().registerListener(this); - registered = true; - } - file = null; - getFile(); - updateSelectionState(); - updateCategoryBorder(); - updateFollowUpIcon(); - updateUI(); - Platform.runLater(getContentUpdateRunnable()); + public void setFile(final Long newFileID) { + if (fileIDOpt.isPresent()) { + if (Objects.equals(newFileID, fileIDOpt.get()) == false) { + setFileHelper(newFileID); } + } else { + if (nonNull(newFileID)) { + setFileHelper(newFileID); + } + } + } + + private void setFileHelper(final Long newFileID) { + fileIDOpt = Optional.ofNullable(newFileID); + disposeContent(); + + if (fileIDOpt.isPresent() == false || Case.isCaseOpen() == false) { + if (registered == true) { + getController().getCategoryManager().unregisterListener(this); + getController().getTagsManager().unregisterListener(this); + registered = false; + } + fileOpt = Optional.empty(); + Platform.runLater(() -> { + clearContent(); + }); + } else { + if (registered == false) { + getController().getCategoryManager().registerListener(this); + getController().getTagsManager().registerListener(this); + registered = true; + } + fileOpt = Optional.empty(); + + updateSelectionState(); + updateCategoryBorder(); + updateFollowUpIcon(); + updateUI(); + Platform.runLater(getContentUpdateRunnable()); } } private void updateUI() { - final boolean isVideo = getFile().isVideo(); - final boolean hasHashSetHits = hasHashHit(); - final String text = getTextForLabel(); + getFile().ifPresent(file -> { + final boolean isVideo = file.isVideo(); + final boolean hasHashSetHits = hasHashHit(); + final String text = getTextForLabel(); - Platform.runLater(() -> { - fileTypeImageView.setImage(isVideo ? videoIcon : null); - hashHitImageView.setImage(hasHashSetHits ? hashHitIcon : null); - nameLabel.setText(text); - nameLabel.setTooltip(new Tooltip(text)); + Platform.runLater(() -> { + fileTypeImageView.setImage(isVideo ? videoIcon : null); + hashHitImageView.setImage(hasHashSetHits ? hashHitIcon : null); + nameLabel.setText(text); + nameLabel.setTooltip(new Tooltip(text)); + }); }); + } /** * update the visual representation of the selection state of this * DrawableView */ - synchronized protected void updateSelectionState() { - final boolean selected = globalSelectionModel.isSelected(getFileID()); - Platform.runLater(() -> { - setBorder(selected ? SELECTED_BORDER : UNSELECTED_BORDER); + protected void updateSelectionState() { + getFile().ifPresent(file -> { + final boolean selected = globalSelectionModel.isSelected(file.getId()); + Platform.runLater(() -> { + setBorder(selected ? SELECTED_BORDER : UNSELECTED_BORDER); + }); }); } @@ -380,22 +397,54 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Subscribe @Override public void handleTagAdded(ContentTagAddedEvent evt) { + fileIDOpt.ifPresent(fileID -> { + try { + if (fileID == evt.getAddedTag().getContent().getId() + && evt.getAddedTag().getName() == getController().getTagsManager().getFollowUpTagName()) { - updateFollowUpIcon(); + Platform.runLater(() -> { + followUpImageView.setImage(followUpIcon); + followUpToggle.setSelected(true); + }); + } + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); + } + }); } @Subscribe @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { - updateFollowUpIcon(); + + fileIDOpt.ifPresent(fileID -> { + try { + if (fileID == evt.getDeletedTag().getContent().getId() + && evt.getDeletedTag().getName() == controller.getTagsManager().getFollowUpTagName()) { + updateFollowUpIcon(); + } + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); + } + }); + } + + private void updateFollowUpIcon() { + boolean hasFollowUp = hasFollowUp(); + Platform.runLater(() -> { + followUpImageView.setImage(hasFollowUp ? followUpIcon : followUpGray); + followUpToggle.setSelected(hasFollowUp); + }); } @Subscribe @Override - synchronized public void handleCategoryChanged(CategoryChangeEvent evt) { - if (fileID != null && evt.getFileIDs().contains(getFileID())) { - updateCategoryBorder(); - } + public void handleCategoryChanged(CategoryChangeEvent evt) { + fileIDOpt.ifPresent(fileID -> { + if (evt.getFileIDs().contains(fileID)) { + updateCategoryBorder(); + } + }); } @Override diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index 0681d29eb9..87bd64491f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -22,6 +22,9 @@ import com.google.common.eventbus.Subscribe; import java.io.IOException; import java.util.Arrays; import java.util.Collection; +import java.util.Objects; +import static java.util.Objects.nonNull; +import java.util.Optional; import java.util.logging.Level; import java.util.stream.Collectors; import javafx.application.Platform; @@ -68,8 +71,6 @@ public class MetaDataPane extends AnchorPane implements DrawableView { return controller; } - private Long fileID; - @FXML private ImageView imageView; @@ -85,13 +86,6 @@ public class MetaDataPane extends AnchorPane implements DrawableView { @FXML private BorderPane imageBorder; - private DrawableFile file; - - @Override - public Long getFileID() { - return fileID; - } - @FXML @SuppressWarnings("unchecked") void initialize() { @@ -152,29 +146,52 @@ public class MetaDataPane extends AnchorPane implements DrawableView { }); } + volatile private Optional> fileOpt = Optional.empty(); + + volatile private Optional fileIDOpt = Optional.empty(); + @Override - public DrawableFile getFile() { - if (fileID != null) { - if (file == null || file.getId() != fileID) { - try { - file = controller.getFileFromId(fileID); - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileID, ex); - return null; - } - } - } else { - return null; - } - return file; + public Optional getFileID() { + return fileIDOpt; } @Override - public void setFile(Long fileID) { - this.fileID = fileID; + public Optional> getFile() { + if (fileIDOpt.isPresent()) { + if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { + return fileOpt; + } else { + try { + fileOpt = Optional.of(ImageGalleryController.getDefault().getFileFromId(fileIDOpt.get())); + } catch (TskCoreException ex) { + Logger.getAnonymousLogger().log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileIDOpt.get(), ex); + fileOpt = Optional.empty(); + } + return fileOpt; + } + } else { + return Optional.empty(); + } + } - if (fileID == null) { + @Override + public void setFile(Long newFileID) { + if (fileIDOpt.isPresent()) { + if (Objects.equals(newFileID, fileIDOpt.get()) == false) { + setFileHelper(newFileID); + } + } else { + if (nonNull(newFileID)) { + setFileHelper(newFileID); + } + } + setFileHelper(newFileID); + } + + private void setFileHelper(Long newFileID) { + fileIDOpt = Optional.of(newFileID); + if (newFileID == null) { Platform.runLater(() -> { imageView.setImage(null); tableView.getItems().clear(); @@ -182,12 +199,7 @@ public class MetaDataPane extends AnchorPane implements DrawableView { }); } else { - try { - file = controller.getFileFromId(fileID); - updateUI(); - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "Failed to get drawable file from ID", ex); - } + updateUI(); } } @@ -206,15 +218,18 @@ public class MetaDataPane extends AnchorPane implements DrawableView { } public void updateUI() { - final Image icon = getFile().getThumbnail(); - final ObservableList, ? extends Object>> attributesList = getFile().getAttributesList(); + getFile().ifPresent(file -> { + final Image icon = file.getThumbnail(); + final ObservableList, ? extends Object>> attributesList = file.getAttributesList(); - Platform.runLater(() -> { - imageView.setImage(icon); - tableView.getItems().setAll(attributesList); + Platform.runLater(() -> { + imageView.setImage(icon); + tableView.getItems().setAll(attributesList); + }); + + updateCategoryBorder(); }); - updateCategoryBorder(); } @Override @@ -226,23 +241,28 @@ public class MetaDataPane extends AnchorPane implements DrawableView { @Subscribe @Override public void handleCategoryChanged(CategoryChangeEvent evt) { - if (getFile() != null && evt.getFileIDs().contains(getFileID())) { - updateUI(); - } + getFileID().ifPresent(fileID -> { + if (evt.getFileIDs().contains(fileID)) { + updateUI(); + } + }); } @Override public void handleTagAdded(ContentTagAddedEvent evt) { - if (getFile() != null && evt.getAddedTag().getContent().getId() == getFileID()) { - updateUI(); - } + handleTagChanged(evt.getAddedTag().getContent().getId()); } @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { - if (getFile() != null && evt.getDeletedTag().getContent().getId() == getFileID()) { - updateUI(); - } + handleTagChanged(evt.getDeletedTag().getContent().getId()); } + private void handleTagChanged(Long tagFileID) { + getFileID().ifPresent(fileID -> { + if (Objects.equals(tagFileID, fileID)) { + updateUI(); + } + }); + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java index 7977eb0219..ab74554b39 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.imagegallery.gui; import java.util.ArrayList; +import java.util.function.Function; import java.util.logging.Level; import javafx.application.Platform; import javafx.beans.Observable; @@ -48,14 +49,15 @@ import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.ImageFile; import org.sleuthkit.autopsy.imagegallery.datamodel.VideoFile; +import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.CAT_BORDER_WIDTH; import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.HASH_BORDER; import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.getCategoryBorder; import org.sleuthkit.datamodel.TagName; @@ -235,9 +237,9 @@ public class SlideShowView extends DrawableViewBase { @Override synchronized public void setFile(final Long fileID) { super.setFile(fileID); - if (this.getFileID() != null) { - getGroupPane().makeSelection(false, this.getFileID()); - } + getFileID().ifPresent((Long id) -> { + getGroupPane().makeSelection(false, id); + }); } @Override @@ -254,24 +256,33 @@ public class SlideShowView extends DrawableViewBase { @Override protected Runnable getContentUpdateRunnable() { - if (getFile().isVideo()) { - return () -> { - imageBorder.setCenter(MediaControl.create((VideoFile) getFile())); - }; - } else { - ImageView imageView = new ImageView(((ImageFile) getFile()).getFullSizeImage()); - imageView.setPreserveRatio(true); - imageView.fitWidthProperty().bind(imageBorder.widthProperty().subtract(CAT_BORDER_WIDTH * 2)); - imageView.fitHeightProperty().bind(this.heightProperty().subtract(CAT_BORDER_WIDTH * 4).subtract(footer.heightProperty()).subtract(toolBar.heightProperty())); - return () -> { - imageBorder.setCenter(imageView); - }; - } + + return getFile().map(new Function, Runnable>() { + + @Override + public Runnable apply(DrawableFile file) { + + if (file.isVideo()) { + return () -> { + imageBorder.setCenter(MediaControl.create((VideoFile) file)); + }; + } else { + ImageView imageView = new ImageView(((ImageFile) file).getFullSizeImage()); + imageView.setPreserveRatio(true); + imageView.fitWidthProperty().bind(imageBorder.widthProperty().subtract(CAT_BORDER_WIDTH * 2)); + imageView.fitHeightProperty().bind(heightProperty().subtract(CAT_BORDER_WIDTH * 4).subtract(footer.heightProperty()).subtract(toolBar.heightProperty())); + return () -> { + imageBorder.setCenter(imageView); + }; + } + } + }).orElse(() -> { + }); } @Override protected String getTextForLabel() { - return getFile().getName() + " " + getSupplementalText(); + return getFile().map(file -> file.getName() + " " + getSupplementalText()).orElse(""); } @ThreadConfined(type = ThreadType.JFX) @@ -302,18 +313,19 @@ public class SlideShowView extends DrawableViewBase { @Override @ThreadConfined(type = ThreadType.ANY) public Category updateCategoryBorder() { - final Category category = getFile().getCategory(); - final Border border = hasHashHit() && (category == Category.ZERO) - ? HASH_BORDER - : getCategoryBorder(category); - ToggleButton toggleForCategory = getToggleForCategory(category); + return getFile().map(file -> { + final Category category = file.getCategory(); + final Border border1 = hasHashHit() && (category == Category.ZERO) + ? HASH_BORDER + : getCategoryBorder(category); + ToggleButton toggleForCategory = getToggleForCategory(category); + Platform.runLater(() -> { + getCategoryBorderRegion().setBorder(border1); + toggleForCategory.setSelected(true); + }); + return category; + }).orElse(Category.ZERO); - Platform.runLater(() -> { - getCategoryBorderRegion().setBorder(border); - toggleForCategory.setSelected(true); - }); - - return category; } private ToggleButton getToggleForCategory(Category category) { @@ -345,10 +357,13 @@ public class SlideShowView extends DrawableViewBase { @Override public void changed(ObservableValue ov, Boolean t, Boolean t1) { - if (t1) { - FileIDSelectionModel.getInstance().clearAndSelect(getFileID()); - new CategorizeAction(getController()).addTag(getController().getTagsManager().getTagName(cat), ""); - } + getFileID().ifPresent(fileID -> { + if (t1) { + FileIDSelectionModel.getInstance().clearAndSelect(fileID); + new CategorizeAction(getController()).addTag(getController().getTagsManager().getTagName(cat), ""); + } + }); + } } }