Autopsy  4.19.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
MediaViewer.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2019-2021 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 obt ain 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.communications.relationships;
20 
21 import java.awt.Component;
22 import java.awt.Cursor;
23 import java.awt.KeyboardFocusManager;
24 import java.beans.PropertyChangeEvent;
25 import java.beans.PropertyChangeListener;
26 import java.util.HashSet;
27 import java.util.List;
28 import java.util.Set;
29 import java.util.concurrent.ExecutionException;
30 import java.util.logging.Level;
31 import java.util.stream.Collectors;
32 import javax.swing.JOptionPane;
33 import javax.swing.JPanel;
34 import static javax.swing.SwingUtilities.isDescendingFrom;
35 import javax.swing.SwingWorker;
36 import org.openide.explorer.ExplorerManager;
37 import static org.openide.explorer.ExplorerUtils.createLookup;
38 import org.openide.nodes.AbstractNode;
39 import org.openide.nodes.Node;
40 import org.openide.util.Lookup;
41 import org.openide.util.NbBundle.Messages;
48 import org.sleuthkit.datamodel.AbstractContent;
49 import org.sleuthkit.datamodel.Account;
50 import org.sleuthkit.datamodel.BlackboardArtifact;
51 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT;
52 import org.sleuthkit.datamodel.BlackboardAttribute;
53 import org.sleuthkit.datamodel.Content;
54 import org.sleuthkit.datamodel.SleuthkitCase;
55 
59 final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerManager.Provider, Lookup.Provider {
60 
61  private static final Logger logger = Logger.getLogger(MediaViewer.class.getName());
62  private static final long serialVersionUID = 1L;
63 
64  private final ExplorerManager tableEM = new ExplorerManager();
65  private PropertyChangeListener focusPropertyListener;
66 
67  private final ModifiableProxyLookup proxyLookup;
68 
69  private final MessageDataContent contentViewer;
70 
71  private MediaViewerWorker worker;
72  private SelectionWorker selectionWorker;
73 
74  @Messages({
75  "MediaViewer_Name=Media Attachments"
76  })
80  MediaViewer() {
81  initComponents();
82 
83  splitPane.setResizeWeight(0.5);
84  splitPane.setDividerLocation(0.5);
85 
86  contentViewer = new MessageDataContent();
87  contentViewer.setPreferredSize(new java.awt.Dimension(450, 400));
88  splitPane.setRightComponent(contentViewer);
89 
90  proxyLookup = new ModifiableProxyLookup(createLookup(tableEM, getActionMap()));
91 
92  tableEM.addPropertyChangeListener((PropertyChangeEvent evt) -> {
93  if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
94  handleNodeSelectionChange();
95  }
96  });
97 
98  thumbnailViewer.resetComponent();
99  }
100 
101  @Override
102  public String getDisplayName() {
103  return Bundle.MediaViewer_Name();
104  }
105 
106  @Override
107  public JPanel getPanel() {
108  return this;
109  }
110 
111  @Override
112  public void setSelectionInfo(SelectionInfo info) {
113  contentViewer.setNode(null);
114  thumbnailViewer.setNode(null);
115 
116  if (worker != null) {
117  worker.cancel(true);
118  }
119 
120  if(selectionWorker != null) {
121  selectionWorker.cancel(true);
122  }
123 
124  worker = new MediaViewerWorker(info);
125 
126  setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
127  worker.execute();
128  }
129 
130  @Override
131  public ExplorerManager getExplorerManager() {
132  return tableEM;
133  }
134 
135  @Override
136  public Lookup getLookup() {
137  return proxyLookup;
138  }
139 
140  @Override
141  public void addNotify() {
142  super.addNotify();
143 
144  if (focusPropertyListener == null) {
145  // See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed
146  // explaination of focusPropertyListener
147  focusPropertyListener = (final PropertyChangeEvent focusEvent) -> {
148  if (focusEvent.getPropertyName().equalsIgnoreCase("focusOwner")) {
149  handleFocusChange((Component) focusEvent.getNewValue());
150  }
151  };
152 
153  }
154  //add listener that maintains correct selection in the Global Actions Context
155  KeyboardFocusManager.getCurrentKeyboardFocusManager()
156  .addPropertyChangeListener("focusOwner", focusPropertyListener);
157  }
158 
164  private void handleFocusChange(Component newFocusOwner) {
165  if (newFocusOwner == null) {
166  return;
167  }
168  if (isDescendingFrom(newFocusOwner, contentViewer)) {
169  //if the focus owner is within the MessageContentViewer (the attachments table)
170  proxyLookup.setNewLookups(createLookup(contentViewer.getExplorerManager(), getActionMap()));
171  } else if (isDescendingFrom(newFocusOwner, this)) {
172  //... or if it is within the Results table.
173  proxyLookup.setNewLookups(createLookup(tableEM, getActionMap()));
174 
175  }
176  }
177 
178  @Override
179  public void removeNotify() {
180  super.removeNotify();
181 
182  if (focusPropertyListener != null) {
183  KeyboardFocusManager.getCurrentKeyboardFocusManager()
184  .removePropertyChangeListener("focusOwner", focusPropertyListener);
185  }
186  }
187 
191  private void handleNodeSelectionChange() {
192  final Node[] nodes = tableEM.getSelectedNodes();
193  contentViewer.setNode(null);
194 
195  if(selectionWorker != null) {
196  selectionWorker.cancel(true);
197  }
198 
199  if (nodes != null && nodes.length == 1) {
200  AbstractContent thumbnail = nodes[0].getLookup().lookup(AbstractContent.class);
201  if (thumbnail != null) {
202  setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
203  selectionWorker = new SelectionWorker(thumbnail);
204  selectionWorker.execute();
205  }
206  }
207  }
208 
212  private class SelectionWorker extends SwingWorker<BlackboardArtifact, Void> {
213 
214  private final AbstractContent thumbnail;
215 
216  // Construct a SelectionWorker.
217  SelectionWorker(AbstractContent thumbnail) {
218  this.thumbnail = thumbnail;
219  }
220 
221  @Override
222  protected BlackboardArtifact doInBackground() throws Exception {
223  SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase();
224  List<BlackboardArtifact> artifactsList = skCase.getBlackboardArtifacts(TSK_ASSOCIATED_OBJECT, thumbnail.getId());
225  for (BlackboardArtifact contextArtifact : artifactsList) {
226  BlackboardAttribute associatedArtifactAttribute = contextArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
227  if (associatedArtifactAttribute != null) {
228  long artifactId = associatedArtifactAttribute.getValueLong();
229  return contextArtifact.getSleuthkitCase().getBlackboardArtifact(artifactId);
230  }
231  }
232  return null;
233  }
234 
235  @Override
236  protected void done() {
237  if (isCancelled()) {
238  return;
239  }
240 
241  try {
242  BlackboardArtifact artifact = get();
243  if (artifact != null) {
244  contentViewer.setNode(new BlackboardArtifactNode(artifact));
245  } else {
246  contentViewer.setNode(null);
247  }
248  } catch (InterruptedException | ExecutionException ex) {
249  logger.log(Level.SEVERE, "Failed message viewer based on thumbnail selection. thumbnailID = " + thumbnail.getId(), ex);
250  } finally {
251  setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
252  }
253  }
254  }
255 
259  private class MediaViewerWorker extends SwingWorker<TableFilterNode, Void> {
260 
262 
264  selectionInfo = info;
265  }
266 
267  @Override
268  protected TableFilterNode doInBackground() throws Exception {
269  Set<Content> relationshipSources;
270  Set<BlackboardArtifact> artifactList = new HashSet<>();
271 
272  if (selectionInfo != null) {
273  relationshipSources = selectionInfo.getRelationshipSources();
274 
275  relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> {
276  artifactList.add((BlackboardArtifact) content);
277  });
278  }
279 
280  return new TableFilterNode(new DataResultFilterNode(new AbstractNode(new AttachmentThumbnailsChildren(artifactList)), tableEM), true, this.getClass().getName());
281  }
282 
283  @Messages({
284  "MediaViewer_selection_failure_msg=Failed to get media attachments for selected accounts.",
285  "MediaViewer_selection_failure_title=Selection Failed"
286  })
287  @Override
288  protected void done() {
289  try {
290  if (isCancelled()) {
291  return;
292  }
293  thumbnailViewer.setNode(get());
294  } catch (ExecutionException | InterruptedException ex) {
295  String accounts = selectionInfo.getAccounts().stream().map(Account::getTypeSpecificID).collect(Collectors.joining(","));
296  logger.log(Level.WARNING, "Unable to update cvt media viewer for " + accounts, ex);
297 
298  JOptionPane.showMessageDialog(MediaViewer.this, Bundle.MediaViewer_selection_failure_msg(), Bundle.MediaViewer_selection_failure_title(), JOptionPane.ERROR_MESSAGE);
299  } finally {
300  setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
301  }
302  }
303 
304  }
305 
311  @SuppressWarnings("unchecked")
312  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
313  private void initComponents() {
314  java.awt.GridBagConstraints gridBagConstraints;
315 
316  splitPane = new javax.swing.JSplitPane();
317  thumbnailViewer = new org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail(tableEM);
318 
319  setLayout(new java.awt.GridBagLayout());
320 
321  splitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
322 
323  thumbnailViewer.setMinimumSize(new java.awt.Dimension(350, 102));
324  thumbnailViewer.setPreferredSize(new java.awt.Dimension(450, 400));
325  splitPane.setLeftComponent(thumbnailViewer);
326 
327  gridBagConstraints = new java.awt.GridBagConstraints();
328  gridBagConstraints.gridx = 0;
329  gridBagConstraints.gridy = 0;
330  gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
331  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
332  gridBagConstraints.weightx = 1.0;
333  gridBagConstraints.weighty = 1.0;
334  add(splitPane, gridBagConstraints);
335  }// </editor-fold>//GEN-END:initComponents
336 
337 
338  // Variables declaration - do not modify//GEN-BEGIN:variables
339  private javax.swing.JSplitPane splitPane;
341  // End of variables declaration//GEN-END:variables
342 
343 }

Copyright © 2012-2021 Basis Technology. Generated on: Thu Sep 30 2021
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.