Autopsy  4.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
MediaViewImagePanel.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2013-15 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.corecomponents;
20 
21 import java.awt.Dimension;
22 import java.awt.EventQueue;
23 import java.awt.event.ActionEvent;
24 import java.util.Collections;
25 import java.util.List;
26 import static java.util.Objects.nonNull;
27 import java.util.SortedSet;
28 import java.util.concurrent.ExecutionException;
29 import java.util.stream.Collectors;
30 import javafx.application.Platform;
31 import javafx.concurrent.Task;
32 import javafx.embed.swing.JFXPanel;
33 import javafx.geometry.Pos;
34 import javafx.scene.Cursor;
35 import javafx.scene.Scene;
36 import javafx.scene.control.Button;
37 import javafx.scene.control.Label;
38 import javafx.scene.control.ProgressBar;
39 import javafx.scene.image.Image;
40 import javafx.scene.image.ImageView;
41 import javafx.scene.layout.BorderPane;
42 import javafx.scene.layout.VBox;
43 import javax.imageio.ImageIO;
44 import javax.swing.JPanel;
45 import org.controlsfx.control.MaskerPane;
46 import org.openide.util.NbBundle;
47 import org.python.google.common.collect.Lists;
53 import org.sleuthkit.datamodel.AbstractFile;
54 
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 public class MediaViewImagePanel extends JPanel implements DataContentViewerMedia.MediaViewPanel {
63 
64  private static final Image EXTERNAL = new Image(MediaViewImagePanel.class.getResource("/org/sleuthkit/autopsy/images/external.png").toExternalForm());
65 
66  private static final Logger LOGGER = Logger.getLogger(MediaViewImagePanel.class.getName());
67 
68  private final boolean fxInited;
69 
70  private JFXPanel fxPanel;
71  private ImageView fxImageView;
72  private BorderPane borderpane;
73  private final ProgressBar progressBar = new ProgressBar();
74  private final MaskerPane maskerPane = new MaskerPane();
75 
76  static {
77  ImageIO.scanForPlugins();
78  }
79 
84  static private final SortedSet<String> supportedMimes = ImageUtils.getSupportedImageMimeTypes();
85 
89  static private final List<String> supportedExtensions = ImageUtils.getSupportedImageExtensions().stream()
90  .map("."::concat) //NOI18N
91  .collect(Collectors.toList());
92 
93  private Task<Image> readImageTask;
94 
99  initComponents();
101  if (fxInited) {
102  Platform.runLater(() -> {
103 
104  // build jfx ui (we could do this in FXML?)
105  fxImageView = new ImageView(); // will hold image
106  borderpane = new BorderPane(fxImageView); // centers and sizes imageview
107  borderpane.getStyleClass().add("bg"); //NOI18N
108  fxPanel = new JFXPanel(); // bridge jfx-swing
109  Scene scene = new Scene(borderpane); //root of jfx tree
110  scene.getStylesheets().add(MediaViewImagePanel.class.getResource("MediaViewImagePanel.css").toExternalForm()); //NOI18N
111  fxPanel.setScene(scene);
112 
113  //bind size of image to that of scene, while keeping proportions
114  fxImageView.fitWidthProperty().bind(scene.widthProperty());
115  fxImageView.fitHeightProperty().bind(scene.heightProperty());
116  fxImageView.setPreserveRatio(true);
117  fxImageView.setSmooth(true);
118  fxImageView.setCache(true);
119 
120  EventQueue.invokeLater(() -> {
121  add(fxPanel);//add jfx ui to JPanel
122  });
123  });
124  }
125  }
126 
127  public boolean isInited() {
128  return fxInited;
129  }
130 
134  public void reset() {
135  Platform.runLater(() -> {
136  fxImageView.setImage(null);
137  borderpane.setCenter(null);
138  });
139  }
140 
141  private void showErrorNode(String errorMessage, AbstractFile file) {
142  final Button externalViewerButton = new Button(Bundle.MediaViewImagePanel_externalViewerButton_text(), new ImageView(EXTERNAL));
143  externalViewerButton.setOnAction(actionEvent -> //fx ActionEvent
144  /*
145  * TODO: why is the name passed into the action constructor? it
146  * means we duplicate this string all over the place -jm
147  */
148  new ExternalViewerAction(Bundle.MediaViewImagePanel_externalViewerButton_text(), new FileNode(file))
149  .actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "")) //Swing ActionEvent
150  );
151 
152  final VBox errorNode = new VBox(10, new Label(errorMessage), externalViewerButton);
153  errorNode.setAlignment(Pos.CENTER);
154  borderpane.setCenter(errorNode);
155  }
156 
163  void showImageFx(final AbstractFile file, final Dimension dims) {
164  if (!fxInited) {
165  return;
166  }
167 
168  Platform.runLater(() -> {
169  if (readImageTask != null) {
170  readImageTask.cancel();
171  }
172  readImageTask = ImageUtils.newReadImageTask(file);
173  readImageTask.setOnSucceeded(succeeded -> {
174  //Note that all error conditions are allready logged in readImageTask.succeeded()
175  if (!Case.isCaseOpen()) {
176  /*
177  * handle in-between condition when case is being closed and
178  * an image was previously selected
179  *
180  * NOTE: I think this is unnecessary -jm
181  */
182  reset();
183  return;
184  }
185 
186  try {
187  Image fxImage = readImageTask.get();
188  if (nonNull(fxImage)) {
189  //we have non-null image show it
190  fxImageView.setImage(fxImage);
191  borderpane.setCenter(fxImageView);
192  } else {
193  showErrorNode(Bundle.MediaViewImagePanel_errorLabel_text(), file);
194  }
195  } catch (InterruptedException | ExecutionException ex) {
196  showErrorNode(Bundle.MediaViewImagePanel_errorLabel_text(), file);
197  }
198  borderpane.setCursor(Cursor.DEFAULT);
199  });
200  readImageTask.setOnFailed(failed -> {
201  if (!Case.isCaseOpen()) {
202  /*
203  * handle in-between condition when case is being closed and
204  * an image was previously selected
205  *
206  * NOTE: I think this is unnecessary -jm
207  */
208  reset();
209  return;
210  }
211  Throwable exception = readImageTask.getException();
212  if (exception instanceof OutOfMemoryError
213  && exception.getMessage().contains("Java heap space")) {
214  showErrorNode(Bundle.MediaViewImagePanel_errorLabel_OOMText(), file);
215  } else {
216  showErrorNode(Bundle.MediaViewImagePanel_errorLabel_text(), file);
217  }
218 
219  borderpane.setCursor(Cursor.DEFAULT);
220  });
221 
222  maskerPane.setProgressNode(progressBar);
223  progressBar.progressProperty().bind(readImageTask.progressProperty());
224  maskerPane.textProperty().bind(readImageTask.messageProperty());
225  borderpane.setCenter(maskerPane);
226  borderpane.setCursor(Cursor.WAIT);
227  new Thread(readImageTask).start();
228  });
229  }
230 
234  @Override
235  public List<String> getMimeTypes() {
236  return Collections.unmodifiableList(Lists.newArrayList(supportedMimes));
237  }
238 
244  @Override
245  public List<String> getExtensionsList() {
246  return getExtensions();
247  }
248 
254  public List<String> getExtensions() {
255  return Collections.unmodifiableList(supportedExtensions);
256  }
257 
258  @Override
259  public boolean isSupported(AbstractFile file) {
261  }
262 
268  @SuppressWarnings("unchecked")
269  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
270  private void initComponents() {
271 
272  setBackground(new java.awt.Color(0, 0, 0));
273  setLayout(new javax.swing.BoxLayout(this, javax.swing.BoxLayout.Y_AXIS));
274  }// </editor-fold>//GEN-END:initComponents
275  // Variables declaration - do not modify//GEN-BEGIN:variables
276  // End of variables declaration//GEN-END:variables
277 
278 }
static List< String > getSupportedImageExtensions()
synchronized static Logger getLogger(String name)
Definition: Logger.java:166
static boolean isImageThumbnailSupported(AbstractFile file)
void showErrorNode(String errorMessage, AbstractFile file)
static SortedSet< String > getSupportedImageMimeTypes()

Copyright © 2012-2015 Basis Technology. Generated on: Wed Apr 6 2016
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.