19 package org.sleuthkit.autopsy.corecomponents;
 
   21 import java.awt.Color;
 
   22 import java.awt.Cursor;
 
   23 import java.awt.EventQueue;
 
   24 import java.beans.PropertyChangeEvent;
 
   25 import java.beans.PropertyChangeListener;
 
   26 import java.util.Arrays;
 
   27 import java.util.concurrent.ExecutionException;
 
   28 import java.util.logging.Level;
 
   29 import javax.swing.JOptionPane;
 
   30 import javax.swing.ListSelectionModel;
 
   31 import javax.swing.SwingWorker;
 
   32 import org.netbeans.api.progress.ProgressHandle;
 
   33 import org.openide.DialogDisplayer;
 
   34 import org.openide.NotifyDescriptor;
 
   35 import org.openide.explorer.ExplorerManager;
 
   36 import org.openide.nodes.AbstractNode;
 
   37 import org.openide.nodes.Children;
 
   38 import org.openide.nodes.Node;
 
   39 import org.openide.nodes.NodeEvent;
 
   40 import org.openide.nodes.NodeListener;
 
   41 import org.openide.nodes.NodeMemberEvent;
 
   42 import org.openide.nodes.NodeReorderEvent;
 
   43 import org.openide.util.NbBundle;
 
   62 final class DataResultViewerThumbnail 
extends AbstractDataResultViewer {
 
   64     private static final long serialVersionUID = 1L;
 
   65     private static final Logger logger = Logger.getLogger(DataResultViewerThumbnail.class.getName());
 
   68     private int totalPages;
 
   69     private int curPageImages;
 
   70     private int iconSize = ImageUtils.ICON_SIZE_MEDIUM;
 
   71     private final PageUpdater pageUpdater = 
new PageUpdater();
 
   77     public DataResultViewerThumbnail(ExplorerManager explorerManager) {
 
   78         super(explorerManager);
 
   86     public DataResultViewerThumbnail() {
 
   90     @NbBundle.Messages({
"DataResultViewerThumbnail.thumbnailSizeComboBox.small=Small Thumbnails",
 
   91                 "DataResultViewerThumbnail.thumbnailSizeComboBox.medium=Medium Thumbnails",
 
   92                 "DataResultViewerThumbnail.thumbnailSizeComboBox.large=Large Thumbnails" 
   94     private void initialize() {
 
   97         iconView.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
 
   98         em.addPropertyChangeListener(
new ExplorerManagerNodeSelectionListener());
 
   99         thumbnailSizeComboBox.setModel(
new javax.swing.DefaultComboBoxModel<>(
 
  100                 new String[] {  Bundle.DataResultViewerThumbnail_thumbnailSizeComboBox_small(),
 
  101                                 Bundle.DataResultViewerThumbnail_thumbnailSizeComboBox_medium(),
 
  102                                 Bundle.DataResultViewerThumbnail_thumbnailSizeComboBox_large() }));
 
  114     @SuppressWarnings(
"unchecked")
 
  116     private 
void initComponents() {
 
  118         pageLabel = 
new javax.swing.JLabel();
 
  119         pagesLabel = 
new javax.swing.JLabel();
 
  120         pagePrevButton = 
new javax.swing.JButton();
 
  121         pageNextButton = 
new javax.swing.JButton();
 
  122         imagesLabel = 
new javax.swing.JLabel();
 
  123         imagesRangeLabel = 
new javax.swing.JLabel();
 
  124         pageNumLabel = 
new javax.swing.JLabel();
 
  125         filePathLabel = 
new javax.swing.JLabel();
 
  126         goToPageLabel = 
new javax.swing.JLabel();
 
  127         goToPageField = 
new javax.swing.JTextField();
 
  128         thumbnailSizeComboBox = 
new javax.swing.JComboBox<>();
 
  129         iconView = 
new org.openide.explorer.view.IconView();
 
  131         pageLabel.setText(
org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, 
"DataResultViewerThumbnail.pageLabel.text")); 
 
  133         pagesLabel.setText(
org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, 
"DataResultViewerThumbnail.pagesLabel.text")); 
 
  135         pagePrevButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); 
 
  136         pagePrevButton.setText(
org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, 
"DataResultViewerThumbnail.pagePrevButton.text")); 
 
  137         pagePrevButton.setDisabledIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); 
 
  138         pagePrevButton.setMargin(
new java.awt.Insets(2, 0, 2, 0));
 
  139         pagePrevButton.setPreferredSize(
new java.awt.Dimension(55, 23));
 
  140         pagePrevButton.setRolloverIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"))); 
 
  141         pagePrevButton.addActionListener(
new java.awt.event.ActionListener() {
 
  142             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  143                 pagePrevButtonActionPerformed(evt);
 
  147         pageNextButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"))); 
 
  148         pageNextButton.setText(
org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, 
"DataResultViewerThumbnail.pageNextButton.text")); 
 
  149         pageNextButton.setDisabledIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); 
 
  150         pageNextButton.setMargin(
new java.awt.Insets(2, 0, 2, 0));
 
  151         pageNextButton.setMaximumSize(
new java.awt.Dimension(27, 23));
 
  152         pageNextButton.setMinimumSize(
new java.awt.Dimension(27, 23));
 
  153         pageNextButton.setRolloverIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"))); 
 
  154         pageNextButton.addActionListener(
new java.awt.event.ActionListener() {
 
  155             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  156                 pageNextButtonActionPerformed(evt);
 
  160         imagesLabel.setText(
org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, 
"DataResultViewerThumbnail.imagesLabel.text")); 
 
  162         imagesRangeLabel.setText(
org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, 
"DataResultViewerThumbnail.imagesRangeLabel.text")); 
 
  164         pageNumLabel.setText(
org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, 
"DataResultViewerThumbnail.pageNumLabel.text")); 
 
  166         filePathLabel.setText(
org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, 
"DataResultViewerThumbnail.filePathLabel.text")); 
 
  168         goToPageLabel.setText(
org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, 
"DataResultViewerThumbnail.goToPageLabel.text")); 
 
  170         goToPageField.setText(
org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, 
"DataResultViewerThumbnail.goToPageField.text")); 
 
  171         goToPageField.addActionListener(
new java.awt.event.ActionListener() {
 
  172             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  173                 goToPageFieldActionPerformed(evt);
 
  177         thumbnailSizeComboBox.addActionListener(
new java.awt.event.ActionListener() {
 
  178             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  179                 thumbnailSizeComboBoxActionPerformed(evt);
 
  183         javax.swing.GroupLayout layout = 
new javax.swing.GroupLayout(
this);
 
  184         this.setLayout(layout);
 
  185         layout.setHorizontalGroup(
 
  186             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  187             .addGroup(layout.createSequentialGroup()
 
  188                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  189                     .addGroup(layout.createSequentialGroup()
 
  191                         .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  192                             .addComponent(filePathLabel)
 
  193                             .addGroup(layout.createSequentialGroup()
 
  194                                 .addComponent(pageLabel)
 
  195                                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  196                                 .addComponent(pageNumLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 95, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  197                                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
 
  198                                 .addComponent(pagesLabel)
 
  199                                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
 
  200                                 .addComponent(pagePrevButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  202                                 .addComponent(pageNextButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  203                                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
 
  204                                 .addComponent(goToPageLabel)
 
  205                                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  206                                 .addComponent(goToPageField, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  208                                 .addComponent(imagesLabel)
 
  209                                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  210                                 .addComponent(imagesRangeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  211                                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  212                                 .addComponent(thumbnailSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
 
  213                     .addComponent(iconView, javax.swing.GroupLayout.DEFAULT_SIZE, 563, Short.MAX_VALUE))
 
  216         layout.setVerticalGroup(
 
  217             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  218             .addGroup(layout.createSequentialGroup()
 
  219                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  220                     .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
  221                         .addComponent(pageLabel)
 
  222                         .addComponent(pagesLabel)
 
  223                         .addComponent(pagePrevButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  224                         .addComponent(pageNumLabel))
 
  225                     .addComponent(pageNextButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  226                     .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
  227                         .addComponent(imagesLabel)
 
  228                         .addComponent(imagesRangeLabel)
 
  229                         .addComponent(goToPageLabel)
 
  230                         .addComponent(goToPageField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  231                         .addComponent(thumbnailSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
 
  232                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  233                 .addComponent(iconView, javax.swing.GroupLayout.DEFAULT_SIZE, 330, Short.MAX_VALUE)
 
  234                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  235                 .addComponent(filePathLabel))
 
  239     private void pagePrevButtonActionPerformed(java.awt.event.ActionEvent evt) {
 
  243     private void pageNextButtonActionPerformed(java.awt.event.ActionEvent evt) {
 
  247     private void goToPageFieldActionPerformed(java.awt.event.ActionEvent evt) {
 
  248         goToPage(goToPageField.getText());
 
  251     private void thumbnailSizeComboBoxActionPerformed(java.awt.event.ActionEvent evt) {
 
  253         iconSize = ImageUtils.ICON_SIZE_MEDIUM;   
 
  254         switch (thumbnailSizeComboBox.getSelectedIndex()) {
 
  256                 iconSize = ImageUtils.ICON_SIZE_SMALL;
 
  259                 iconSize = ImageUtils.ICON_SIZE_LARGE;
 
  263         Node root = em.getRootContext();
 
  264         for (Children c : Arrays.asList(root.getChildren())) {
 
  265             ((ThumbnailViewChildren) c).setIconSize(iconSize);
 
  268         for (Node page : root.getChildren().getNodes()) {
 
  269             for (Node node : page.getChildren().getNodes()) {
 
  270                 ((ThumbnailViewNode) node).setIconSize(iconSize);
 
  279         em.setExploredContext(root);
 
  284     private javax.swing.JLabel filePathLabel;
 
  285     private javax.swing.JTextField goToPageField;
 
  286     private javax.swing.JLabel goToPageLabel;
 
  287     private org.openide.explorer.view.IconView iconView;
 
  288     private javax.swing.JLabel imagesLabel;
 
  289     private javax.swing.JLabel imagesRangeLabel;
 
  290     private javax.swing.JLabel pageLabel;
 
  291     private javax.swing.JButton pageNextButton;
 
  292     private javax.swing.JLabel pageNumLabel;
 
  293     private javax.swing.JButton pagePrevButton;
 
  294     private javax.swing.JLabel pagesLabel;
 
  295     private javax.swing.JComboBox<String> thumbnailSizeComboBox;
 
  299     public boolean isSupported(Node selectedNode) {
 
  300         if (selectedNode == null) {
 
  307     public void setNode(Node givenNode) {
 
  309         setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
 
  311             if (givenNode != null) {
 
  312                 ThumbnailViewChildren childNode = 
new ThumbnailViewChildren(givenNode, iconSize);
 
  314                 final Node root = 
new AbstractNode(childNode);
 
  315                 pageUpdater.setRoot(root);
 
  316                 root.addNodeListener(pageUpdater);
 
  317                 em.setRootContext(root);
 
  319                 Node emptyNode = 
new AbstractNode(Children.LEAF);
 
  320                 em.setRootContext(emptyNode); 
 
  322                 iconView.setBackground(Color.BLACK);
 
  325             this.setCursor(null);
 
  330     public String getTitle() {
 
  331         return NbBundle.getMessage(this.getClass(), 
"DataResultViewerThumbnail.title");
 
  335     public DataResultViewer createInstance() {
 
  336         return new DataResultViewerThumbnail();
 
  340     public void resetComponent() {
 
  341         super.resetComponent();
 
  350     public void clearComponent() {
 
  351         this.iconView.removeAll();
 
  352         this.iconView = null;
 
  354         super.clearComponent();
 
  357     private void nextPage() {
 
  358         if (curPage < totalPages) {
 
  365     private void previousPage() {
 
  373     private void goToPage(String pageNumText) {
 
  376             newPage = Integer.parseInt(pageNumText);
 
  377         } 
catch (NumberFormatException e) {
 
  382         if (newPage > totalPages || newPage < 1) {
 
  383             JOptionPane.showMessageDialog(
this,
 
  384                     NbBundle.getMessage(
this.getClass(),
 
  385                             "DataResultViewerThumbnail.goToPageTextField.msgDlg",
 
  387                     NbBundle.getMessage(
this.getClass(),
 
  388                             "DataResultViewerThumbnail.goToPageTextField.err"),
 
  389                     JOptionPane.WARNING_MESSAGE);
 
  397     private void switchPage() {
 
  399         EventQueue.invokeLater(() -> {
 
  400             setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
 
  404         new SwingWorker<Object, Void>() {
 
  405             private ProgressHandle progress;
 
  408             protected Object doInBackground() throws Exception {
 
  409                 pagePrevButton.setEnabled(
false);
 
  410                 pageNextButton.setEnabled(
false);
 
  411                 goToPageField.setEnabled(
false);
 
  412                 progress = ProgressHandle.createHandle(
 
  413                         NbBundle.getMessage(
this.getClass(), 
"DataResultViewerThumbnail.genThumbs"));
 
  415                 progress.switchToIndeterminate();
 
  416                 Node root = em.getRootContext();
 
  417                 Node pageNode = root.getChildren().getNodeAt(curPage - 1);
 
  418                 em.setExploredContext(pageNode);
 
  419                 curPageImages = pageNode.getChildren().getNodesCount();
 
  424             protected void done() {
 
  431                 } 
catch (InterruptedException | ExecutionException ex) {
 
  433                             = 
new NotifyDescriptor.Message(
 
  434                                     NbBundle.getMessage(
this.getClass(), 
"DataResultViewerThumbnail.switchPage.done.errMsg",
 
  436                                     NotifyDescriptor.ERROR_MESSAGE);
 
  437                     DialogDisplayer.getDefault().notify(d);
 
  438                     logger.log(Level.SEVERE, 
"Error making thumbnails: {0}", ex.getMessage()); 
 
  440                 catch (java.util.concurrent.CancellationException ex) {
 
  447     private void updateControls() {
 
  448         if (totalPages == 0) {
 
  449             pagePrevButton.setEnabled(
false);
 
  450             pageNextButton.setEnabled(
false);
 
  451             goToPageField.setEnabled(
false);
 
  452             pageNumLabel.setText(
"");
 
  453             imagesRangeLabel.setText(
"");
 
  454             thumbnailSizeComboBox.setEnabled(
false);
 
  456             pageNumLabel.setText(
 
  457                     NbBundle.getMessage(
this.getClass(), 
"DataResultViewerThumbnail.pageNumbers.curOfTotal",
 
  458                             Integer.toString(curPage), Integer.toString(totalPages)));
 
  459             final int imagesFrom = (curPage - 1) * ThumbnailViewChildren.IMAGES_PER_PAGE + 1;
 
  460             final int imagesTo = curPageImages + (curPage - 1) * ThumbnailViewChildren.IMAGES_PER_PAGE;
 
  461             imagesRangeLabel.setText(imagesFrom + 
"-" + imagesTo);
 
  463             pageNextButton.setEnabled(!(curPage == totalPages));
 
  464             pagePrevButton.setEnabled(!(curPage == 1));
 
  465             goToPageField.setEnabled(totalPages > 1);
 
  466             thumbnailSizeComboBox.setEnabled(
true);
 
  478         void setRoot(Node root) {
 
  488             totalPages = root.getChildren().getNodesCount();
 
  490             if (totalPages == 0) {
 
  496             if (curPage == -1 || curPage > totalPages) {
 
  501             final Node pageNode = root.getChildren().getNodeAt(curPage - 1);
 
  504             if (pageNode != null) {
 
  505                 pageNode.addNodeListener(
new NodeListener() {
 
  508                         curPageImages = pageNode.getChildren().getNodesCount();
 
  531                 em.setExploredContext(pageNode);
 
  558             if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
 
  559                 setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
 
  561                     Node[] selectedNodes = em.getSelectedNodes();
 
  562                     if (selectedNodes.length == 1) {
 
  563                         AbstractFile af = selectedNodes[0].getLookup().lookup(AbstractFile.class);
 
  565                             filePathLabel.setText(
"");
 
  568                                 String uPath = af.getUniquePath();
 
  569                                 filePathLabel.setText(uPath);
 
  570                                 filePathLabel.setToolTipText(uPath);
 
  571                             } 
catch (TskCoreException e) {
 
  572                                 logger.log(Level.WARNING, 
"Could not get unique path for content: {0}", af.getName()); 
 
  576                         filePathLabel.setText(
"");
 
void propertyChange(PropertyChangeEvent evt)
void nodeDestroyed(NodeEvent ne)
void childrenAdded(NodeMemberEvent nme)
void childrenRemoved(NodeMemberEvent nme)
void propertyChange(PropertyChangeEvent evt)
void childrenReordered(NodeReorderEvent nre)