Autopsy 4.22.1
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 */
19package org.sleuthkit.autopsy.corecomponents;
20
21import java.awt.Cursor;
22import java.beans.PropertyChangeEvent;
23import java.util.ArrayList;
24import java.util.Collection;
25import java.util.List;
26import java.util.concurrent.ExecutionException;
27import java.util.logging.Level;
28import javax.swing.JTabbedPane;
29import javax.swing.SwingWorker;
30import javax.swing.event.ChangeEvent;
31import javax.swing.event.ChangeListener;
32import org.openide.nodes.Node;
33import org.openide.util.Lookup;
34import org.openide.util.NbBundle;
35import org.sleuthkit.autopsy.core.UserPreferences;
36import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent;
37import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
38import org.sleuthkit.autopsy.coreutils.Logger;
39import org.sleuthkit.datamodel.Content;
40import org.sleuthkit.datamodel.TskCoreException;
41
45@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
46public 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;
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);
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
226 private boolean outdated;
227
228 UpdateWrapper(DataContentViewer wrapped) {
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();
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-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.