Autopsy  4.12.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
DataResultViewerThumbnail.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2012-2018 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.Color;
22 import java.awt.Cursor;
23 import java.awt.Dialog;
24 import java.awt.EventQueue;
25 import java.beans.PropertyChangeEvent;
26 import java.beans.PropertyChangeListener;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.concurrent.ExecutionException;
30 import java.util.function.Function;
31 import java.util.logging.Level;
32 import java.util.prefs.Preferences;
33 import java.util.stream.Collectors;
34 import javax.swing.JOptionPane;
35 import javax.swing.ListSelectionModel;
36 import javax.swing.SortOrder;
37 import javax.swing.SwingWorker;
38 import org.apache.commons.lang3.StringUtils;
39 import org.netbeans.api.progress.ProgressHandle;
40 import org.openide.DialogDescriptor;
41 import org.openide.DialogDisplayer;
42 import org.openide.NotifyDescriptor;
43 import org.openide.explorer.ExplorerManager;
44 import org.openide.nodes.AbstractNode;
45 import org.openide.nodes.Children;
46 import org.openide.nodes.Node;
47 import org.openide.nodes.NodeEvent;
48 import org.openide.nodes.NodeListener;
49 import org.openide.nodes.NodeMemberEvent;
50 import org.openide.nodes.NodeReorderEvent;
51 import org.openide.util.NbBundle;
52 import org.openide.util.NbPreferences;
53 import org.openide.util.lookup.ServiceProvider;
55 import static org.sleuthkit.autopsy.corecomponents.Bundle.*;
59 import org.sleuthkit.datamodel.AbstractFile;
60 import org.sleuthkit.datamodel.TskCoreException;
61 
73 @ServiceProvider(service = DataResultViewer.class)
74 @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
76 
77  private static final long serialVersionUID = 1L;
78  private static final Logger logger = Logger.getLogger(DataResultViewerThumbnail.class.getName());
79  private final PageUpdater pageUpdater = new PageUpdater();
81  private ThumbnailViewChildren rootNodeChildren;
83  private int currentPage;
84  private int totalPages;
85  private int currentPageImages;
86  private int thumbSize = ImageUtils.ICON_SIZE_MEDIUM;
87 
96  this(null);
97  }
98 
108  @NbBundle.Messages({
109  "DataResultViewerThumbnail.thumbnailSizeComboBox.small=Small Thumbnails",
110  "DataResultViewerThumbnail.thumbnailSizeComboBox.medium=Medium Thumbnails",
111  "DataResultViewerThumbnail.thumbnailSizeComboBox.large=Large Thumbnails"
112  })
113  public DataResultViewerThumbnail(ExplorerManager explorerManager) {
114  super(explorerManager);
115  initComponents();
116  iconView.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
117  thumbnailSizeComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(new String[]{
118  Bundle.DataResultViewerThumbnail_thumbnailSizeComboBox_small(),
119  Bundle.DataResultViewerThumbnail_thumbnailSizeComboBox_medium(),
120  Bundle.DataResultViewerThumbnail_thumbnailSizeComboBox_large()}));
121  thumbnailSizeComboBox.setSelectedIndex(1);
122  currentPage = -1;
123  totalPages = 0;
124  currentPageImages = 0;
125 
126  // The GUI builder is using FlowLayout therefore this change so have no
127  // impact on the initally designed layout. This change will just effect
128  // how the components are laid out as size of the window changes.
129  buttonBarPanel.setLayout(new WrapLayout(java.awt.FlowLayout.LEFT));
130  }
131 
137  @SuppressWarnings("unchecked")
138  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
139  private void initComponents() {
140  java.awt.GridBagConstraints gridBagConstraints;
141 
142  buttonBarPanel = new javax.swing.JPanel();
143  pagesPanel = new javax.swing.JPanel();
144  pageNumberPane = new javax.swing.JPanel();
145  pageLabel = new javax.swing.JLabel();
146  pageNumLabel = new javax.swing.JLabel();
147  pageButtonPanel = new javax.swing.JPanel();
148  pagesLabel = new javax.swing.JLabel();
149  pagePrevButton = new javax.swing.JButton();
150  pageNextButton = new javax.swing.JButton();
151  pageGotoPane = new javax.swing.JPanel();
152  goToPageLabel = new javax.swing.JLabel();
153  goToPageField = new javax.swing.JTextField();
154  imagePane = new javax.swing.JPanel();
155  imagesLabel = new javax.swing.JLabel();
156  imagesRangeLabel = new javax.swing.JLabel();
157  thumbnailSizeComboBox = new javax.swing.JComboBox<>();
158  sortPane = new javax.swing.JPanel();
159  sortLabel = new javax.swing.JLabel();
160  sortButton = new javax.swing.JButton();
161  filePathLabel = new javax.swing.JLabel();
162  iconView = new org.openide.explorer.view.IconView();
163 
164  setLayout(new java.awt.BorderLayout());
165 
166  buttonBarPanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));
167 
168  pagesPanel.setLayout(new java.awt.GridBagLayout());
169 
170  pageNumberPane.setLayout(new java.awt.GridBagLayout());
171 
172  pageLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pageLabel.text")); // NOI18N
173  gridBagConstraints = new java.awt.GridBagConstraints();
174  gridBagConstraints.gridx = 0;
175  gridBagConstraints.gridy = 0;
176  gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
177  gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
178  gridBagConstraints.weighty = 1.0;
179  gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 9);
180  pageNumberPane.add(pageLabel, gridBagConstraints);
181 
182  pageNumLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pageNumLabel.text")); // NOI18N
183  gridBagConstraints = new java.awt.GridBagConstraints();
184  gridBagConstraints.gridx = 1;
185  gridBagConstraints.gridy = 0;
186  gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
187  gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
188  gridBagConstraints.weightx = 1.0;
189  gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 15);
190  pageNumberPane.add(pageNumLabel, gridBagConstraints);
191 
192  gridBagConstraints = new java.awt.GridBagConstraints();
193  gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
194  gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
195  pagesPanel.add(pageNumberPane, gridBagConstraints);
196 
197  buttonBarPanel.add(pagesPanel);
198 
199  pageButtonPanel.setLayout(new java.awt.GridBagLayout());
200 
201  pagesLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pagesLabel.text")); // NOI18N
202  gridBagConstraints = new java.awt.GridBagConstraints();
203  gridBagConstraints.gridx = 0;
204  gridBagConstraints.gridy = 0;
205  gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
206  gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
207  gridBagConstraints.weighty = 1.0;
208  gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 9);
209  pageButtonPanel.add(pagesLabel, gridBagConstraints);
210 
211  pagePrevButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); // NOI18N
212  pagePrevButton.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pagePrevButton.text")); // NOI18N
213  pagePrevButton.setBorder(null);
214  pagePrevButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); // NOI18N
215  pagePrevButton.setFocusable(false);
216  pagePrevButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
217  pagePrevButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
218  pagePrevButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"))); // NOI18N
219  pagePrevButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
220  pagePrevButton.addActionListener(new java.awt.event.ActionListener() {
221  public void actionPerformed(java.awt.event.ActionEvent evt) {
222  pagePrevButtonActionPerformed(evt);
223  }
224  });
225  gridBagConstraints = new java.awt.GridBagConstraints();
226  gridBagConstraints.gridx = 1;
227  gridBagConstraints.gridy = 0;
228  gridBagConstraints.gridheight = 2;
229  gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
230  pageButtonPanel.add(pagePrevButton, gridBagConstraints);
231 
232  pageNextButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"))); // NOI18N
233  pageNextButton.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pageNextButton.text")); // NOI18N
234  pageNextButton.setBorder(null);
235  pageNextButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); // NOI18N
236  pageNextButton.setFocusable(false);
237  pageNextButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
238  pageNextButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
239  pageNextButton.setMaximumSize(new java.awt.Dimension(27, 23));
240  pageNextButton.setMinimumSize(new java.awt.Dimension(27, 23));
241  pageNextButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"))); // NOI18N
242  pageNextButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
243  pageNextButton.addActionListener(new java.awt.event.ActionListener() {
244  public void actionPerformed(java.awt.event.ActionEvent evt) {
245  pageNextButtonActionPerformed(evt);
246  }
247  });
248  gridBagConstraints = new java.awt.GridBagConstraints();
249  gridBagConstraints.gridx = 2;
250  gridBagConstraints.gridy = 0;
251  gridBagConstraints.gridheight = 2;
252  gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
253  gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 15);
254  pageButtonPanel.add(pageNextButton, gridBagConstraints);
255 
256  buttonBarPanel.add(pageButtonPanel);
257 
258  pageGotoPane.setLayout(new java.awt.GridBagLayout());
259 
260  goToPageLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.goToPageLabel.text")); // NOI18N
261  gridBagConstraints = new java.awt.GridBagConstraints();
262  gridBagConstraints.gridx = 0;
263  gridBagConstraints.gridy = 0;
264  gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
265  gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
266  gridBagConstraints.weighty = 1.0;
267  gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 9);
268  pageGotoPane.add(goToPageLabel, gridBagConstraints);
269 
270  goToPageField.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.goToPageField.text")); // NOI18N
271  goToPageField.addActionListener(new java.awt.event.ActionListener() {
272  public void actionPerformed(java.awt.event.ActionEvent evt) {
273  goToPageFieldActionPerformed(evt);
274  }
275  });
276  gridBagConstraints = new java.awt.GridBagConstraints();
277  gridBagConstraints.gridx = 1;
278  gridBagConstraints.gridy = 0;
279  gridBagConstraints.gridheight = 2;
280  gridBagConstraints.ipadx = 75;
281  gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
282  gridBagConstraints.weightx = 1.0;
283  gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 15);
284  pageGotoPane.add(goToPageField, gridBagConstraints);
285 
286  buttonBarPanel.add(pageGotoPane);
287 
288  imagePane.setLayout(new java.awt.GridBagLayout());
289 
290  imagesLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.imagesLabel.text")); // NOI18N
291  gridBagConstraints = new java.awt.GridBagConstraints();
292  gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 9);
293  imagePane.add(imagesLabel, gridBagConstraints);
294 
295  imagesRangeLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.imagesRangeLabel.text")); // NOI18N
296  gridBagConstraints = new java.awt.GridBagConstraints();
297  gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 15);
298  imagePane.add(imagesRangeLabel, gridBagConstraints);
299 
300  buttonBarPanel.add(imagePane);
301 
302  thumbnailSizeComboBox.addActionListener(new java.awt.event.ActionListener() {
303  public void actionPerformed(java.awt.event.ActionEvent evt) {
304  thumbnailSizeComboBoxActionPerformed(evt);
305  }
306  });
307  buttonBarPanel.add(thumbnailSizeComboBox);
308 
309  sortPane.setLayout(new java.awt.GridBagLayout());
310 
311  sortLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.sortLabel.text")); // NOI18N
312  gridBagConstraints = new java.awt.GridBagConstraints();
313  gridBagConstraints.gridx = 1;
314  gridBagConstraints.gridy = 0;
315  gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
316  gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
317  gridBagConstraints.weighty = 1.0;
318  sortPane.add(sortLabel, gridBagConstraints);
319 
320  sortButton.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.sortButton.text")); // NOI18N
321  sortButton.addActionListener(new java.awt.event.ActionListener() {
322  public void actionPerformed(java.awt.event.ActionEvent evt) {
323  sortButtonActionPerformed(evt);
324  }
325  });
326  gridBagConstraints = new java.awt.GridBagConstraints();
327  gridBagConstraints.gridx = 0;
328  gridBagConstraints.gridy = 0;
329  gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
330  gridBagConstraints.insets = new java.awt.Insets(0, 15, 0, 9);
331  sortPane.add(sortButton, gridBagConstraints);
332 
333  buttonBarPanel.add(sortPane);
334 
335  add(buttonBarPanel, java.awt.BorderLayout.NORTH);
336 
337  filePathLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.filePathLabel.text")); // NOI18N
338  add(filePathLabel, java.awt.BorderLayout.SOUTH);
339  add(iconView, java.awt.BorderLayout.CENTER);
340  }// </editor-fold>//GEN-END:initComponents
341 
342  private void pagePrevButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pagePrevButtonActionPerformed
343  previousPage();
344  }//GEN-LAST:event_pagePrevButtonActionPerformed
345 
346  private void pageNextButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pageNextButtonActionPerformed
347  nextPage();
348  }//GEN-LAST:event_pageNextButtonActionPerformed
349 
350  private void goToPageFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_goToPageFieldActionPerformed
351  goToPage(goToPageField.getText());
352  }//GEN-LAST:event_goToPageFieldActionPerformed
353 
354  private void thumbnailSizeComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_thumbnailSizeComboBoxActionPerformed
355  int newIconSize;
356  switch (thumbnailSizeComboBox.getSelectedIndex()) {
357  case 0:
358  newIconSize = ImageUtils.ICON_SIZE_SMALL;
359  break;
360  case 2:
361  newIconSize = ImageUtils.ICON_SIZE_LARGE;
362  break;
363  case 1:
364  default:
365  newIconSize = ImageUtils.ICON_SIZE_MEDIUM; //default size
366  break;
367  }
368 
369  if (thumbSize != newIconSize) {
370  thumbSize = newIconSize;
371  Node root = this.getExplorerManager().getRootContext();
372  ((ThumbnailViewChildren) root.getChildren()).setThumbsSize(thumbSize);
373 
374  // Temporarily set the explored context to the root, instead of a child node.
375  // This is a workaround hack to convince org.openide.explorer.ExplorerManager to
376  // update even though the new and old Node values are identical. This in turn
377  // will cause the entire view to update completely. After this we
378  // immediately set the node back to the current child by calling switchPage().
379  this.getExplorerManager().setExploredContext(root);
380  switchPage();
381  }
382  }//GEN-LAST:event_thumbnailSizeComboBoxActionPerformed
383 
384  private void sortButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sortButtonActionPerformed
385  List<Node.Property<?>> childProperties = ResultViewerPersistence.getAllChildProperties(this.getExplorerManager().getRootContext(), 100);
386  SortChooser sortChooser = new SortChooser(childProperties, ResultViewerPersistence.loadSortCriteria(rootNode));
387  DialogDescriptor dialogDescriptor = new DialogDescriptor(sortChooser, sortChooser.getDialogTitle());
388  Dialog createDialog = DialogDisplayer.getDefault().createDialog(dialogDescriptor);
389  createDialog.setVisible(true);
390  final Object dialogReturnValue = dialogDescriptor.getValue();
391  if (DialogDescriptor.OK_OPTION == dialogReturnValue) {
392  //apply new sort
393  List<SortCriterion> criteria = sortChooser.getCriteria();
394  final Preferences preferences = NbPreferences.forModule(DataResultViewerThumbnail.class);
395 
396  Map<Node.Property<?>, SortCriterion> criteriaMap = criteria.stream()
397  .collect(Collectors.toMap(SortCriterion::getProperty,
398  Function.identity(),
399  (u, v) -> u)); //keep first criteria if property is selected multiple times.
400 
401  //store the sorting information
402  int numProperties = childProperties.size();
403  for (int i = 0; i < numProperties; i++) {
404  Node.Property<?> prop = childProperties.get(i);
405  String propName = prop.getName();
406  SortCriterion criterion = criteriaMap.get(prop);
407  final String columnSortOrderKey = ResultViewerPersistence.getColumnSortOrderKey(rootNode, propName);
408  final String columnSortRankKey = ResultViewerPersistence.getColumnSortRankKey(rootNode, propName);
409 
410  if (criterion != null) {
411  preferences.putBoolean(columnSortOrderKey, criterion.getSortOrder() == SortOrder.ASCENDING);
412  preferences.putInt(columnSortRankKey, criterion.getSortRank() + 1);
413  } else {
414  preferences.remove(columnSortOrderKey);
415  preferences.remove(columnSortRankKey);
416  }
417  }
418  setNode(rootNode); //this is just to force a refresh
419  }
420  }//GEN-LAST:event_sortButtonActionPerformed
421 
422 
423  // Variables declaration - do not modify//GEN-BEGIN:variables
424  private javax.swing.JPanel buttonBarPanel;
425  private javax.swing.JLabel filePathLabel;
426  private javax.swing.JTextField goToPageField;
427  private javax.swing.JLabel goToPageLabel;
428  private org.openide.explorer.view.IconView iconView;
429  private javax.swing.JPanel imagePane;
430  private javax.swing.JLabel imagesLabel;
431  private javax.swing.JLabel imagesRangeLabel;
432  private javax.swing.JPanel pageButtonPanel;
433  private javax.swing.JPanel pageGotoPane;
434  private javax.swing.JLabel pageLabel;
435  private javax.swing.JButton pageNextButton;
436  private javax.swing.JLabel pageNumLabel;
437  private javax.swing.JPanel pageNumberPane;
438  private javax.swing.JButton pagePrevButton;
439  private javax.swing.JLabel pagesLabel;
440  private javax.swing.JPanel pagesPanel;
441  private javax.swing.JButton sortButton;
442  private javax.swing.JLabel sortLabel;
443  private javax.swing.JPanel sortPane;
444  private javax.swing.JComboBox<String> thumbnailSizeComboBox;
445  // End of variables declaration//GEN-END:variables
446 
447  @Override
448  public boolean isSupported(Node selectedNode) {
449  return (selectedNode != null);
450  }
451 
452  @Override
453  public void setNode(Node givenNode) {
454  setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
455  if (selectionListener == null) {
456  this.getExplorerManager().addPropertyChangeListener(new NodeSelectionListener());
457  }
458  if (rootNodeChildren != null) {
459  rootNodeChildren.cancelLoadingThumbnails();
460  }
461  try {
462  // There is an issue with ThumbnailViewChildren
463  // addNotify, that it's call to getChildren.getNodes() does not cause the
464  // children nodes to be created. Adding a call to getChildren.getNodesCount()
465  // here will assure that the children nodes are created particularly in the
466  // case where the DataResultViewerThumbnail stands along from the
467  // DataResultViewer. See DataResultViewer setNode for more information.
468  if (givenNode != null && givenNode.getChildren().getNodesCount() > 0) {
469  rootNode = (TableFilterNode) givenNode;
470  /*
471  * Wrap the given node in a ThumbnailViewChildren that will
472  * produce ThumbnailPageNodes with ThumbnailViewNode children
473  * from the child nodes of the given node.
474  */
475  rootNodeChildren = new ThumbnailViewChildren(givenNode, thumbSize);
476  final Node root = new AbstractNode(rootNodeChildren);
477 
478  pageUpdater.setRoot(root);
479  root.addNodeListener(pageUpdater);
480  this.getExplorerManager().setRootContext(root);
481  } else {
482  rootNode = null;
483  rootNodeChildren = null;
484  Node emptyNode = new AbstractNode(Children.LEAF);
485  this.getExplorerManager().setRootContext(emptyNode);
486  iconView.setBackground(Color.BLACK);
487  }
488  } finally {
489  this.setCursor(null);
490  }
491  }
492 
493  @Override
494  public String getTitle() {
495  return NbBundle.getMessage(this.getClass(), "DataResultViewerThumbnail.title");
496  }
497 
498  @Override
500  return new DataResultViewerThumbnail();
501  }
502 
503  @Override
504  public void resetComponent() {
505  super.resetComponent();
506  this.totalPages = 0;
507  this.currentPage = -1;
508  currentPageImages = 0;
509  updateControls();
510  }
511 
512  @Override
513  public void clearComponent() {
514  this.iconView.removeAll();
515  this.iconView = null;
516  super.clearComponent();
517  }
518 
519  private void nextPage() {
520  if (currentPage < totalPages) {
521  currentPage++;
522  switchPage();
523  }
524  }
525 
526  private void previousPage() {
527  if (currentPage > 1) {
528  currentPage--;
529  switchPage();
530  }
531  }
532 
533  private void goToPage(String pageNumText) {
534  int newPage;
535  try {
536  newPage = Integer.parseInt(pageNumText);
537  } catch (NumberFormatException e) {
538  //ignore input
539  return;
540  }
541 
542  if (newPage > totalPages || newPage < 1) {
543  JOptionPane.showMessageDialog(this,
544  NbBundle.getMessage(this.getClass(), "DataResultViewerThumbnail.goToPageTextField.msgDlg", totalPages),
545  NbBundle.getMessage(this.getClass(), "DataResultViewerThumbnail.goToPageTextField.err"),
546  JOptionPane.WARNING_MESSAGE);
547  return;
548  }
549 
550  currentPage = newPage;
551  switchPage();
552  }
553 
554  private void switchPage() {
555 
556  EventQueue.invokeLater(() -> {
557  setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
558  });
559 
560  //Note the nodes factories are likely creating nodes in EDT anyway, but worker still helps
561  new SwingWorker<Object, Void>() {
562  private ProgressHandle progress;
563 
564  @Override
565  protected Object doInBackground() throws Exception {
566  pagePrevButton.setEnabled(false);
567  pageNextButton.setEnabled(false);
568  goToPageField.setEnabled(false);
569  progress = ProgressHandle.createHandle(
570  NbBundle.getMessage(this.getClass(), "DataResultViewerThumbnail.genThumbs"));
571  progress.start();
572  progress.switchToIndeterminate();
573  ExplorerManager explorerManager = DataResultViewerThumbnail.this.getExplorerManager();
574  Node root = explorerManager.getRootContext();
575  Node pageNode = root.getChildren().getNodeAt(currentPage - 1);
576  explorerManager.setExploredContext(pageNode);
577  currentPageImages = pageNode.getChildren().getNodesCount();
578  return null;
579  }
580 
581  @Override
582  protected void done() {
583  progress.finish();
584  setCursor(null);
585  updateControls();
586  // see if any exceptions were thrown
587  try {
588  get();
589  } catch (InterruptedException | ExecutionException ex) {
590  NotifyDescriptor d
591  = new NotifyDescriptor.Message(
592  NbBundle.getMessage(this.getClass(), "DataResultViewerThumbnail.switchPage.done.errMsg",
593  ex.getMessage()),
594  NotifyDescriptor.ERROR_MESSAGE);
595  DialogDisplayer.getDefault().notify(d);
596  logger.log(Level.SEVERE, "Error making thumbnails: {0}", ex.getMessage()); //NON-NLS
597  }
598  catch (java.util.concurrent.CancellationException ex) {
599  // catch and ignore if we were cancelled
600  }
601  }
602  }.execute();
603 
604  }
605 
606  @NbBundle.Messages({
607  "# {0} - sort criteria", "DataResultViewerThumbnail.sortLabel.textTemplate=Sorted by: {0}",
608  "DataResultViewerThumbnail.sortLabel.text=Sorted by: ---"})
609  private void updateControls() {
610  if (totalPages == 0) {
611  pagePrevButton.setEnabled(false);
612  pageNextButton.setEnabled(false);
613  goToPageField.setEnabled(false);
614  pageNumLabel.setText("");
615  imagesRangeLabel.setText("");
616  thumbnailSizeComboBox.setEnabled(false);
617  sortButton.setEnabled(false);
618  sortLabel.setText(DataResultViewerThumbnail_sortLabel_text());
619 
620  } else {
621  pageNumLabel.setText(NbBundle.getMessage(this.getClass(), "DataResultViewerThumbnail.pageNumbers.curOfTotal",
622  Integer.toString(currentPage), Integer.toString(totalPages)));
623  final int imagesFrom = (currentPage - 1) * ThumbnailViewChildren.IMAGES_PER_PAGE + 1;
624  final int imagesTo = currentPageImages + (currentPage - 1) * ThumbnailViewChildren.IMAGES_PER_PAGE;
625  imagesRangeLabel.setText(imagesFrom + "-" + imagesTo);
626 
627  pageNextButton.setEnabled(!(currentPage == totalPages));
628  pagePrevButton.setEnabled(!(currentPage == 1));
629  goToPageField.setEnabled(totalPages > 1);
630  sortButton.setEnabled(true);
631  thumbnailSizeComboBox.setEnabled(true);
632  if (rootNode != null) {
633  String sortString = ResultViewerPersistence.loadSortCriteria(rootNode).stream()
634  .map(SortCriterion::toString)
635  .collect(Collectors.joining(" "));
636  sortString = StringUtils.defaultIfBlank(sortString, "---");
637  sortLabel.setText(Bundle.DataResultViewerThumbnail_sortLabel_textTemplate(sortString));
638  } else {
639  sortLabel.setText(DataResultViewerThumbnail_sortLabel_text());
640  }
641  }
642  }
643 
647  private class PageUpdater implements NodeListener {
648 
649  private Node root;
650 
651  void setRoot(Node root) {
652  this.root = root;
653  }
654 
655  @Override
656  public void propertyChange(PropertyChangeEvent evt) {
657  }
658 
659  @Override
660  public void childrenAdded(NodeMemberEvent nme) {
661  totalPages = root.getChildren().getNodesCount();
662 
663  if (totalPages == 0) {
664  currentPage = -1;
665  updateControls();
666  return;
667  }
668 
669  if (currentPage == -1 || currentPage > totalPages) {
670  currentPage = 1;
671  }
672 
673  //force load the curPage node
674  final Node pageNode = root.getChildren().getNodeAt(currentPage - 1);
675 
676  //em.setSelectedNodes(new Node[]{pageNode});
677  if (pageNode != null) {
678  pageNode.addNodeListener(new NodeListener() {
679  @Override
680  public void childrenAdded(NodeMemberEvent nme) {
681  currentPageImages = pageNode.getChildren().getNodesCount();
682  updateControls();
683  }
684 
685  @Override
686  public void childrenRemoved(NodeMemberEvent nme) {
687  currentPageImages = 0;
688  updateControls();
689  }
690 
691  @Override
692  public void childrenReordered(NodeReorderEvent nre) {
693  }
694 
695  @Override
696  public void nodeDestroyed(NodeEvent ne) {
697  }
698 
699  @Override
700  public void propertyChange(PropertyChangeEvent evt) {
701  }
702  });
703 
704  DataResultViewerThumbnail.this.getExplorerManager().setExploredContext(pageNode);
705  }
706 
707  updateControls();
708  }
709 
710  @Override
711  public void childrenRemoved(NodeMemberEvent nme) {
712  totalPages = 0;
713  currentPage = -1;
714  updateControls();
715  }
716 
717  @Override
718  public void childrenReordered(NodeReorderEvent nre) {
719  }
720 
721  @Override
722  public void nodeDestroyed(NodeEvent ne) {
723  }
724  }
725 
726  private class NodeSelectionListener implements PropertyChangeListener {
727 
728  @Override
729  public void propertyChange(PropertyChangeEvent evt) {
730  if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
731  setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
732  try {
733  Node[] selectedNodes = DataResultViewerThumbnail.this.getExplorerManager().getSelectedNodes();
734  if (selectedNodes.length == 1) {
735  AbstractFile af = selectedNodes[0].getLookup().lookup(AbstractFile.class);
736  if (af == null) {
737  filePathLabel.setText("");
738  } else {
739  try {
740  String uPath = af.getUniquePath();
741  filePathLabel.setText(uPath);
742  filePathLabel.setToolTipText(uPath);
743  } catch (TskCoreException e) {
744  logger.log(Level.WARNING, "Could not get unique path for content: {0}", af.getName()); //NON-NLS
745  }
746  }
747  } else {
748  filePathLabel.setText("");
749  }
750  } finally {
751  setCursor(null);
752  }
753  }
754  }
755  }
756 }
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

Copyright © 2012-2018 Basis Technology. Generated on: Wed Sep 18 2019
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.