Merge pull request #1918 from millmanorama/IG-double-click-fix

restrict double click action on SlideShowView to non control areas
This commit is contained in:
Richard Cordovano
2016-02-04 08:56:41 -05:00
5 changed files with 85 additions and 76 deletions
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-15 Basis Technology Corp.
* Copyright 2013-16 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,7 +19,6 @@
package org.sleuthkit.autopsy.imagegallery.gui.drawableviews;
import java.util.Objects;
import java.util.logging.Level;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.WeakChangeListener;
@@ -29,6 +28,8 @@ import javafx.scene.CacheHint;
import javafx.scene.control.Control;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.imagegallery.FXMLConstructor;
@@ -51,11 +52,7 @@ public class DrawableTile extends DrawableTileBase {
private static final Logger LOGGER = Logger.getLogger(DrawableTile.class.getName());
private final ChangeListener<? super Long> lastSelectionListener = (observable, oldValue, newValue) -> {
try {
setEffect(Objects.equals(newValue, getFileID()) ? LAST_SELECTED_EFFECT : null);
} catch (java.lang.IllegalStateException ex) {
Logger.getLogger(DrawableTile.class.getName()).log(Level.WARNING, "Error displaying tile"); //NON-NLS
}
updateSelectionState();
};
@FXML
@@ -73,11 +70,28 @@ public class DrawableTile extends DrawableTileBase {
imageView.fitWidthProperty().bind(Toolbar.getDefault(getController()).sizeSliderValue());
selectionModel.lastSelectedProperty().addListener(new WeakChangeListener<>(lastSelectionListener));
//set up mouse listener
addEventHandler(MouseEvent.MOUSE_CLICKED, clickEvent -> {
if (clickEvent.getButton() == MouseButton.PRIMARY) {
getFile().ifPresent(file -> {
final long fileID = file.getId();
if (clickEvent.isControlDown()) {
selectionModel.toggleSelection(fileID);
} else {
getGroupPane().makeSelection(clickEvent.isShiftDown(), fileID);
}
if (clickEvent.getClickCount() > 1) {
getGroupPane().activateSlideShowViewer(fileID);
}
});
clickEvent.consume();
}
});
}
public DrawableTile(GroupPane gp, ImageGalleryController controller) {
super(gp, controller);
FXMLConstructor.construct(this, "DrawableTile.fxml"); //NON-NLS
}
@@ -87,9 +101,9 @@ public class DrawableTile extends DrawableTileBase {
@Override
protected void updateSelectionState() {
super.updateSelectionState();
final boolean lastSelected = Objects.equals(selectionModel.lastSelectedProperty().get(), getFileID());
Platform.runLater(() -> {
setEffect(lastSelected ? LAST_SELECTED_EFFECT : null);
getFileID().ifPresent(fileID -> {
final boolean lastSelected = Objects.equals(selectionModel.lastSelectedProperty().get(), fileID);
Platform.runLater(() -> setEffect(lastSelected ? LAST_SELECTED_EFFECT : null));
});
}
@@ -102,5 +116,4 @@ public class DrawableTile extends DrawableTileBase {
protected String getTextForLabel() {
return getFile().map(AbstractContent::getName).orElse("");
}
}
@@ -1,8 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-15 Basis Technology Corp.
* Copyright 2013-16 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,9 +25,7 @@ import java.util.Optional;
import java.util.logging.Level;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.WeakInvalidationListener;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.ContextMenu;
@@ -73,7 +70,6 @@ import org.sleuthkit.autopsy.imagegallery.actions.OpenExternalViewerAction;
import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter;
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute;
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile;
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewMode;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
@@ -154,29 +150,14 @@ public abstract class DrawableTileBase extends DrawableUIBase {
selectionModel.getSelected().addListener(new WeakInvalidationListener(selectionListener));
//set up mouse listener
//TODO: split this between DrawableTile and SingleDrawableViewBase
addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
@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()) {
selectionModel.toggleSelection(fileID);
} else {
groupPane.makeSelection(t.isShiftDown(), fileID);
}
} else if (t.getClickCount() > 1) {
if (groupPane.getGroupViewMode() == GroupViewMode.TILE) {
groupPane.activateSlideShowViewer(fileID);
} else {
groupPane.activateTileViewer();
}
}
break;
case SECONDARY:
if (t.getClickCount() == 1) {
if (selectionModel.isSelected(fileID) == false) {
@@ -195,7 +176,6 @@ public abstract class DrawableTileBase extends DrawableUIBase {
break;
}
});
t.consume();
}
@@ -206,8 +186,9 @@ public abstract class DrawableTileBase extends DrawableUIBase {
menuItems.add(new AddDrawableTagAction(getController()).getPopupMenu());
final MenuItem extractMenuItem = new MenuItem(Bundle.DrawableTileBase_menuItem_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));
@@ -215,8 +196,9 @@ public abstract class DrawableTileBase extends DrawableUIBase {
});
menuItems.add(extractMenuItem);
MenuItem contentViewer = new MenuItem(Bundle.DrawableTileBase_menuItem_showContentViewer());
contentViewer.setOnAction((ActionEvent t) -> {
contentViewer.setOnAction(actionEvent -> {
SwingUtilities.invokeLater(() -> {
new NewWindowViewAction(Bundle.DrawableTileBase_menuItem_showContentViewer(), new FileNode(file.getAbstractFile())).actionPerformed(null);
});
@@ -246,7 +228,7 @@ public abstract class DrawableTileBase extends DrawableUIBase {
}
});
}
private final InvalidationListener selectionListener = (Observable observable) -> updateSelectionState();
private final InvalidationListener selectionListener = observable -> updateSelectionState();
GroupPane getGroupPane() {
return groupPane;
@@ -255,7 +237,7 @@ public abstract class DrawableTileBase extends DrawableUIBase {
protected abstract String getTextForLabel();
protected void initialize() {
followUpToggle.setOnAction((ActionEvent event) -> {
followUpToggle.setOnAction(actionEvent -> {
getFile().ifPresent(file -> {
if (followUpToggle.isSelected() == true) {
try {
@@ -265,7 +247,7 @@ public abstract class DrawableTileBase extends DrawableUIBase {
LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); //NON-NLS
}
} else {
new DeleteFollowUpTagAction(getController(), file).handle(event);
new DeleteFollowUpTagAction(getController(), file).handle(actionEvent);
}
});
});
@@ -339,8 +321,8 @@ public abstract class DrawableTileBase extends DrawableUIBase {
* DrawableView
*/
protected void updateSelectionState() {
getFile().ifPresent(file -> {
final boolean selected = selectionModel.isSelected(file.getId());
getFileID().ifPresent(fileID -> {
final boolean selected = selectionModel.isSelected(fileID);
Platform.runLater(() -> setBorder(selected ? SELECTED_BORDER : UNSELECTED_BORDER));
});
}
@@ -353,7 +335,7 @@ public abstract class DrawableTileBase extends DrawableUIBase {
@Subscribe
@Override
public void handleTagAdded(ContentTagAddedEvent evt) {
getFileID().ifPresent((fileID) -> {
getFileID().ifPresent(fileID -> {
try {
final TagName followUpTagName = getController().getTagsManager().getFollowUpTagName();
final ContentTag addedTag = evt.getAddedTag();
@@ -373,7 +355,7 @@ public abstract class DrawableTileBase extends DrawableUIBase {
@Subscribe
@Override
public void handleTagDeleted(ContentTagDeletedEvent evt) {
getFileID().ifPresent((fileID) -> {
getFileID().ifPresent(fileID -> {
try {
final TagName followUpTagName = getController().getTagsManager().getFollowUpTagName();
final ContentTagDeletedEvent.DeletedContentTagInfo deletedTagInfo = evt.getDeletedTagInfo();
@@ -560,7 +560,6 @@ public class GroupPane extends BorderPane {
contextMenu.hide();
}
}
t.consume();
break;
case SECONDARY:
if (t.getClickCount() == 1) {
@@ -574,7 +573,6 @@ public class GroupPane extends BorderPane {
contextMenu.hide();
contextMenu.show(GroupPane.this, t.getScreenX(), t.getScreenY());
}
t.consume();
break;
}
}
@@ -1,14 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.net.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import org.controlsfx.control.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ToggleButton?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<fx:root type="AnchorPane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<fx:root type="AnchorPane" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1">
<children>
<HBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
@@ -27,7 +29,7 @@
</HBox>
<BorderPane fx:id="internalBorderPane" maxWidth="-1.0" prefHeight="-1.0" prefWidth="-1.0" BorderPane.alignment="CENTER" HBox.hgrow="ALWAYS">
<center>
<AnchorPane maxHeight="-1.0" maxWidth="-1.0" minHeight="-Infinity" minWidth="-Infinity" opacity="1.0" prefHeight="-1.0" prefWidth="-1.0" style="-fx-border-width: 1; -fx-border-color: darkgray; -fx-border-radius: 2; -fx-background-color: linear-gradient(to bottom, derive(-fx-base,-30%), derive(-fx-base,-60%)), linear-gradient(to bottom, derive(-fx-base,65%) 2%, derive(-fx-base,-20%) 95%); -fx-background-radius: 2;" BorderPane.alignment="CENTER">
<AnchorPane fx:id="innerPane" maxHeight="-1.0" maxWidth="-1.0" minHeight="-Infinity" minWidth="-Infinity" opacity="1.0" prefHeight="-1.0" prefWidth="-1.0" style="-fx-border-width: 1; -fx-border-color: darkgray; -fx-border-radius: 2; -fx-background-color: linear-gradient(to bottom, derive(-fx-base,-30%), derive(-fx-base,-60%)), linear-gradient(to bottom, derive(-fx-base,65%) 2%, derive(-fx-base,-20%) 95%); -fx-background-radius: 2;" BorderPane.alignment="CENTER">
<children>
<BorderPane maxHeight="-1.0" maxWidth="-1.0" minHeight="-Infinity" minWidth="-Infinity" prefHeight="-1.0" prefWidth="-1.0" snapToPixel="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<bottom>
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-15 Basis Technology Corp.
* Copyright 2013-16 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,7 +27,6 @@ import javafx.application.Platform;
import javafx.beans.Observable;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Button;
@@ -37,7 +36,10 @@ import javafx.scene.image.Image;
import static javafx.scene.input.KeyCode.LEFT;
import static javafx.scene.input.KeyCode.RIGHT;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaException;
import javafx.scene.media.MediaPlayer;
@@ -54,6 +56,7 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.VideoFile;
import org.sleuthkit.autopsy.imagegallery.gui.VideoPlayer;
import static org.sleuthkit.autopsy.imagegallery.gui.drawableviews.DrawableUIBase.exec;
import static org.sleuthkit.autopsy.imagegallery.gui.drawableviews.DrawableView.CAT_BORDER_WIDTH;
import org.sleuthkit.datamodel.AbstractContent;
/**
* Displays the files of a group one at a time. Designed to be embedded in a
@@ -72,6 +75,8 @@ public class SlideShowView extends DrawableTileBase {
@FXML
private BorderPane footer;
@FXML
private Pane innerPane;
private volatile MediaLoadTask mediaTask;
@@ -90,24 +95,33 @@ public class SlideShowView extends DrawableTileBase {
imageView.fitWidthProperty().bind(imageBorder.widthProperty().subtract(CAT_BORDER_WIDTH * 2));
imageView.fitHeightProperty().bind(heightProperty().subtract(CAT_BORDER_WIDTH * 4).subtract(footer.heightProperty()));
leftButton.setOnAction((ActionEvent t) -> {
cycleSlideShowImage(-1);
});
rightButton.setOnAction((ActionEvent t) -> {
cycleSlideShowImage(1);
leftButton.setOnAction(actionEvent -> cycleSlideShowImage(-1));
rightButton.setOnAction(sctionEvent -> cycleSlideShowImage(1));
innerPane.addEventHandler(MouseEvent.MOUSE_CLICKED, clickEvent -> {
if (clickEvent.getButton() == MouseButton.PRIMARY) {
getFile().ifPresent(file -> {
final long fileID = file.getId();
getGroupPane().makeSelection(false, fileID);
if (clickEvent.getClickCount() > 1) {
getGroupPane().activateTileViewer();
}
});
clickEvent.consume();
}
});
//set up key listener equivalents of buttons
addEventFilter(KeyEvent.KEY_PRESSED, (KeyEvent t) -> {
if (t.getEventType() == KeyEvent.KEY_PRESSED) {
switch (t.getCode()) {
addEventFilter(KeyEvent.KEY_PRESSED, keyEvent -> {
if (keyEvent.getEventType() == KeyEvent.KEY_PRESSED) {
switch (keyEvent.getCode()) {
case LEFT:
cycleSlideShowImage(-1);
t.consume();
keyEvent.consume();
break;
case RIGHT:
cycleSlideShowImage(1);
t.consume();
keyEvent.consume();
break;
}
}
@@ -115,12 +129,11 @@ public class SlideShowView extends DrawableTileBase {
syncButtonVisibility();
getGroupPane().grouping().addListener((Observable observable) -> {
getGroupPane().grouping().addListener(observable -> {
syncButtonVisibility();
if (getGroupPane().getGroup() != null) {
getGroupPane().getGroup().getFileIDs().addListener((Observable observable1) -> {
syncButtonVisibility();
});
getGroupPane().getGroup().getFileIDs().addListener((Observable observable1) ->
syncButtonVisibility());
}
});
}
@@ -252,7 +265,7 @@ public class SlideShowView extends DrawableTileBase {
*/
@Override
protected String getTextForLabel() {
return getFile().map(file -> file.getName()).orElse("") + " " + getSupplementalText();
return getFile().map(AbstractContent::getName).orElse("") + " " + getSupplementalText();
}
/**
@@ -266,10 +279,11 @@ public class SlideShowView extends DrawableTileBase {
synchronized private void cycleSlideShowImage(int direction) {
stopVideo();
final int groupSize = getGroupPane().getGroup().getFileIDs().size();
final Integer nextIndex = getFileID().map(fileID -> {
final int currentIndex = getGroupPane().getGroup().getFileIDs().indexOf(fileID);
return (currentIndex + direction + groupSize) % groupSize;
}).orElse(0);
final Integer nextIndex = getFileID()
.map(fileID -> {
final int currentIndex = getGroupPane().getGroup().getFileIDs().indexOf(fileID);
return (currentIndex + direction + groupSize) % groupSize;
}).orElse(0);
setFile(getGroupPane().getGroup().getFileIDs().get(nextIndex));
}