Autopsy 4.22.1
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 */
19package org.sleuthkit.autopsy.corecomponents;
20
21import java.awt.Color;
22import java.awt.Cursor;
23import java.awt.Dialog;
24import java.awt.EventQueue;
25import java.beans.PropertyChangeEvent;
26import java.beans.PropertyChangeListener;
27import java.util.List;
28import java.util.Map;
29import java.util.concurrent.ExecutionException;
30import java.util.function.Function;
31import java.util.logging.Level;
32import java.util.prefs.Preferences;
33import java.util.stream.Collectors;
34import javax.swing.JOptionPane;
35import javax.swing.ListSelectionModel;
36import javax.swing.SortOrder;
37import javax.swing.SwingWorker;
38import org.apache.commons.lang3.StringUtils;
39import org.netbeans.api.progress.ProgressHandle;
40import org.openide.DialogDescriptor;
41import org.openide.DialogDisplayer;
42import org.openide.NotifyDescriptor;
43import org.openide.explorer.ExplorerManager;
44import org.openide.nodes.AbstractNode;
45import org.openide.nodes.Children;
46import org.openide.nodes.Node;
47import org.openide.nodes.NodeEvent;
48import org.openide.nodes.NodeListener;
49import org.openide.nodes.NodeMemberEvent;
50import org.openide.nodes.NodeReorderEvent;
51import org.openide.util.NbBundle;
52import org.openide.util.NbPreferences;
53import org.openide.util.lookup.ServiceProvider;
54import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
55import static org.sleuthkit.autopsy.corecomponents.Bundle.*;
56import org.sleuthkit.autopsy.corecomponents.ResultViewerPersistence.SortCriterion;
57import org.sleuthkit.autopsy.coreutils.ImageUtils;
58import org.sleuthkit.autopsy.coreutils.Logger;
59import org.sleuthkit.autopsy.guiutils.WrapLayout;
60import org.sleuthkit.datamodel.AbstractFile;
61import 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;
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 })
115 super(explorerManager);
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;
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
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
503
504 @Override
505 public void resetComponent() {
506 super.resetComponent();
507 this.totalPages = 0;
508 this.currentPage = -1;
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);
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;
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();
684 }
685
686 @Override
687 public void childrenRemoved(NodeMemberEvent nme) {
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
709 }
710
711 @Override
712 public void childrenRemoved(NodeMemberEvent nme) {
713 totalPages = 0;
714 currentPage = -1;
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-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.