19 package org.sleuthkit.autopsy.contentviewers.imagetagging;
21 import com.sun.javafx.event.EventDispatchChainImpl;
22 import java.beans.PropertyChangeEvent;
23 import java.beans.PropertyChangeListener;
24 import java.beans.PropertyChangeSupport;
25 import javafx.collections.ListChangeListener;
26 import javafx.scene.Cursor;
27 import javafx.scene.Group;
28 import javafx.scene.Node;
29 import javafx.scene.control.Tooltip;
30 import javafx.scene.image.ImageView;
31 import javafx.scene.input.MouseEvent;
32 import javafx.scene.paint.Color;
33 import javafx.scene.shape.Circle;
34 import javafx.scene.shape.Rectangle;
52 private final PropertyChangeSupport
pcs =
new PropertyChangeSupport(
this);
58 ALL_CHILDREN =
new EventDispatchChainImpl();
59 this.appTag = contentViewerTag;
61 this.getChildren().addListener((ListChangeListener<Node>) change -> {
63 change.getAddedSubList().forEach((node) -> ALL_CHILDREN.append(node.getEventDispatcher()));
67 PhysicalTag physicalTag =
new PhysicalTag(details);
70 Boundary dragBoundary = (x, y) -> {
71 double boundingX = image.getX();
72 double boundingY = image.getY();
73 double width = image.getImage().getWidth();
74 double height = image.getImage().getHeight();
82 EditHandle bottomLeft =
new EditHandle(physicalTag)
83 .setPosition(Position.bottom(), Position.left())
84 .setDrag(dragBoundary, Draggable.bottom(), Draggable.left());
86 EditHandle bottomRight =
new EditHandle(physicalTag)
87 .setPosition(Position.bottom(), Position.right())
88 .setDrag(dragBoundary, Draggable.bottom(), Draggable.right());
90 EditHandle topLeft =
new EditHandle(physicalTag)
91 .setPosition(Position.top(), Position.left())
92 .setDrag(dragBoundary, Draggable.top(), Draggable.left());
94 EditHandle topRight =
new EditHandle(physicalTag)
95 .setPosition(Position.top(), Position.right())
96 .setDrag(dragBoundary, Draggable.top(), Draggable.right());
98 EditHandle bottomMiddle =
new EditHandle(physicalTag)
99 .setPosition(Position.bottom(), Position.xMiddle())
100 .setDrag(dragBoundary, Draggable.bottom());
102 EditHandle topMiddle =
new EditHandle(physicalTag)
103 .setPosition(Position.top(), Position.xMiddle())
104 .setDrag(dragBoundary, Draggable.top());
106 EditHandle rightMiddle =
new EditHandle(physicalTag)
107 .setPosition(Position.right(), Position.yMiddle())
108 .setDrag(dragBoundary, Draggable.right());
110 EditHandle leftMiddle =
new EditHandle(physicalTag)
111 .setPosition(Position.left(), Position.yMiddle())
112 .setDrag(dragBoundary, Draggable.left());
115 this.getChildren().addAll(physicalTag, bottomLeft, bottomRight, topLeft,
116 topRight, bottomMiddle, topMiddle, rightMiddle, leftMiddle);
118 Tooltip.install(
this,
new Tooltip(contentViewerTag.
getContentTag()
119 .getName().getDisplayName()));
132 pcs.addPropertyChangeListener(listener);
147 class PhysicalTag
extends Rectangle {
150 this.setStroke(Color.RED);
151 this.setFill(Color.RED.deriveColor(0, 0, 0, 0));
154 setX(details.
getX());
155 setY(details.
getY());
181 class EditHandle
extends Circle {
183 private final PhysicalTag parent;
185 public EditHandle(PhysicalTag parent) {
186 this.setVisible(
false);
189 this.addEventHandler(ImageTagControls.NOT_FOCUSED, event ->
this.setVisible(
false));
190 this.addEventHandler(ImageTagControls.FOCUSED, event ->
this.setVisible(
true));
192 this.setRadius(parent.getStrokeWidth());
193 this.setFill(parent.getStroke());
195 this.setOnDragDetected(event -> {
196 this.getParent().setCursor(Cursor.CLOSED_HAND);
199 this.setOnMouseReleased(event -> {
200 this.getParent().setCursor(Cursor.DEFAULT);
201 pcs.firePropertyChange(
new PropertyChangeEvent(
this,
"Tag Edit", null, parent.getState()));
204 this.parent = parent;
213 public EditHandle setPosition(Position... vals) {
214 for (Position pos : vals) {
215 parent.widthProperty().addListener((obs, oldVal, newVal) -> pos.set(parent,
this));
216 parent.heightProperty().addListener((obs, oldVal, newVal) -> pos.set(parent,
this));
217 pos.set(parent,
this);
229 public EditHandle setDrag(Boundary bounds, Draggable... vals) {
230 this.setOnMouseDragged((event) -> {
231 for (Draggable drag : vals) {
232 drag.perform(parent, event, bounds);
243 static interface Position {
245 void set(PhysicalTag parent, Circle knob);
247 static Position left() {
248 return (parent, knob) -> knob.centerXProperty().bind(parent.xProperty());
251 static Position right() {
252 return (parent, knob) -> knob.centerXProperty().bind(parent.xProperty().add(parent.getWidth()));
255 static Position top() {
256 return (parent, knob) -> knob.centerYProperty().bind(parent.yProperty());
259 static Position bottom() {
260 return (parent, knob) -> knob.centerYProperty().bind(parent.yProperty().add(parent.getHeight()));
263 static Position xMiddle() {
264 return (parent, knob) -> knob.centerXProperty().bind(parent.xProperty().add(parent.getWidth() / 2));
267 static Position yMiddle() {
268 return (parent, knob) -> knob.centerYProperty().bind(parent.yProperty().add(parent.getHeight() / 2));
276 static interface Boundary {
278 boolean isPointInBounds(
double x,
double y);
285 static interface Draggable {
287 void perform(PhysicalTag parent, MouseEvent event, Boundary b);
289 static Draggable bottom() {
290 return (parent, event, bounds) -> {
291 if (!bounds.isPointInBounds(event.getX(),
event.getY())) {
295 double deltaY =
event.getY() - parent.getY();
297 parent.setHeight(deltaY);
302 static Draggable top() {
303 return (parent, event, bounds) -> {
304 if (!bounds.isPointInBounds(event.getX(),
event.getY())) {
308 double deltaY = parent.getY() + parent.getHeight() -
event.getY();
309 if (deltaY < parent.getY() + parent.getHeight() && deltaY > 0) {
310 parent.setHeight(deltaY);
311 parent.setY(event.getY());
316 static Draggable left() {
317 return (parent, event, bounds) -> {
318 if (!bounds.isPointInBounds(event.getX(),
event.getY())) {
322 double deltaX = parent.getX() + parent.getWidth() -
event.getX();
323 if (deltaX < parent.getX() + parent.getWidth() && deltaX > 0) {
324 parent.setWidth(deltaX);
325 parent.setX(event.getX());
330 static Draggable right() {
331 return (parent, event, bounds) -> {
332 if (!bounds.isPointInBounds(event.getX(),
event.getY())) {
336 double deltaX =
event.getX() - parent.getX();
338 parent.setWidth(deltaX);
final PropertyChangeSupport pcs
ImageTagRegion setHeight(double height)
ImageTagRegion setStrokeThickness(double thickness)
ImageTagRegion setY(double y)
static final EventType< Event > FOCUSED
ImageTagRegion setWidth(double width)
ContentViewerTag< ImageTagRegion > getContentViewerTag()
static final EventType< Event > NOT_FOCUSED
double getStrokeThickness()
ContentTag getContentTag()
final ContentViewerTag< ImageTagRegion > appTag
ImageTag(ContentViewerTag< ImageTagRegion > contentViewerTag, ImageView image)
ImageTagRegion setX(double x)
void subscribeToEditEvents(PropertyChangeListener listener)
final EventDispatchChainImpl ALL_CHILDREN