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

View File

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

View File

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

View File

@ -66,6 +66,7 @@ import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.swing.SortOrder;
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.StringUtils;
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.
*/
@NbBundle.Messages({"GroupSortBy.groupSize=Group Size",
@NbBundle.Messages({
"GroupSortBy.groupSize=Group Size",
"GroupSortBy.groupName=Group Name",
"GroupSortBy.none=None",
"GroupSortBy.priority=Priority"})
@ -37,40 +38,35 @@ public class GroupSortBy implements Comparator<DrawableGroup> {
/**
* sort the groups by the number of files in each
*/
public final static GroupSortBy FILE_COUNT =
new GroupSortBy(Bundle.GroupSortBy_groupSize(), "folder-open-image.png",
public final static GroupSortBy FILE_COUNT
= new GroupSortBy(Bundle.GroupSortBy_groupSize(), "folder-open-image.png",
Comparator.comparing(DrawableGroup::getSize));
/**
* sort the groups by the natural order of the grouping value ( eg group
* them by path alphabetically )
*/
public final static GroupSortBy GROUP_BY_VALUE =
new GroupSortBy(Bundle.GroupSortBy_groupName(), "folder-rename.png",
public final static GroupSortBy GROUP_BY_VALUE
= new GroupSortBy(Bundle.GroupSortBy_groupName(), "folder-rename.png",
Comparator.comparing(DrawableGroup::getGroupByValueDislpayName));
/**
* don't sort the groups just use what ever order they come in (ingest
* order)
*/
public final static GroupSortBy NONE =
new GroupSortBy(Bundle.GroupSortBy_none(), "prohibition.png",
public final static GroupSortBy NONE
= new GroupSortBy(Bundle.GroupSortBy_none(), "prohibition.png",
new AllEqualComparator<>());
/**
* sort the groups by some priority metric to be determined and implemented
*/
public final static GroupSortBy PRIORITY =
new GroupSortBy(Bundle.GroupSortBy_priority(), "hashset_hits.png",
public final static GroupSortBy PRIORITY
= new GroupSortBy(Bundle.GroupSortBy_priority(), "hashset_hits.png",
Comparator.comparing(DrawableGroup::getHashHitDensity)
.thenComparing(Comparator.comparing(DrawableGroup::getUncategorizedCount))
.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));
/**
@ -109,6 +105,11 @@ public class GroupSortBy implements Comparator<DrawableGroup> {
return icon;
}
@Override
public int compare(DrawableGroup o1, DrawableGroup o2) {
return delegate.compare(o1, o2);
}
static class AllEqualComparator<A> implements Comparator<A> {
@Override

View File

@ -30,6 +30,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.logging.Level;
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.GroupSortBy;
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState;
import org.sleuthkit.autopsy.imagegallery.utils.TaskUtils;
import org.sleuthkit.datamodel.DataSource;
/**
@ -84,7 +86,7 @@ import org.sleuthkit.datamodel.DataSource;
*/
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;
@FXML
@ -109,9 +111,7 @@ public class Toolbar extends ToolBar {
private Label thumbnailSizeLabel;
private SortChooser<DrawableGroup, GroupSortBy> sortChooser;
private final ListeningExecutorService exec
= MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor(
new ThreadFactoryBuilder().setNameFormat("Image Gallery Toolbar BG Thread").build()));
private final ListeningExecutorService exec = TaskUtils.getExecutorForClass(Toolbar.class);
private final ImageGalleryController controller;
@ -291,19 +291,31 @@ public class Toolbar extends ToolBar {
* TODO (JIRA-3010): SEVERE error logged by image Gallery UI
*/
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 {
// 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);
tagGroupMenuButton.showingProperty().addListener(showing -> {
if (tagGroupMenuButton.isShowing()) {
List<MenuItem> selTagMenues = Lists.transform(controller.getTagsManager().getNonCategoryTagNames(),
tagName -> GuiUtils.createAutoAssigningMenuItem(tagGroupMenuButton, new TagGroupAction(tagName, controller)));
tagGroupMenuButton.getItems().setAll(selTagMenues);
ListenableFuture<List<MenuItem>> getTagsFuture = exec.submit(() -> {
return Lists.transform(controller.getTagsManager().getNonCategoryTagNames(),
tagName -> GuiUtils.createAutoAssigningMenuItem(tagGroupMenuButton, new TagGroupAction(tagName, controller)));
});
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
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())
.title("Image Gallery Error")
.text(Bundle.Toolbar_getDataSources_errMessage())
@ -389,6 +401,7 @@ public class Toolbar extends ToolBar {
this.controller = controller;
FXMLConstructor.construct(this, "Toolbar.fxml"); //NON-NLS
}
/**

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2017 Basis Technology Corp.
* Copyright 2013-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -79,9 +79,9 @@ import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
/**
* An abstract base class for {@link DrawableTile} and {@link SlideShowView},
* since they share a similar node tree and many behaviors, other implementors
* of {@link DrawableView}s should implement the interface directly
* An abstract base class for DrawableTile and SlideShowView, since they share a
* similar node tree and many behaviors, other implementors of DrawableViews
* should implement the interface directly
*
*
* 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"})
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 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<>();
menuItems.add(CategorizeAction.getCategoriesMenu(getController()));
menuItems.add(AddTagAction.getTagMenu(getController()));
try {
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));
if(selectedFilesList.size() == 1) {
if (selectedFilesList.size() == 1) {
menuItems.add(DeleteTagAction.getTagMenu(getController()));
}
final MenuItem extractMenuItem = new MenuItem(Bundle.DrawableTileBase_menuItem_extractFiles());
extractMenuItem.setOnAction(actionEvent -> {
SwingUtilities.invokeLater(() -> {
TopComponent etc = WindowManager.getDefault().findTopComponent(ImageGalleryTopComponent.PREFERRED_ID);
ExtractAction.getInstance().actionPerformed(new java.awt.event.ActionEvent(etc, 0, null));
});
});
extractMenuItem.setOnAction(actionEvent
-> SwingUtilities.invokeLater(() -> {
TopComponent etc = WindowManager.getDefault().findTopComponent(ImageGalleryTopComponent.PREFERRED_ID);
ExtractAction.getInstance().actionPerformed(new java.awt.event.ActionEvent(etc, 0, null));
}));
menuItems.add(extractMenuItem);
MenuItem contentViewer = new MenuItem(Bundle.DrawableTileBase_menuItem_showContentViewer());
contentViewer.setOnAction(actionEvent -> {
SwingUtilities.invokeLater(() -> {
new NewWindowViewAction(Bundle.DrawableTileBase_menuItem_showContentViewer(), new FileNode(file.getAbstractFile())).actionPerformed(null);
});
});
contentViewer.setOnAction(actionEvent
-> SwingUtilities.invokeLater(() -> {
new NewWindowViewAction(Bundle.DrawableTileBase_menuItem_showContentViewer(), new FileNode(file.getAbstractFile()))
.actionPerformed(null);
}));
menuItems.add(contentViewer);
OpenExternalViewerAction openExternalViewerAction = new OpenExternalViewerAction(file);
@ -243,32 +246,24 @@ public abstract class DrawableTileBase extends DrawableUIBase {
protected abstract String getTextForLabel();
protected void initialize() {
followUpToggle.setOnAction(actionEvent -> {
getFile().ifPresent(file -> {
if (followUpToggle.isSelected() == true) {
try {
followUpToggle.setOnAction(actionEvent
-> getFile().ifPresent(file -> {
if (followUpToggle.isSelected()) {
selectionModel.clearAndSelect(file.getId());
new AddTagAction(getController(), getController().getTagsManager().getFollowUpTagName(), selectionModel.getSelected()).handle(actionEvent);
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); //NON-NLS
new AddTagAction(getController(), getController().getTagsManager().getFollowUpTagName(), selectionModel.getSelected())
.handle(actionEvent);
} else {
new DeleteFollowUpTagAction(getController(), file).handle(actionEvent);
}
} else {
new DeleteFollowUpTagAction(getController(), file).handle(actionEvent);
}
});
});
})
);
}
protected boolean hasFollowUp() {
if (getFileID().isPresent()) {
try {
TagName followUpTagName = getController().getTagsManager().getFollowUpTagName();
return DrawableAttribute.TAGS.getValue(getFile().get()).stream()
.anyMatch(followUpTagName::equals);
} catch (TskCoreException ex) {
LOGGER.log(Level.WARNING, "failed to get follow up tag name ", ex); //NON-NLS
return true;
}
TagName followUpTagName = getController().getTagsManager().getFollowUpTagName();
return DrawableAttribute.TAGS.getValue(getFile().get()).stream()
.anyMatch(followUpTagName::equals);
} else {
return false;
}
@ -342,18 +337,14 @@ public abstract class DrawableTileBase extends DrawableUIBase {
@Override
public void handleTagAdded(ContentTagAddedEvent evt) {
getFileID().ifPresent(fileID -> {
try {
final TagName followUpTagName = getController().getTagsManager().getFollowUpTagName();
final ContentTag addedTag = evt.getAddedTag();
if (fileID == addedTag.getContent().getId()
&& addedTag.getName().equals(followUpTagName)) {
Platform.runLater(() -> {
followUpImageView.setImage(followUpIcon);
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
final TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); //NON-NLS
final ContentTag addedTag = evt.getAddedTag();
if (fileID == addedTag.getContent().getId()
&& addedTag.getName().equals(followUpTagName)) {
Platform.runLater(() -> {
followUpImageView.setImage(followUpIcon);
followUpToggle.setSelected(true);
});
}
});
}
@ -362,15 +353,11 @@ public abstract class DrawableTileBase extends DrawableUIBase {
@Override
public void handleTagDeleted(ContentTagDeletedEvent evt) {
getFileID().ifPresent(fileID -> {
try {
final TagName followUpTagName = getController().getTagsManager().getFollowUpTagName();
final ContentTagDeletedEvent.DeletedContentTagInfo deletedTagInfo = evt.getDeletedTagInfo();
if (fileID == deletedTagInfo.getContentID()
&& deletedTagInfo.getName().equals(followUpTagName)) {
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
final TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); //NON-NLS
final ContentTagDeletedEvent.DeletedContentTagInfo deletedTagInfo = evt.getDeletedTagInfo();
if (fileID == deletedTagInfo.getContentID()
&& deletedTagInfo.getName().equals(followUpTagName)) {
updateFollowUpIcon();
}
});
}

View File

@ -21,6 +21,10 @@ package org.sleuthkit.autopsy.imagegallery.gui.drawableviews;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
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.Arrays;
import java.util.Collection;
@ -31,8 +35,10 @@ import java.util.Map;
import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import java.util.Optional;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
@ -97,6 +103,7 @@ import org.controlsfx.control.GridCell;
import org.controlsfx.control.GridView;
import org.controlsfx.control.SegmentedButton;
import org.controlsfx.control.action.ActionUtils;
import org.openide.util.Exceptions;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
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.ThreadConfined;
import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType;
import org.sleuthkit.autopsy.datamodel.DhsImageCategory;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.imagegallery.FXMLConstructor;
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.TagSelectedFilesAction;
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.grouping.DrawableGroup;
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewMode;
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState;
import org.sleuthkit.autopsy.imagegallery.gui.GuiUtils;
import org.sleuthkit.autopsy.imagegallery.utils.TaskUtils;
import org.sleuthkit.datamodel.TskCoreException;
/**
@ -145,10 +153,11 @@ import org.sleuthkit.datamodel.TskCoreException;
*/
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 CornerRadii CORNER_RADII_2 = new CornerRadii(2);
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)),
@ -156,8 +165,9 @@ public class GroupPane extends BorderPane {
);
private final FileIDSelectionModel selectionModel;
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);
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);
private final Back backAction;
@ -426,27 +436,35 @@ public class GroupPane extends BorderPane {
catSelectedSplitMenu.disableProperty().bind(isSelectionEmpty);
tagSelectedSplitMenu.disableProperty().bind(isSelectionEmpty);
TagSelectedFilesAction followUpSelectedAction = new TagSelectedFilesAction(controller.getTagsManager().getFollowUpTagName(), controller); //NON-NLS
Platform.runLater(() -> {
try {
TagSelectedFilesAction followUpSelectedACtion = new TagSelectedFilesAction(controller.getTagsManager().getFollowUpTagName(), controller);
tagSelectedSplitMenu.setText(followUpSelectedACtion.getText());
tagSelectedSplitMenu.setGraphic(followUpSelectedACtion.getGraphic());
tagSelectedSplitMenu.setOnAction(followUpSelectedACtion);
} catch (TskCoreException tskCoreException) {
LOGGER.log(Level.WARNING, "failed to load FollowUpTagName", tskCoreException); //NON-NLS
}
tagSelectedSplitMenu.setText(followUpSelectedAction.getText());
tagSelectedSplitMenu.setGraphic(followUpSelectedAction.getGraphic());
tagSelectedSplitMenu.setOnAction(followUpSelectedAction);
tagSelectedSplitMenu.showingProperty().addListener(showing -> {
if (tagSelectedSplitMenu.isShowing()) {
List<MenuItem> selTagMenues = Lists.transform(controller.getTagsManager().getNonCategoryTagNames(),
tagName -> GuiUtils.createAutoAssigningMenuItem(tagSelectedSplitMenu, new TagSelectedFilesAction(tagName, controller)));
tagSelectedSplitMenu.getItems().setAll(selTagMenues);
ListenableFuture<List<MenuItem>> getTagsFuture = exec.submit(()
-> 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);
catSelectedSplitMenu.setOnAction(cat5SelectedAction);
catSelectedSplitMenu.setText(cat5SelectedAction.getText());
catSelectedSplitMenu.setGraphic(cat5SelectedAction.getGraphic());
catSelectedSplitMenu.showingProperty().addListener(showing -> {
@ -516,7 +534,7 @@ public class GroupPane extends BorderPane {
//listen to tile selection and make sure it is visible in scroll area
selectionModel.lastSelectedProperty().addListener((observable, oldFileID, newFileId) -> {
if (groupViewMode.get() == GroupViewMode.SLIDE_SHOW
&& slideShowPane != null) {
&& slideShowPane != null) {
slideShowPane.setFile(newFileId);
} else {
scrollToFileID(newFileId);
@ -832,23 +850,25 @@ public class GroupPane extends BorderPane {
private ContextMenu buildContextMenu() {
ArrayList<MenuItem> menuItems = new ArrayList<>();
menuItems.add(CategorizeAction.getCategoriesMenu(controller));
menuItems.add(AddTagAction.getTagMenu(controller));
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()));
}
}
try {
menuItems.add(AddTagAction.getTagMenu(controller));
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error building tagging context menu.", ex);
}
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());
extractMenuItem.setOnAction((ActionEvent t) -> {
extractMenuItem.setOnAction(actionEvent -> {
SwingUtilities.invokeLater(() -> {
TopComponent etc = WindowManager.getDefault().findTopComponent(ImageGalleryTopComponent.PREFERRED_ID);
ExtractAction.getInstance().actionPerformed(new java.awt.event.ActionEvent(etc, 0, null));
@ -857,7 +877,9 @@ public class GroupPane extends BorderPane {
menuItems.add(extractMenuItem);
ContextMenu contextMenu = new ContextMenu(menuItems.toArray(new MenuItem[]{}));
contextMenu.setAutoHide(true);
contextMenu.setAutoHide(
true);
return contextMenu;
}

View File

@ -18,13 +18,20 @@
*/
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.Executors;
import javafx.concurrent.Task;
/**
*
*/
public class TaskUtils {
public final class TaskUtils {
private TaskUtils() {
}
public static <T> Task<T> taskFrom(Callable<T> callable) {
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
#Mon, 25 Jun 2018 17:19:36 -0400
#Mon, 03 Sep 2018 17:29:44 +0200
LBL_splash_window_title=Starting Autopsy
SPLASH_HEIGHT=314
SPLASH_WIDTH=538

View File

@ -1,4 +1,4 @@
#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_No_Project=Autopsy 4.8.0