Autopsy  4.19.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ImageTag.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2019 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.contentviewers.imagetagging;
20 
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;
36 
46 public final class ImageTag extends Group {
47 
48  // Used to tell the 8 edit handles to hide if this tag is no longer selected
49  private final EventDispatchChainImpl ALL_CHILDREN;
50 
51  private final PhysicalTag physicalTag;
52 
53  //Notifies listeners that the user has editted the tag boundaries
54  private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
55 
56  //The underlying presistent tag details that this image tag originates from
58 
59  public ImageTag(ContentViewerTag<ImageTagRegion> contentViewerTag, ImageView image) {
60  ALL_CHILDREN = new EventDispatchChainImpl();
61  this.appTag = contentViewerTag;
62 
63  this.getChildren().addListener((ListChangeListener<Node>) change -> {
64  change.next();
65  change.getAddedSubList().forEach((node) -> ALL_CHILDREN.append(node.getEventDispatcher()));
66  });
67 
68  ImageTagRegion details = contentViewerTag.getDetails();
69  physicalTag = new PhysicalTag(details);
70 
71  //Defines the max allowable boundary that a user may drag any given handle.
72  Boundary dragBoundary = (x, y) -> {
73  double boundingX = image.getX();
74  double boundingY = image.getY();
75  double width = image.getImage().getWidth();
76  double height = image.getImage().getHeight();
77 
78  return x > boundingX + details.getStrokeThickness() / 2
79  && x < boundingX + width - details.getStrokeThickness() / 2
80  && y > boundingY + details.getStrokeThickness() / 2
81  && y < boundingY + height - details.getStrokeThickness() / 2;
82  };
83 
84  EditHandle bottomLeft = new EditHandle(physicalTag)
85  .setPosition(Position.bottom(), Position.left())
86  .setDrag(dragBoundary, Draggable.bottom(), Draggable.left());
87 
88  EditHandle bottomRight = new EditHandle(physicalTag)
89  .setPosition(Position.bottom(), Position.right())
90  .setDrag(dragBoundary, Draggable.bottom(), Draggable.right());
91 
92  EditHandle topLeft = new EditHandle(physicalTag)
93  .setPosition(Position.top(), Position.left())
94  .setDrag(dragBoundary, Draggable.top(), Draggable.left());
95 
96  EditHandle topRight = new EditHandle(physicalTag)
97  .setPosition(Position.top(), Position.right())
98  .setDrag(dragBoundary, Draggable.top(), Draggable.right());
99 
100  EditHandle bottomMiddle = new EditHandle(physicalTag)
101  .setPosition(Position.bottom(), Position.xMiddle())
102  .setDrag(dragBoundary, Draggable.bottom());
103 
104  EditHandle topMiddle = new EditHandle(physicalTag)
105  .setPosition(Position.top(), Position.xMiddle())
106  .setDrag(dragBoundary, Draggable.top());
107 
108  EditHandle rightMiddle = new EditHandle(physicalTag)
109  .setPosition(Position.right(), Position.yMiddle())
110  .setDrag(dragBoundary, Draggable.right());
111 
112  EditHandle leftMiddle = new EditHandle(physicalTag)
113  .setPosition(Position.left(), Position.yMiddle())
114  .setDrag(dragBoundary, Draggable.left());
115 
116  //The "logical" tag is the Group
117  this.getChildren().addAll(physicalTag, bottomLeft, bottomRight, topLeft,
118  topRight, bottomMiddle, topMiddle, rightMiddle, leftMiddle);
119 
120  Tooltip.install(this, new Tooltip(contentViewerTag.getContentTag()
121  .getName().getDisplayName()));
122 
123  this.addEventHandler(ImageTagControls.NOT_FOCUSED, event -> ALL_CHILDREN.dispatchEvent(event));
124  this.addEventHandler(ImageTagControls.FOCUSED, event -> ALL_CHILDREN.dispatchEvent(event));
125  }
126 
133  public void subscribeToEditEvents(PropertyChangeListener listener) {
134  pcs.addPropertyChangeListener(listener);
135  }
136 
137  public double getWidth() {
138  return physicalTag.getWidth();
139  }
140 
141  public double getHeight() {
142  return physicalTag.getHeight();
143  }
144 
151  return appTag;
152  }
153 
157  class PhysicalTag extends Rectangle {
158 
159  public PhysicalTag(ImageTagRegion details) {
160  this.setStroke(Color.RED);
161  this.setFill(Color.RED.deriveColor(0, 0, 0, 0));
162  this.setStrokeWidth(details.getStrokeThickness());
163 
164  setX(details.getX());
165  setY(details.getY());
166  setWidth(details.getWidth());
167  setHeight(details.getHeight());
168 
169  this.addEventHandler(ImageTagControls.NOT_FOCUSED, event -> this.setOpacity(1));
170  this.addEventHandler(ImageTagControls.FOCUSED, event -> this.setOpacity(0.5));
171  }
172 
178  public ImageTagRegion getState() {
179  return new ImageTagRegion()
180  .setX(this.getX())
181  .setY(this.getY())
182  .setWidth(this.getWidth())
183  .setHeight(this.getHeight())
184  .setStrokeThickness(this.getStrokeWidth());
185  }
186  }
187 
191  class EditHandle extends Circle {
192 
193  private final PhysicalTag parent;
194 
195  public EditHandle(PhysicalTag parent) {
196  this.setVisible(false);
197 
198  //Hide when the tag is not selected.
199  this.addEventHandler(ImageTagControls.NOT_FOCUSED, event -> this.setVisible(false));
200  this.addEventHandler(ImageTagControls.FOCUSED, event -> this.setVisible(true));
201 
202  this.setRadius(parent.getStrokeWidth());
203  this.setFill(parent.getStroke());
204 
205  this.setOnDragDetected(event -> {
206  this.getParent().setCursor(Cursor.CLOSED_HAND);
207  });
208 
209  this.setOnMouseReleased(event -> {
210  this.getParent().setCursor(Cursor.DEFAULT);
211  pcs.firePropertyChange(new PropertyChangeEvent(this, "Tag Edit", null, parent.getState()));
212  });
213 
214  this.parent = parent;
215  }
216 
223  public EditHandle setPosition(Position... vals) {
224  for (Position pos : vals) {
225  parent.widthProperty().addListener((obs, oldVal, newVal) -> pos.set(parent, this));
226  parent.heightProperty().addListener((obs, oldVal, newVal) -> pos.set(parent, this));
227  pos.set(parent, this);
228  }
229  return this;
230  }
231 
239  public EditHandle setDrag(Boundary bounds, Draggable... vals) {
240  this.setOnMouseDragged((event) -> {
241  for (Draggable drag : vals) {
242  drag.perform(parent, event, bounds);
243  }
244  });
245  return this;
246  }
247  }
248 
253  static interface Position {
254 
255  void set(PhysicalTag parent, Circle knob);
256 
257  static Position left() {
258  return (parent, knob) -> knob.centerXProperty().bind(parent.xProperty());
259  }
260 
261  static Position right() {
262  return (parent, knob) -> knob.centerXProperty().bind(parent.xProperty().add(parent.getWidth()));
263  }
264 
265  static Position top() {
266  return (parent, knob) -> knob.centerYProperty().bind(parent.yProperty());
267  }
268 
269  static Position bottom() {
270  return (parent, knob) -> knob.centerYProperty().bind(parent.yProperty().add(parent.getHeight()));
271  }
272 
273  static Position xMiddle() {
274  return (parent, knob) -> knob.centerXProperty().bind(parent.xProperty().add(parent.getWidth() / 2));
275  }
276 
277  static Position yMiddle() {
278  return (parent, knob) -> knob.centerYProperty().bind(parent.yProperty().add(parent.getHeight() / 2));
279  }
280  }
281 
285  @FunctionalInterface
286  static interface Boundary {
287 
288  boolean isPointInBounds(double x, double y);
289  }
290 
295  static interface Draggable {
296 
297  void perform(PhysicalTag parent, MouseEvent event, Boundary b);
298 
299  static Draggable bottom() {
300  return (parent, event, bounds) -> {
301  if (!bounds.isPointInBounds(event.getX(), event.getY())) {
302  return;
303  }
304 
305  double deltaY = event.getY() - parent.getY();
306  if (deltaY > 0) {
307  parent.setHeight(deltaY);
308  }
309  };
310  }
311 
312  static Draggable top() {
313  return (parent, event, bounds) -> {
314  if (!bounds.isPointInBounds(event.getX(), event.getY())) {
315  return;
316  }
317 
318  double deltaY = parent.getY() + parent.getHeight() - event.getY();
319  if (deltaY < parent.getY() + parent.getHeight() && deltaY > 0) {
320  parent.setHeight(deltaY);
321  parent.setY(event.getY());
322  }
323  };
324  }
325 
326  static Draggable left() {
327  return (parent, event, bounds) -> {
328  if (!bounds.isPointInBounds(event.getX(), event.getY())) {
329  return;
330  }
331 
332  double deltaX = parent.getX() + parent.getWidth() - event.getX();
333  if (deltaX < parent.getX() + parent.getWidth() && deltaX > 0) {
334  parent.setWidth(deltaX);
335  parent.setX(event.getX());
336  }
337  };
338  }
339 
340  static Draggable right() {
341  return (parent, event, bounds) -> {
342  if (!bounds.isPointInBounds(event.getX(), event.getY())) {
343  return;
344  }
345 
346  double deltaX = event.getX() - parent.getX();
347  if (deltaX > 0) {
348  parent.setWidth(deltaX);
349  }
350  };
351  }
352  }
353 }
ContentViewerTag< ImageTagRegion > getContentViewerTag()
Definition: ImageTag.java:150
final ContentViewerTag< ImageTagRegion > appTag
Definition: ImageTag.java:57
ImageTag(ContentViewerTag< ImageTagRegion > contentViewerTag, ImageView image)
Definition: ImageTag.java:59
void subscribeToEditEvents(PropertyChangeListener listener)
Definition: ImageTag.java:133

Copyright © 2012-2021 Basis Technology. Generated on: Fri Aug 6 2021
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.