Autopsy  4.20.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
DataContentPanel.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-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.Cursor;
22 import java.beans.PropertyChangeEvent;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.List;
26 import java.util.concurrent.ExecutionException;
27 import java.util.logging.Level;
28 import javax.swing.JTabbedPane;
29 import javax.swing.SwingWorker;
30 import javax.swing.event.ChangeEvent;
31 import javax.swing.event.ChangeListener;
32 import org.openide.nodes.Node;
33 import org.openide.util.Lookup;
34 import org.openide.util.NbBundle;
39 import org.sleuthkit.datamodel.Content;
40 import org.sleuthkit.datamodel.TskCoreException;
41 
45 @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
46 public class DataContentPanel extends javax.swing.JPanel implements DataContent, ChangeListener {
47 
48  private static Logger logger = Logger.getLogger(DataContentPanel.class.getName());
49  private final List<UpdateWrapper> viewers = new ArrayList<>();
50  private Node currentNode;
51  private final boolean isMain;
52  private boolean listeningToTabbedPane = false;
53 
55 
65  DataContentPanel(boolean isMain) {
66  this.isMain = isMain;
67  initComponents();
68 
69  // add all implementors of DataContentViewer and put them in the tabbed pane
70  Collection<? extends DataContentViewer> dcvs = Lookup.getDefault().lookupAll(DataContentViewer.class);
71  for (DataContentViewer factory : dcvs) {
73  if (isMain) {
74  //use the instance from Lookup for the main viewer
75  dcv = factory;
76  } else {
77  dcv = factory.createInstance();
78  }
79  viewers.add(new UpdateWrapper(dcv));
80  javax.swing.JScrollPane scrollTab = new javax.swing.JScrollPane(dcv.getComponent());
81  scrollTab.setVerticalScrollBarPolicy(javax.swing.JScrollPane.VERTICAL_SCROLLBAR_NEVER);
82  jTabbedPane1.addTab(dcv.getTitle(), null,
83  scrollTab, dcv.getToolTip());
84  }
85 
86  // disable the tabs
87  int numTabs = jTabbedPane1.getTabCount();
88  for (int tab = 0; tab < numTabs; ++tab) {
89  jTabbedPane1.setEnabledAt(tab, false);
90  }
91  }
92 
99  public static DataContentPanel createInstance() {
100  return new DataContentPanel(false);
101  }
102 
103  public JTabbedPane getTabPanels() {
104  return jTabbedPane1;
105  }
106 
112  @SuppressWarnings("unchecked")
113  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
114  private void initComponents() {
115 
116  jTabbedPane1 = new javax.swing.JTabbedPane();
117 
118  setMinimumSize(new java.awt.Dimension(5, 5));
119 
120  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
121  this.setLayout(layout);
122  layout.setHorizontalGroup(
123  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
124  .addComponent(jTabbedPane1)
125  );
126  layout.setVerticalGroup(
127  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
128  .addComponent(jTabbedPane1)
129  );
130  }// </editor-fold>//GEN-END:initComponents
131  // Variables declaration - do not modify//GEN-BEGIN:variables
132  private javax.swing.JTabbedPane jTabbedPane1;
133  // End of variables declaration//GEN-END:variables
134 
135  @Override
136  public void setNode(Node selectedNode) {
137 
138  if (workerThread != null) {
139  workerThread.cancel(true);
140  workerThread = null;
141  }
142 
143  currentNode = null;
144 
145  // Reset everything
146  for (int index = 0; index < jTabbedPane1.getTabCount(); index++) {
147  jTabbedPane1.setEnabledAt(index, false);
148  String tabTitle = viewers.get(index).getTitle(selectedNode);
149  tabTitle = tabTitle == null ? "" : tabTitle;
150  if (!tabTitle.equals(jTabbedPane1.getTitleAt(index))) {
151  jTabbedPane1.setTitleAt(index, tabTitle);
152  }
153 
154  viewers.get(index).resetComponent();
155  }
156 
157  if (selectedNode != null) {
158  workerThread = new DataContentPanelWorker(selectedNode);
159  workerThread.execute();
160  }
161  }
162 
171  private void updateTabs(Node selectedNode, List<Integer> supportedIndices, int preferredIndex) {
172  // Deferring becoming a listener to the tabbed pane until this point
173  // eliminates handling a superfluous stateChanged event during construction.
174  if (listeningToTabbedPane == false) {
175  jTabbedPane1.addChangeListener(this);
176  listeningToTabbedPane = true;
177  }
178 
179  for (Integer index : supportedIndices) {
180  jTabbedPane1.setEnabledAt(index, true);
181  }
182 
183  // let the user decide if we should stay with the current viewer
184  int tabIndex = UserPreferences.keepPreferredContentViewer() ? jTabbedPane1.getSelectedIndex() : preferredIndex;
185 
186  UpdateWrapper dcv = viewers.get(tabIndex);
187  // this is really only needed if no tabs were enabled
188  if (jTabbedPane1.isEnabledAt(tabIndex) == false) {
189  dcv.resetComponent();
190  } else {
191  dcv.setNode(selectedNode);
192  }
193 
194  // set the tab to the one the user wants, then set that viewer's node.
195  jTabbedPane1.setSelectedIndex(tabIndex);
196  jTabbedPane1.getSelectedComponent().repaint();
197  }
198 
199  @Override
200  public void propertyChange(PropertyChangeEvent evt) {
201  }
202 
203  @Override
204  public void stateChanged(ChangeEvent evt) {
205  JTabbedPane pane = (JTabbedPane) evt.getSource();
206 
207  // Get and set current selected tab
208  int currentTab = pane.getSelectedIndex();
209  if (currentTab != -1) {
210  UpdateWrapper dcv = viewers.get(currentTab);
211  if (dcv.isOutdated() || dcv.getViewer() instanceof DataArtifactContentViewer) {
212  // change the cursor to "waiting cursor" for this operation
213  this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
214  try {
215  dcv.setNode(currentNode);
216  } finally {
217  this.setCursor(null);
218  }
219  }
220  }
221  }
222 
223  private static class UpdateWrapper {
224 
225  private final DataContentViewer wrapped;
226  private boolean outdated;
227 
229  this.wrapped = wrapped;
230  this.outdated = true;
231  }
232 
233  void setNode(Node selectedNode) {
234  this.wrapped.setNode(selectedNode);
235  this.outdated = false;
236  }
237 
238  void resetComponent() {
239  this.wrapped.resetComponent();
240  this.outdated = true;
241  }
242 
243  boolean isOutdated() {
244  return this.outdated;
245  }
246 
247  boolean isSupported(Node node) {
248  return this.wrapped.isSupported(node);
249  }
250 
251  int isPreferred(Node node) {
252  return this.wrapped.isPreferred(node);
253  }
254 
255  String getTitle(Node node) {
256  return this.wrapped.getTitle(node);
257  }
258 
259  DataContentViewer getViewer() {
260  return wrapped;
261  }
262  }
263 
268  private class DataContentPanelWorker extends SwingWorker<WorkerResults, Void> {
269 
270  private final Node node;
271 
277  DataContentPanelWorker(Node node) {
278  this.node = node;
279  }
280 
281  @Override
282  protected WorkerResults doInBackground() throws Exception {
283 
284  List<Integer> supportedViewers = new ArrayList<>();
285  int preferredViewerIndex = 0;
286  int maxPreferred = 0;
287 
288  for (int index = 0; index < viewers.size(); index++) {
289  UpdateWrapper dcv = viewers.get(index);
290  if (dcv.isSupported(node)) {
291  supportedViewers.add(index);
292 
293  int currentPreferred = dcv.isPreferred(node);
294  if (currentPreferred > maxPreferred) {
295  preferredViewerIndex = index;
296  maxPreferred = currentPreferred;
297  }
298  }
299 
300  if (this.isCancelled()) {
301  return null;
302  }
303 
304  }
305 
306  return new WorkerResults(node, supportedViewers, preferredViewerIndex);
307  }
308 
309  @Override
310  protected void done() {
311  // Do nothing if the thread was cancelled.
312  if (isCancelled()) {
313  return;
314  }
315 
316  try {
317  WorkerResults results = get();
318  currentNode = node;
319  if (results != null) {
320  updateTabs(results.getNode(), results.getSupportedIndices(), results.getPreferredViewerIndex());
321  }
322 
323  } catch (InterruptedException | ExecutionException ex) {
324  logger.log(Level.SEVERE, "Failed to updated data content panel for node " + node.getName(), ex);
325  } finally {
326  setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
327  }
328  }
329  }
330 
334  private class WorkerResults {
335 
336  private final Node node;
337  private final List<Integer> supportedViewerIndices;
338  private final int preferredViewerIndex;
339 
340  WorkerResults(Node node, List<Integer> supportedViewerIndices, int preferredViewerIndex) {
341  this.node = node;
342  this.supportedViewerIndices = supportedViewerIndices;
343  this.preferredViewerIndex = preferredViewerIndex;
344  }
345 
351  Node getNode() {
352  return node;
353  }
354 
360  List<Integer> getSupportedIndices() {
361  return supportedViewerIndices;
362  }
363 
369  int getPreferredViewerIndex() {
370  return preferredViewerIndex;
371  }
372  }
373 }
void updateTabs(Node selectedNode, List< Integer > supportedIndices, int preferredIndex)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

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