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

Copyright © 2012-2022 Basis Technology. Generated on: Tue Feb 6 2024
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.