19 package org.sleuthkit.autopsy.contentviewers;
22 import java.awt.Dimension;
23 import java.awt.EventQueue;
24 import java.awt.event.ActionEvent;
25 import java.util.Collections;
26 import java.util.List;
27 import static java.util.Objects.nonNull;
28 import java.util.SortedSet;
29 import java.util.concurrent.ExecutionException;
30 import java.util.stream.Collectors;
31 import javafx.application.Platform;
32 import javafx.concurrent.Task;
33 import javafx.embed.swing.JFXPanel;
34 import javafx.geometry.Pos;
35 import javafx.scene.Cursor;
36 import javafx.scene.Scene;
37 import javafx.scene.control.Button;
38 import javafx.scene.control.Label;
39 import javafx.scene.control.ProgressBar;
40 import javafx.scene.image.Image;
41 import javafx.scene.image.ImageView;
42 import javafx.scene.layout.BorderPane;
43 import javafx.scene.layout.VBox;
44 import javax.imageio.ImageIO;
45 import javax.swing.JPanel;
46 import org.controlsfx.control.MaskerPane;
47 import org.openide.util.NbBundle;
48 import org.python.google.common.collect.Lists;
59 @NbBundle.Messages({
"MediaViewImagePanel.externalViewerButton.text=Open in External Viewer",
60 "MediaViewImagePanel.errorLabel.text=Could not load file into Media View.",
61 "MediaViewImagePanel.errorLabel.OOMText=Could not load file into Media View: insufficent memory."})
62 @SuppressWarnings(
"PMD.SingularField")
63 class MediaViewImagePanel
extends JPanel implements MediaFileViewer.MediaViewPanel {
65 private static final Image EXTERNAL =
new Image(MediaViewImagePanel.class.getResource(
"/org/sleuthkit/autopsy/images/external.png").toExternalForm());
67 private final boolean fxInited;
69 private JFXPanel fxPanel;
70 private ImageView fxImageView;
71 private BorderPane borderpane;
72 private final ProgressBar progressBar =
new ProgressBar();
73 private final MaskerPane maskerPane =
new MaskerPane();
76 ImageIO.scanForPlugins();
83 static private final SortedSet<String> supportedMimes = ImageUtils.getSupportedImageMimeTypes();
88 static private final List<String> supportedExtensions = ImageUtils.getSupportedImageExtensions().stream()
90 .collect(Collectors.toList());
92 private Task<Image> readImageTask;
97 public MediaViewImagePanel() {
101 Platform.runLater(() -> {
104 fxImageView =
new ImageView();
105 borderpane =
new BorderPane(fxImageView);
106 borderpane.getStyleClass().add(
"bg");
107 fxPanel =
new JFXPanel();
108 Scene scene =
new Scene(borderpane);
109 scene.getStylesheets().add(MediaViewImagePanel.class.getResource(
"MediaViewImagePanel.css").toExternalForm());
110 fxPanel.setScene(scene);
113 fxImageView.fitWidthProperty().bind(scene.widthProperty());
114 fxImageView.fitHeightProperty().bind(scene.heightProperty());
115 fxImageView.setPreserveRatio(
true);
116 fxImageView.setSmooth(
true);
117 fxImageView.setCache(
true);
119 EventQueue.invokeLater(() -> {
126 public boolean isInited() {
133 public void reset() {
134 Platform.runLater(() -> {
135 fxImageView.setImage(null);
136 borderpane.setCenter(null);
140 private void showErrorNode(String errorMessage, AbstractFile file) {
141 final Button externalViewerButton =
new Button(Bundle.MediaViewImagePanel_externalViewerButton_text(),
new ImageView(EXTERNAL));
142 externalViewerButton.setOnAction(actionEvent
147 new ExternalViewerAction(Bundle.MediaViewImagePanel_externalViewerButton_text(),
new FileNode(file))
148 .actionPerformed(
new ActionEvent(
this, ActionEvent.ACTION_PERFORMED,
""))
151 final VBox errorNode =
new VBox(10,
new Label(errorMessage), externalViewerButton);
152 errorNode.setAlignment(Pos.CENTER);
153 borderpane.setCenter(errorNode);
162 void showImageFx(
final AbstractFile file,
final Dimension dims) {
167 Platform.runLater(() -> {
168 if (readImageTask != null) {
169 readImageTask.cancel();
171 readImageTask = ImageUtils.newReadImageTask(file);
172 readImageTask.setOnSucceeded(succeeded -> {
173 if (!Case.isCaseOpen()) {
185 Image fxImage = readImageTask.get();
186 if (nonNull(fxImage)) {
188 fxImageView.setImage(fxImage);
189 borderpane.setCenter(fxImageView);
191 showErrorNode(Bundle.MediaViewImagePanel_errorLabel_text(), file);
193 }
catch (InterruptedException | ExecutionException ex) {
194 showErrorNode(Bundle.MediaViewImagePanel_errorLabel_text(), file);
196 borderpane.setCursor(Cursor.DEFAULT);
198 readImageTask.setOnFailed(failed -> {
199 if (!Case.isCaseOpen()) {
209 Throwable exception = readImageTask.getException();
210 if (exception instanceof OutOfMemoryError
211 && exception.getMessage().contains(
"Java heap space")) {
212 showErrorNode(Bundle.MediaViewImagePanel_errorLabel_OOMText(), file);
214 showErrorNode(Bundle.MediaViewImagePanel_errorLabel_text(), file);
217 borderpane.setCursor(Cursor.DEFAULT);
220 maskerPane.setProgressNode(progressBar);
221 progressBar.progressProperty().bind(readImageTask.progressProperty());
222 maskerPane.textProperty().bind(readImageTask.messageProperty());
223 borderpane.setCenter(maskerPane);
224 borderpane.setCursor(Cursor.WAIT);
225 new Thread(readImageTask).start();
233 public List<String> getMimeTypes() {
234 return Collections.unmodifiableList(Lists.newArrayList(supportedMimes));
243 public List<String> getExtensionsList() {
244 return getExtensions();
252 public List<String> getExtensions() {
253 return Collections.unmodifiableList(supportedExtensions);
257 public boolean isSupported(AbstractFile file) {
258 return ImageUtils.isImageThumbnailSupported(file);
266 @SuppressWarnings(
"unchecked")
268 private
void initComponents() {
270 setBackground(
new java.awt.Color(0, 0, 0));
271 setLayout(
new javax.swing.BoxLayout(
this, javax.swing.BoxLayout.Y_AXIS));
static boolean isJavaFxInited()