This commit is contained in:
millmanorama 2018-09-03 17:32:39 +02:00
parent 49dfc6ae4b
commit f8cdcc7f4d
11 changed files with 318 additions and 269 deletions

View File

@ -60,6 +60,7 @@ import javax.swing.JOptionPane;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandle;
import org.openide.util.Cancellable; import org.openide.util.Cancellable;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.casemodule.Case.CaseType;
@ -123,7 +124,7 @@ public final class ImageGalleryController {
private final GroupManager groupManager = new GroupManager(this); private final GroupManager groupManager = new GroupManager(this);
private final HashSetManager hashSetManager = new HashSetManager(); private final HashSetManager hashSetManager = new HashSetManager();
private final CategoryManager categoryManager = new CategoryManager(this); private final CategoryManager categoryManager = new CategoryManager(this);
private final DrawableTagsManager tagsManager = new DrawableTagsManager(null); private DrawableTagsManager tagsManager;
private Runnable showTree; private Runnable showTree;
private Toolbar toolbar; private Toolbar toolbar;
@ -144,7 +145,11 @@ public final class ImageGalleryController {
public static synchronized ImageGalleryController getDefault() { public static synchronized ImageGalleryController getDefault() {
if (instance == null) { if (instance == null) {
try {
instance = new ImageGalleryController(); instance = new ImageGalleryController();
} catch (NoClassDefFoundError error) {
Exceptions.printStackTrace(error);
}
} }
return instance; return instance;
} }
@ -367,8 +372,10 @@ public final class ImageGalleryController {
* configure the controller for a specific case. * configure the controller for a specific case.
* *
* @param theNewCase the case to configure the controller for * @param theNewCase the case to configure the controller for
*
* @throws org.sleuthkit.datamodel.TskCoreException
*/ */
public synchronized void setCase(Case theNewCase) { public synchronized void setCase(Case theNewCase) throws TskCoreException {
if (null == theNewCase) { if (null == theNewCase) {
reset(); reset();
} else { } else {
@ -384,7 +391,9 @@ public final class ImageGalleryController {
groupManager.reset(); groupManager.reset();
hashSetManager.setDb(db); hashSetManager.setDb(db);
categoryManager.setDb(db); categoryManager.setDb(db);
tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); tagsManager.unregisterListener(groupManager);
tagsManager.unregisterListener(categoryManager);
tagsManager = new DrawableTagsManager(theNewCase.getServices().getTagsManager());
tagsManager.registerListener(groupManager); tagsManager.registerListener(groupManager);
tagsManager.registerListener(categoryManager); tagsManager.registerListener(categoryManager);
shutDownDBExecutor(); shutDownDBExecutor();
@ -413,9 +422,10 @@ public final class ImageGalleryController {
ThumbnailCache.getDefault().clearCache(); ThumbnailCache.getDefault().clearCache();
historyManager.clear(); historyManager.clear();
groupManager.reset(); groupManager.reset();
tagsManager.clearFollowUpTagName();
tagsManager.unregisterListener(groupManager); tagsManager.unregisterListener(groupManager);
tagsManager.unregisterListener(categoryManager); tagsManager.unregisterListener(categoryManager);
tagsManager = null;
shutDownDBExecutor(); shutDownDBExecutor();
if (toolbar != null) { if (toolbar != null) {
@ -860,6 +870,7 @@ public final class ImageGalleryController {
logger.log(Level.SEVERE, "Error in trying to rollback transaction", ex2); //NON-NLS logger.log(Level.SEVERE, "Error in trying to rollback transaction", ex2); //NON-NLS
} }
} }
progressHandle.progress(Bundle.BulkTask_stopCopy_status()); progressHandle.progress(Bundle.BulkTask_stopCopy_status());
logger.log(Level.WARNING, "Stopping copy to drawable db task. Failed to transfer all database contents", ex); //NON-NLS logger.log(Level.WARNING, "Stopping copy to drawable db task. Failed to transfer all database contents", ex); //NON-NLS
MessageNotifyUtil.Notify.warn(Bundle.BulkTask_errPopulating_errMsg(), ex.getMessage()); MessageNotifyUtil.Notify.warn(Bundle.BulkTask_errPopulating_errMsg(), ex.getMessage());
@ -1060,8 +1071,13 @@ public final class ImageGalleryController {
//close window, reset everything //close window, reset everything
SwingUtilities.invokeLater(ImageGalleryTopComponent::closeTopComponent); SwingUtilities.invokeLater(ImageGalleryTopComponent::closeTopComponent);
reset(); reset();
} else { // a new case has been opened } else {
try {
// a new case has been opened
setCase(newCase); //connect db, groupmanager, start worker thread setCase(newCase); //connect db, groupmanager, start worker thread
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error changing case in ImageGallery.", ex);
}
} }
break; break;
case DATA_SOURCE_ADDED: case DATA_SOURCE_ADDED:

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2013-2017 Basis Technology Corp. * Copyright 2013-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -36,7 +36,6 @@ import javax.swing.SwingWorker;
import org.controlsfx.control.action.Action; import org.controlsfx.control.action.Action;
import org.controlsfx.control.action.ActionUtils; import org.controlsfx.control.action.ActionUtils;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.TopComponent; import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager; import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog;
@ -50,8 +49,8 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile;
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager;
import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/** /**
* Instances of this Action allow users to apply tags to content. * Instances of this Action allow users to apply tags to content.
@ -75,7 +74,7 @@ public class AddTagAction extends Action {
setEventHandler(actionEvent -> addTagWithComment("")); setEventHandler(actionEvent -> addTagWithComment(""));
} }
static public Menu getTagMenu(ImageGalleryController controller) { static public Menu getTagMenu(ImageGalleryController controller) throws TskCoreException {
return new TagMenu(controller); return new TagMenu(controller);
} }
@ -141,7 +140,7 @@ public class AddTagAction extends Action {
"AddDrawableTagAction.displayName.singular=Tag File"}) "AddDrawableTagAction.displayName.singular=Tag File"})
private static class TagMenu extends Menu { private static class TagMenu extends Menu {
TagMenu(ImageGalleryController controller) { TagMenu(ImageGalleryController controller) throws TskCoreException {
setGraphic(new ImageView(DrawableAttribute.TAGS.getIcon())); setGraphic(new ImageView(DrawableAttribute.TAGS.getIcon()));
ObservableSet<Long> selectedFileIDs = controller.getSelectionModel().getSelected(); ObservableSet<Long> selectedFileIDs = controller.getSelectionModel().getSelected();
setText(selectedFileIDs.size() > 1 setText(selectedFileIDs.size() > 1
@ -163,11 +162,10 @@ public class AddTagAction extends Action {
empty.setDisable(true); empty.setDisable(true);
quickTagMenu.getItems().add(empty); quickTagMenu.getItems().add(empty);
} else { } else {
for (final TagName tagName : tagNames) { tagNames.stream()
AddTagAction addDrawableTagAction = new AddTagAction(controller, tagName, selectedFileIDs); .map(tagName -> new AddTagAction(controller, tagName, selectedFileIDs))
MenuItem tagNameItem = ActionUtils.createMenuItem(addDrawableTagAction); .map(ActionUtils::createMenuItem)
quickTagMenu.getItems().add(tagNameItem); .forEachOrdered(quickTagMenu.getItems()::add);
}
} }
/* /*

View File

@ -42,12 +42,14 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.GuardedBy;
import javax.swing.SortOrder; import javax.swing.SortOrder;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.openide.util.Exceptions;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.DhsImageCategory; import org.sleuthkit.autopsy.datamodel.DhsImageCategory;

View File

@ -66,6 +66,7 @@ import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.GuardedBy;
import javax.swing.SortOrder; import javax.swing.SortOrder;
import static org.apache.commons.collections4.CollectionUtils.isNotEmpty; import static org.apache.commons.collections4.CollectionUtils.isNotEmpty;
import org.apache.commons.collections4.comparators.ComparableComparator;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.apache.commons.lang3.concurrent.BasicThreadFactory;

View File

@ -28,7 +28,8 @@ import org.openide.util.NbBundle;
/** /**
* Pseudo enum of possible properties to sort groups by. * Pseudo enum of possible properties to sort groups by.
*/ */
@NbBundle.Messages({"GroupSortBy.groupSize=Group Size", @NbBundle.Messages({
"GroupSortBy.groupSize=Group Size",
"GroupSortBy.groupName=Group Name", "GroupSortBy.groupName=Group Name",
"GroupSortBy.none=None", "GroupSortBy.none=None",
"GroupSortBy.priority=Priority"}) "GroupSortBy.priority=Priority"})
@ -37,40 +38,35 @@ public class GroupSortBy implements Comparator<DrawableGroup> {
/** /**
* sort the groups by the number of files in each * sort the groups by the number of files in each
*/ */
public final static GroupSortBy FILE_COUNT = public final static GroupSortBy FILE_COUNT
new GroupSortBy(Bundle.GroupSortBy_groupSize(), "folder-open-image.png", = new GroupSortBy(Bundle.GroupSortBy_groupSize(), "folder-open-image.png",
Comparator.comparing(DrawableGroup::getSize)); Comparator.comparing(DrawableGroup::getSize));
/** /**
* sort the groups by the natural order of the grouping value ( eg group * sort the groups by the natural order of the grouping value ( eg group
* them by path alphabetically ) * them by path alphabetically )
*/ */
public final static GroupSortBy GROUP_BY_VALUE = public final static GroupSortBy GROUP_BY_VALUE
new GroupSortBy(Bundle.GroupSortBy_groupName(), "folder-rename.png", = new GroupSortBy(Bundle.GroupSortBy_groupName(), "folder-rename.png",
Comparator.comparing(DrawableGroup::getGroupByValueDislpayName)); Comparator.comparing(DrawableGroup::getGroupByValueDislpayName));
/** /**
* don't sort the groups just use what ever order they come in (ingest * don't sort the groups just use what ever order they come in (ingest
* order) * order)
*/ */
public final static GroupSortBy NONE = public final static GroupSortBy NONE
new GroupSortBy(Bundle.GroupSortBy_none(), "prohibition.png", = new GroupSortBy(Bundle.GroupSortBy_none(), "prohibition.png",
new AllEqualComparator<>()); new AllEqualComparator<>());
/** /**
* sort the groups by some priority metric to be determined and implemented * sort the groups by some priority metric to be determined and implemented
*/ */
public final static GroupSortBy PRIORITY = public final static GroupSortBy PRIORITY
new GroupSortBy(Bundle.GroupSortBy_priority(), "hashset_hits.png", = new GroupSortBy(Bundle.GroupSortBy_priority(), "hashset_hits.png",
Comparator.comparing(DrawableGroup::getHashHitDensity) Comparator.comparing(DrawableGroup::getHashHitDensity)
.thenComparing(Comparator.comparing(DrawableGroup::getUncategorizedCount)) .thenComparing(Comparator.comparing(DrawableGroup::getUncategorizedCount))
.reversed()); .reversed());
@Override
public int compare(DrawableGroup o1, DrawableGroup o2) {
return delegate.compare(o1, o2);
}
private final static ObservableList<GroupSortBy> values = FXCollections.unmodifiableObservableList(FXCollections.observableArrayList(PRIORITY, NONE, GROUP_BY_VALUE, FILE_COUNT)); private final static ObservableList<GroupSortBy> values = FXCollections.unmodifiableObservableList(FXCollections.observableArrayList(PRIORITY, NONE, GROUP_BY_VALUE, FILE_COUNT));
/** /**
@ -109,6 +105,11 @@ public class GroupSortBy implements Comparator<DrawableGroup> {
return icon; return icon;
} }
@Override
public int compare(DrawableGroup o1, DrawableGroup o2) {
return delegate.compare(o1, o2);
}
static class AllEqualComparator<A> implements Comparator<A> { static class AllEqualComparator<A> implements Comparator<A> {
@Override @Override

View File

@ -30,6 +30,7 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.logging.Level; import java.util.logging.Level;
import javafx.application.Platform; import javafx.application.Platform;
@ -77,6 +78,7 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute;
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup;
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupSortBy; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupSortBy;
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState;
import org.sleuthkit.autopsy.imagegallery.utils.TaskUtils;
import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.DataSource;
/** /**
@ -84,7 +86,7 @@ import org.sleuthkit.datamodel.DataSource;
*/ */
public class Toolbar extends ToolBar { public class Toolbar extends ToolBar {
private static final Logger LOGGER = Logger.getLogger(Toolbar.class.getName()); private static final Logger logger = Logger.getLogger(Toolbar.class.getName());
private static final int SIZE_SLIDER_DEFAULT = 100; private static final int SIZE_SLIDER_DEFAULT = 100;
@FXML @FXML
@ -109,9 +111,7 @@ public class Toolbar extends ToolBar {
private Label thumbnailSizeLabel; private Label thumbnailSizeLabel;
private SortChooser<DrawableGroup, GroupSortBy> sortChooser; private SortChooser<DrawableGroup, GroupSortBy> sortChooser;
private final ListeningExecutorService exec private final ListeningExecutorService exec = TaskUtils.getExecutorForClass(Toolbar.class);
= MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor(
new ThreadFactoryBuilder().setNameFormat("Image Gallery Toolbar BG Thread").build()));
private final ImageGalleryController controller; private final ImageGalleryController controller;
@ -291,19 +291,31 @@ public class Toolbar extends ToolBar {
* TODO (JIRA-3010): SEVERE error logged by image Gallery UI * TODO (JIRA-3010): SEVERE error logged by image Gallery UI
*/ */
if (Case.isCaseOpen()) { if (Case.isCaseOpen()) {
LOGGER.log(Level.WARNING, "Could not create Follow Up tag menu item", t); //NON-NLS logger.log(Level.WARNING, "Could not create Follow Up tag menu item", t); //NON-NLS
} else { } else {
// don't add stack trace to log because it makes looking for real errors harder // don't add stack trace to log because it makes looking for real errors harder
LOGGER.log(Level.INFO, "Unable to get tag name. Case is closed."); //NON-NLS logger.log(Level.INFO, "Unable to get tag name. Case is closed."); //NON-NLS
} }
} }
}, Platform::runLater); }, Platform::runLater);
tagGroupMenuButton.showingProperty().addListener(showing -> { tagGroupMenuButton.showingProperty().addListener(showing -> {
if (tagGroupMenuButton.isShowing()) { if (tagGroupMenuButton.isShowing()) {
List<MenuItem> selTagMenues = Lists.transform(controller.getTagsManager().getNonCategoryTagNames(), ListenableFuture<List<MenuItem>> getTagsFuture = exec.submit(() -> {
return Lists.transform(controller.getTagsManager().getNonCategoryTagNames(),
tagName -> GuiUtils.createAutoAssigningMenuItem(tagGroupMenuButton, new TagGroupAction(tagName, controller))); tagName -> GuiUtils.createAutoAssigningMenuItem(tagGroupMenuButton, new TagGroupAction(tagName, controller)));
tagGroupMenuButton.getItems().setAll(selTagMenues); });
Futures.addCallback(getTagsFuture, new FutureCallback<List<MenuItem>>() {
@Override
public void onSuccess(List<MenuItem> result) {
tagGroupMenuButton.getItems().setAll(result);
}
@Override
public void onFailure(Throwable t) {
logger.log(Level.SEVERE, "Error getting non-gategory tag names.", t);
}
}, Platform::runLater);
} }
}); });
} }
@ -320,7 +332,7 @@ public class Toolbar extends ToolBar {
@Override @Override
public void onFailure(Throwable t) { public void onFailure(Throwable t) {
LOGGER.log(Level.SEVERE, "Unable to get datasources for current case.", t); //NON-NLS logger.log(Level.SEVERE, "Unable to get datasources for current case.", t); //NON-NLS
Notifications.create().owner(getScene().getRoot()) Notifications.create().owner(getScene().getRoot())
.title("Image Gallery Error") .title("Image Gallery Error")
.text(Bundle.Toolbar_getDataSources_errMessage()) .text(Bundle.Toolbar_getDataSources_errMessage())
@ -389,6 +401,7 @@ public class Toolbar extends ToolBar {
this.controller = controller; this.controller = controller;
FXMLConstructor.construct(this, "Toolbar.fxml"); //NON-NLS FXMLConstructor.construct(this, "Toolbar.fxml"); //NON-NLS
} }
/** /**

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2013-2017 Basis Technology Corp. * Copyright 2013-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -79,9 +79,9 @@ import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
/** /**
* An abstract base class for {@link DrawableTile} and {@link SlideShowView}, * An abstract base class for DrawableTile and SlideShowView, since they share a
* since they share a similar node tree and many behaviors, other implementors * similar node tree and many behaviors, other implementors of DrawableViews
* of {@link DrawableView}s should implement the interface directly * should implement the interface directly
* *
* *
* TODO: refactor ExternalViewerAction to supply its own name * TODO: refactor ExternalViewerAction to supply its own name
@ -89,7 +89,7 @@ import org.sleuthkit.datamodel.TskCoreException;
@NbBundle.Messages({"DrawableTileBase.externalViewerAction.text=Open in External Viewer"}) @NbBundle.Messages({"DrawableTileBase.externalViewerAction.text=Open in External Viewer"})
public abstract class DrawableTileBase extends DrawableUIBase { public abstract class DrawableTileBase extends DrawableUIBase {
private static final Logger LOGGER = Logger.getLogger(DrawableTileBase.class.getName()); private static final Logger logger = Logger.getLogger(DrawableTileBase.class.getName());
private static final Border UNSELECTED_BORDER = new Border(new BorderStroke(Color.GRAY, BorderStrokeStyle.SOLID, new CornerRadii(2), new BorderWidths(3))); private static final Border UNSELECTED_BORDER = new Border(new BorderStroke(Color.GRAY, BorderStrokeStyle.SOLID, new CornerRadii(2), new BorderWidths(3)));
private static final Border SELECTED_BORDER = new Border(new BorderStroke(Color.BLUE, BorderStrokeStyle.SOLID, new CornerRadii(2), new BorderWidths(3))); private static final Border SELECTED_BORDER = new Border(new BorderStroke(Color.BLUE, BorderStrokeStyle.SOLID, new CornerRadii(2), new BorderWidths(3)));
@ -187,28 +187,31 @@ public abstract class DrawableTileBase extends DrawableUIBase {
final ArrayList<MenuItem> menuItems = new ArrayList<>(); final ArrayList<MenuItem> menuItems = new ArrayList<>();
menuItems.add(CategorizeAction.getCategoriesMenu(getController())); menuItems.add(CategorizeAction.getCategoriesMenu(getController()));
try {
menuItems.add(AddTagAction.getTagMenu(getController())); menuItems.add(AddTagAction.getTagMenu(getController()));
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error building tagging context menu.", ex);
}
final Collection<AbstractFile> selectedFilesList = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); final Collection<AbstractFile> selectedFilesList = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if(selectedFilesList.size() == 1) { if (selectedFilesList.size() == 1) {
menuItems.add(DeleteTagAction.getTagMenu(getController())); menuItems.add(DeleteTagAction.getTagMenu(getController()));
} }
final MenuItem extractMenuItem = new MenuItem(Bundle.DrawableTileBase_menuItem_extractFiles()); final MenuItem extractMenuItem = new MenuItem(Bundle.DrawableTileBase_menuItem_extractFiles());
extractMenuItem.setOnAction(actionEvent -> { extractMenuItem.setOnAction(actionEvent
SwingUtilities.invokeLater(() -> { -> SwingUtilities.invokeLater(() -> {
TopComponent etc = WindowManager.getDefault().findTopComponent(ImageGalleryTopComponent.PREFERRED_ID); TopComponent etc = WindowManager.getDefault().findTopComponent(ImageGalleryTopComponent.PREFERRED_ID);
ExtractAction.getInstance().actionPerformed(new java.awt.event.ActionEvent(etc, 0, null)); ExtractAction.getInstance().actionPerformed(new java.awt.event.ActionEvent(etc, 0, null));
}); }));
});
menuItems.add(extractMenuItem); menuItems.add(extractMenuItem);
MenuItem contentViewer = new MenuItem(Bundle.DrawableTileBase_menuItem_showContentViewer()); MenuItem contentViewer = new MenuItem(Bundle.DrawableTileBase_menuItem_showContentViewer());
contentViewer.setOnAction(actionEvent -> { contentViewer.setOnAction(actionEvent
SwingUtilities.invokeLater(() -> { -> SwingUtilities.invokeLater(() -> {
new NewWindowViewAction(Bundle.DrawableTileBase_menuItem_showContentViewer(), new FileNode(file.getAbstractFile())).actionPerformed(null); new NewWindowViewAction(Bundle.DrawableTileBase_menuItem_showContentViewer(), new FileNode(file.getAbstractFile()))
}); .actionPerformed(null);
}); }));
menuItems.add(contentViewer); menuItems.add(contentViewer);
OpenExternalViewerAction openExternalViewerAction = new OpenExternalViewerAction(file); OpenExternalViewerAction openExternalViewerAction = new OpenExternalViewerAction(file);
@ -243,32 +246,24 @@ public abstract class DrawableTileBase extends DrawableUIBase {
protected abstract String getTextForLabel(); protected abstract String getTextForLabel();
protected void initialize() { protected void initialize() {
followUpToggle.setOnAction(actionEvent -> { followUpToggle.setOnAction(actionEvent
getFile().ifPresent(file -> { -> getFile().ifPresent(file -> {
if (followUpToggle.isSelected() == true) { if (followUpToggle.isSelected()) {
try {
selectionModel.clearAndSelect(file.getId()); selectionModel.clearAndSelect(file.getId());
new AddTagAction(getController(), getController().getTagsManager().getFollowUpTagName(), selectionModel.getSelected()).handle(actionEvent); new AddTagAction(getController(), getController().getTagsManager().getFollowUpTagName(), selectionModel.getSelected())
} catch (TskCoreException ex) { .handle(actionEvent);
LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); //NON-NLS
}
} else { } else {
new DeleteFollowUpTagAction(getController(), file).handle(actionEvent); new DeleteFollowUpTagAction(getController(), file).handle(actionEvent);
} }
}); })
}); );
} }
protected boolean hasFollowUp() { protected boolean hasFollowUp() {
if (getFileID().isPresent()) { if (getFileID().isPresent()) {
try {
TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); TagName followUpTagName = getController().getTagsManager().getFollowUpTagName();
return DrawableAttribute.TAGS.getValue(getFile().get()).stream() return DrawableAttribute.TAGS.getValue(getFile().get()).stream()
.anyMatch(followUpTagName::equals); .anyMatch(followUpTagName::equals);
} catch (TskCoreException ex) {
LOGGER.log(Level.WARNING, "failed to get follow up tag name ", ex); //NON-NLS
return true;
}
} else { } else {
return false; return false;
} }
@ -342,8 +337,7 @@ public abstract class DrawableTileBase extends DrawableUIBase {
@Override @Override
public void handleTagAdded(ContentTagAddedEvent evt) { public void handleTagAdded(ContentTagAddedEvent evt) {
getFileID().ifPresent(fileID -> { getFileID().ifPresent(fileID -> {
try { final TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); //NON-NLS
final TagName followUpTagName = getController().getTagsManager().getFollowUpTagName();
final ContentTag addedTag = evt.getAddedTag(); final ContentTag addedTag = evt.getAddedTag();
if (fileID == addedTag.getContent().getId() if (fileID == addedTag.getContent().getId()
&& addedTag.getName().equals(followUpTagName)) { && addedTag.getName().equals(followUpTagName)) {
@ -352,9 +346,6 @@ public abstract class DrawableTileBase extends DrawableUIBase {
followUpToggle.setSelected(true); followUpToggle.setSelected(true);
}); });
} }
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Failed to get followup tag name. Unable to update follow up status for file. ", ex); //NON-NLS
}
}); });
} }
@ -362,16 +353,12 @@ public abstract class DrawableTileBase extends DrawableUIBase {
@Override @Override
public void handleTagDeleted(ContentTagDeletedEvent evt) { public void handleTagDeleted(ContentTagDeletedEvent evt) {
getFileID().ifPresent(fileID -> { getFileID().ifPresent(fileID -> {
try { final TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); //NON-NLS
final TagName followUpTagName = getController().getTagsManager().getFollowUpTagName();
final ContentTagDeletedEvent.DeletedContentTagInfo deletedTagInfo = evt.getDeletedTagInfo(); final ContentTagDeletedEvent.DeletedContentTagInfo deletedTagInfo = evt.getDeletedTagInfo();
if (fileID == deletedTagInfo.getContentID() if (fileID == deletedTagInfo.getContentID()
&& deletedTagInfo.getName().equals(followUpTagName)) { && deletedTagInfo.getName().equals(followUpTagName)) {
updateFollowUpIcon(); updateFollowUpIcon();
} }
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Failed to get followup tag name. Unable to update follow up status for file. ", ex); //NON-NLS
}
}); });
} }

View File

@ -21,6 +21,10 @@ package org.sleuthkit.autopsy.imagegallery.gui.drawableviews;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -31,8 +35,10 @@ import java.util.Map;
import static java.util.Objects.isNull; import static java.util.Objects.isNull;
import static java.util.Objects.nonNull; import static java.util.Objects.nonNull;
import java.util.Optional; import java.util.Optional;
import java.util.function.Function;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import java.util.stream.Stream;
import javafx.animation.Interpolator; import javafx.animation.Interpolator;
import javafx.animation.KeyFrame; import javafx.animation.KeyFrame;
import javafx.animation.KeyValue; import javafx.animation.KeyValue;
@ -97,6 +103,7 @@ import org.controlsfx.control.GridCell;
import org.controlsfx.control.GridView; import org.controlsfx.control.GridView;
import org.controlsfx.control.SegmentedButton; import org.controlsfx.control.SegmentedButton;
import org.controlsfx.control.action.ActionUtils; import org.controlsfx.control.action.ActionUtils;
import org.openide.util.Exceptions;
import org.openide.util.Lookup; import org.openide.util.Lookup;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.actions.Presenter; import org.openide.util.actions.Presenter;
@ -107,6 +114,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.ContextMenuActionsProvider;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType;
import org.sleuthkit.autopsy.datamodel.DhsImageCategory;
import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor;
import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel;
@ -122,12 +130,12 @@ import org.sleuthkit.autopsy.imagegallery.actions.RedoAction;
import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter;
import org.sleuthkit.autopsy.imagegallery.actions.TagSelectedFilesAction; import org.sleuthkit.autopsy.imagegallery.actions.TagSelectedFilesAction;
import org.sleuthkit.autopsy.imagegallery.actions.UndoAction; import org.sleuthkit.autopsy.imagegallery.actions.UndoAction;
import org.sleuthkit.autopsy.datamodel.DhsImageCategory;
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile;
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup;
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewMode; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewMode;
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState;
import org.sleuthkit.autopsy.imagegallery.gui.GuiUtils; import org.sleuthkit.autopsy.imagegallery.gui.GuiUtils;
import org.sleuthkit.autopsy.imagegallery.utils.TaskUtils;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
/** /**
@ -145,10 +153,11 @@ import org.sleuthkit.datamodel.TskCoreException;
*/ */
public class GroupPane extends BorderPane { public class GroupPane extends BorderPane {
private static final Logger LOGGER = Logger.getLogger(GroupPane.class.getName()); private static final Logger logger = Logger.getLogger(GroupPane.class.getName());
private final ListeningExecutorService exec = TaskUtils.getExecutorForClass(GroupPane.class);
private static final BorderWidths BORDER_WIDTHS_2 = new BorderWidths(2); private static final BorderWidths BORDER_WIDTHS_2 = new BorderWidths(2);
private static final CornerRadii CORNER_RADII_2 = new CornerRadii(2); private static final CornerRadii CORNER_RADII_2 = new CornerRadii(2);
private static final DropShadow DROP_SHADOW = new DropShadow(10, Color.BLUE); private static final DropShadow DROP_SHADOW = new DropShadow(10, Color.BLUE);
private static final Timeline flashAnimation = new Timeline(new KeyFrame(Duration.millis(400), new KeyValue(DROP_SHADOW.radiusProperty(), 1, Interpolator.LINEAR)), private static final Timeline flashAnimation = new Timeline(new KeyFrame(Duration.millis(400), new KeyValue(DROP_SHADOW.radiusProperty(), 1, Interpolator.LINEAR)),
@ -156,7 +165,8 @@ public class GroupPane extends BorderPane {
); );
private final FileIDSelectionModel selectionModel; private final FileIDSelectionModel selectionModel;
private static final List<KeyCode> categoryKeyCodes = Arrays.asList(KeyCode.NUMPAD0, KeyCode.NUMPAD1, KeyCode.NUMPAD2, KeyCode.NUMPAD3, KeyCode.NUMPAD4, KeyCode.NUMPAD5, private static final List<KeyCode> categoryKeyCodes
= Arrays.asList(KeyCode.NUMPAD0, KeyCode.NUMPAD1, KeyCode.NUMPAD2, KeyCode.NUMPAD3, KeyCode.NUMPAD4, KeyCode.NUMPAD5,
KeyCode.DIGIT0, KeyCode.DIGIT1, KeyCode.DIGIT2, KeyCode.DIGIT3, KeyCode.DIGIT4, KeyCode.DIGIT5); KeyCode.DIGIT0, KeyCode.DIGIT1, KeyCode.DIGIT2, KeyCode.DIGIT3, KeyCode.DIGIT4, KeyCode.DIGIT5);
private final Back backAction; private final Back backAction;
@ -426,27 +436,35 @@ public class GroupPane extends BorderPane {
catSelectedSplitMenu.disableProperty().bind(isSelectionEmpty); catSelectedSplitMenu.disableProperty().bind(isSelectionEmpty);
tagSelectedSplitMenu.disableProperty().bind(isSelectionEmpty); tagSelectedSplitMenu.disableProperty().bind(isSelectionEmpty);
TagSelectedFilesAction followUpSelectedAction = new TagSelectedFilesAction(controller.getTagsManager().getFollowUpTagName(), controller); //NON-NLS
Platform.runLater(() -> { Platform.runLater(() -> {
try { tagSelectedSplitMenu.setText(followUpSelectedAction.getText());
TagSelectedFilesAction followUpSelectedACtion = new TagSelectedFilesAction(controller.getTagsManager().getFollowUpTagName(), controller); tagSelectedSplitMenu.setGraphic(followUpSelectedAction.getGraphic());
tagSelectedSplitMenu.setText(followUpSelectedACtion.getText()); tagSelectedSplitMenu.setOnAction(followUpSelectedAction);
tagSelectedSplitMenu.setGraphic(followUpSelectedACtion.getGraphic());
tagSelectedSplitMenu.setOnAction(followUpSelectedACtion);
} catch (TskCoreException tskCoreException) {
LOGGER.log(Level.WARNING, "failed to load FollowUpTagName", tskCoreException); //NON-NLS
}
tagSelectedSplitMenu.showingProperty().addListener(showing -> { tagSelectedSplitMenu.showingProperty().addListener(showing -> {
if (tagSelectedSplitMenu.isShowing()) { if (tagSelectedSplitMenu.isShowing()) {
List<MenuItem> selTagMenues = Lists.transform(controller.getTagsManager().getNonCategoryTagNames(),
tagName -> GuiUtils.createAutoAssigningMenuItem(tagSelectedSplitMenu, new TagSelectedFilesAction(tagName, controller))); ListenableFuture<List<MenuItem>> getTagsFuture = exec.submit(()
tagSelectedSplitMenu.getItems().setAll(selTagMenues); -> Lists.transform(controller.getTagsManager().getNonCategoryTagNames(),
tagName -> GuiUtils.createAutoAssigningMenuItem(tagSelectedSplitMenu, new TagSelectedFilesAction(tagName, controller))));
Futures.addCallback(getTagsFuture, new FutureCallback<List<MenuItem>>() {
@Override
public void onSuccess(List<MenuItem> result) {
tagSelectedSplitMenu.getItems().setAll(result);
}
@Override
public void onFailure(Throwable t) {
logger.log(Level.SEVERE, "Error getting tag names.", t);
}
}, Platform::runLater);
} }
}); });
}); });
CategorizeSelectedFilesAction cat5SelectedAction = new CategorizeSelectedFilesAction(DhsImageCategory.FIVE, controller); CategorizeSelectedFilesAction cat5SelectedAction = new CategorizeSelectedFilesAction(DhsImageCategory.FIVE, controller);
catSelectedSplitMenu.setOnAction(cat5SelectedAction); catSelectedSplitMenu.setOnAction(cat5SelectedAction);
catSelectedSplitMenu.setText(cat5SelectedAction.getText()); catSelectedSplitMenu.setText(cat5SelectedAction.getText());
catSelectedSplitMenu.setGraphic(cat5SelectedAction.getGraphic()); catSelectedSplitMenu.setGraphic(cat5SelectedAction.getGraphic());
catSelectedSplitMenu.showingProperty().addListener(showing -> { catSelectedSplitMenu.showingProperty().addListener(showing -> {
@ -832,23 +850,25 @@ public class GroupPane extends BorderPane {
private ContextMenu buildContextMenu() { private ContextMenu buildContextMenu() {
ArrayList<MenuItem> menuItems = new ArrayList<>(); ArrayList<MenuItem> menuItems = new ArrayList<>();
menuItems.add(CategorizeAction.getCategoriesMenu(controller)); menuItems.add(CategorizeAction.getCategoriesMenu(controller));
try {
menuItems.add(AddTagAction.getTagMenu(controller)); menuItems.add(AddTagAction.getTagMenu(controller));
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error building tagging context menu.", ex);
Collection<? extends ContextMenuActionsProvider> menuProviders = Lookup.getDefault().lookupAll(ContextMenuActionsProvider.class);
for (ContextMenuActionsProvider provider : menuProviders) {
for (final Action act : provider.getActions()) {
if (act instanceof Presenter.Popup) {
Presenter.Popup aact = (Presenter.Popup) act;
menuItems.add(SwingMenuItemAdapter.create(aact.getPopupPresenter()));
}
}
} }
Lookup.getDefault().lookupAll(ContextMenuActionsProvider.class).stream()
.map(ContextMenuActionsProvider::getActions)
.flatMap(Collection::stream)
.filter(Presenter.Popup.class::isInstance)
.map(Presenter.Popup.class::cast)
.map(Presenter.Popup::getPopupPresenter)
.map(SwingMenuItemAdapter::create)
.forEachOrdered(menuItems::add);
final MenuItem extractMenuItem = new MenuItem(Bundle.GroupPane_gridViewContextMenuItem_extractFiles()); final MenuItem extractMenuItem = new MenuItem(Bundle.GroupPane_gridViewContextMenuItem_extractFiles());
extractMenuItem.setOnAction((ActionEvent t) -> {
extractMenuItem.setOnAction(actionEvent -> {
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
TopComponent etc = WindowManager.getDefault().findTopComponent(ImageGalleryTopComponent.PREFERRED_ID); TopComponent etc = WindowManager.getDefault().findTopComponent(ImageGalleryTopComponent.PREFERRED_ID);
ExtractAction.getInstance().actionPerformed(new java.awt.event.ActionEvent(etc, 0, null)); ExtractAction.getInstance().actionPerformed(new java.awt.event.ActionEvent(etc, 0, null));
@ -857,7 +877,9 @@ public class GroupPane extends BorderPane {
menuItems.add(extractMenuItem); menuItems.add(extractMenuItem);
ContextMenu contextMenu = new ContextMenu(menuItems.toArray(new MenuItem[]{})); ContextMenu contextMenu = new ContextMenu(menuItems.toArray(new MenuItem[]{}));
contextMenu.setAutoHide(true);
contextMenu.setAutoHide(
true);
return contextMenu; return contextMenu;
} }

View File

@ -18,13 +18,20 @@
*/ */
package org.sleuthkit.autopsy.imagegallery.utils; package org.sleuthkit.autopsy.imagegallery.utils;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import javafx.concurrent.Task; import javafx.concurrent.Task;
/** /**
* *
*/ */
public class TaskUtils { public final class TaskUtils {
private TaskUtils() {
}
public static <T> Task<T> taskFrom(Callable<T> callable) { public static <T> Task<T> taskFrom(Callable<T> callable) {
return new Task<T>() { return new Task<T>() {
@ -35,6 +42,8 @@ public class TaskUtils {
}; };
} }
private TaskUtils() { public static ListeningExecutorService getExecutorForClass(Class<?> clazz) {
return MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor(
new ThreadFactoryBuilder().setNameFormat("Image Gallery " + clazz.getSimpleName() + " BG Thread").build()));
} }
} }

View File

@ -1,5 +1,5 @@
#Updated by build script #Updated by build script
#Mon, 25 Jun 2018 17:19:36 -0400 #Mon, 03 Sep 2018 17:29:44 +0200
LBL_splash_window_title=Starting Autopsy LBL_splash_window_title=Starting Autopsy
SPLASH_HEIGHT=314 SPLASH_HEIGHT=314
SPLASH_WIDTH=538 SPLASH_WIDTH=538

View File

@ -1,4 +1,4 @@
#Updated by build script #Updated by build script
#Mon, 25 Jun 2018 17:19:36 -0400 #Mon, 03 Sep 2018 17:29:44 +0200
CTL_MainWindow_Title=Autopsy 4.8.0 CTL_MainWindow_Title=Autopsy 4.8.0
CTL_MainWindow_Title_No_Project=Autopsy 4.8.0 CTL_MainWindow_Title_No_Project=Autopsy 4.8.0