Autopsy  4.15.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
MessageViewer.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2019 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.communications.relationships;
20 
21 import java.awt.CardLayout;
22 import java.awt.Component;
23 import java.awt.Graphics2D;
24 import java.awt.Image;
25 import java.awt.KeyboardFocusManager;
26 import java.awt.RenderingHints;
27 import java.awt.event.ActionEvent;
28 import java.awt.image.BufferedImage;
29 import java.beans.PropertyChangeEvent;
30 import java.beans.PropertyChangeListener;
31 import java.beans.PropertyVetoException;
32 import java.lang.reflect.InvocationTargetException;
33 import java.util.ArrayList;
34 import java.util.logging.Level;
35 import javax.swing.AbstractAction;
36 import javax.swing.ImageIcon;
37 import javax.swing.JPanel;
38 import javax.swing.ListSelectionModel;
39 import javax.swing.SwingUtilities;
40 import static javax.swing.SwingUtilities.isDescendingFrom;
41 import org.netbeans.swing.outline.DefaultOutlineModel;
42 import org.netbeans.swing.outline.Outline;
43 import org.openide.explorer.ExplorerManager;
44 import static org.openide.explorer.ExplorerUtils.createLookup;
45 import org.openide.nodes.AbstractNode;
46 import org.openide.nodes.Children;
47 import org.openide.nodes.Node;
48 import org.openide.nodes.Node.Property;
49 import org.openide.nodes.Node.PropertySet;
50 import org.openide.util.Lookup;
51 import org.openide.util.NbBundle.Messages;
54 
59 @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
60 final class MessageViewer extends JPanel implements RelationshipsViewer {
61 
62  private static final Logger logger = Logger.getLogger(MessageViewer.class.getName());
63  private static final long serialVersionUID = 1L;
64 
65  private final ModifiableProxyLookup proxyLookup;
66  private PropertyChangeListener focusPropertyListener;
67  private final ThreadChildNodeFactory rootMessageFactory;
68  private final MessagesChildNodeFactory threadMessageNodeFactory;
69 
70  private SelectionInfo currentSelectionInfo = null;
71 
72  private OutlineViewPanel currentPanel;
73 
74  @Messages({
75  "MessageViewer_tabTitle=Messages",
76  "MessageViewer_columnHeader_From=From",
77  "MessageViewer_columnHeader_Date=Date",
78  "MessageViewer_columnHeader_To=To",
79  "MessageViewer_columnHeader_EarlyDate=Earliest Message",
80  "MessageViewer_columnHeader_Subject=Subject",
81  "MessageViewer_columnHeader_Attms=Attachments",
82  "MessageViewer_no_messages=<No messages found for selected account>",
83  "MessageViewer_viewMessage_all=All",
84  "MessageViewer_viewMessage_selected=Selected",
85  "MessageViewer_viewMessage_unthreaded=Unthreaded",
86  "MessageViewer_viewMessage_calllogs=Call Logs"})
87 
91  MessageViewer() {
92 
93  initComponents();
94  currentPanel = rootTablePane;
95  proxyLookup = new ModifiableProxyLookup(createLookup(rootTablePane.getExplorerManager(), getActionMap()));
96  rootMessageFactory = new ThreadChildNodeFactory(new ShowThreadMessagesAction());
97  threadMessageNodeFactory = new MessagesChildNodeFactory();
98 
99  rootTablePane.getExplorerManager().setRootContext(
100  new AbstractNode(Children.create(rootMessageFactory, true)));
101 
102  rootTablePane.getOutlineView().setPopupAllowed(false);
103 
104  Outline outline = rootTablePane.getOutlineView().getOutline();
105  rootTablePane.getOutlineView().setPropertyColumns(
106  "Date", Bundle.MessageViewer_columnHeader_EarlyDate(),
107  "Subject", Bundle.MessageViewer_columnHeader_Subject()
108  );
109  outline.setRootVisible(false);
110  ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel("Type");
111  outline.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
112 
113  rootTablePane.getExplorerManager().addPropertyChangeListener((PropertyChangeEvent evt) -> {
114  if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
115  showSelectedThread();
116  }
117  });
118 
119  threadMessagesPanel.setChildFactory(threadMessageNodeFactory);
120 
121  rootTablePane.setTableColumnsWidth(10, 20, 70);
122 
123  Image image = getScaledImage((new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/timeline/images/arrow-180.png"))).getImage(), 16, 16);
124  backButton.setIcon(new ImageIcon(image));
125  }
126 
127  @Override
128  public String getDisplayName() {
129  return Bundle.MessageViewer_tabTitle();
130  }
131 
132  @Override
133  public JPanel getPanel() {
134  return this;
135  }
136 
137  @Override
138  public void setSelectionInfo(SelectionInfo info) {
139  currentSelectionInfo = info;
140 
141  currentPanel = rootTablePane;
142 
143  CardLayout layout = (CardLayout) this.getLayout();
144  layout.show(this, "threads");
145 
146  rootMessageFactory.refresh(info);
147  }
148 
149  @Override
150  public Lookup getLookup() {
151  return proxyLookup;
152  }
153 
154  @Override
155  public void addNotify() {
156  super.addNotify();
157 
158  if (focusPropertyListener == null) {
159  // See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed
160  // explaination of focusPropertyListener
161  focusPropertyListener = (final PropertyChangeEvent focusEvent) -> {
162  if (focusEvent.getPropertyName().equalsIgnoreCase("focusOwner")) {
163  handleFocusChange((Component) focusEvent.getNewValue());
164  }
165  };
166 
167  }
168  //add listener that maintains correct selection in the Global Actions Context
169  KeyboardFocusManager.getCurrentKeyboardFocusManager()
170  .addPropertyChangeListener("focusOwner", focusPropertyListener);
171  }
172 
178  private void handleFocusChange(Component newFocusOwner) {
179  if (newFocusOwner == null) {
180  return;
181  }
182  if (isDescendingFrom(newFocusOwner, rootTablePane)) {
183  proxyLookup.setNewLookups(createLookup(rootTablePane.getExplorerManager(), getActionMap()));
184  } else if (isDescendingFrom(newFocusOwner, this)) {
185  proxyLookup.setNewLookups(createLookup(currentPanel.getExplorerManager(), getActionMap()));
186  }
187  }
188 
189  @Override
190  public void removeNotify() {
191  super.removeNotify();
192  KeyboardFocusManager.getCurrentKeyboardFocusManager()
193  .removePropertyChangeListener("focusOwner", focusPropertyListener);
194  }
195 
196  @SuppressWarnings("rawtypes")
197  private void showSelectedThread() {
198  final Node[] nodes = rootTablePane.getExplorerManager().getSelectedNodes();
199 
200  if (nodes == null) {
201  return;
202  }
203 
204  if (nodes.length == 0 || nodes.length > 1) {
205  return;
206  }
207 
208  ArrayList<String> threadIDList = new ArrayList<>();
209  String subject = "";
210 
211  PropertySet[] propertySets = nodes[0].getPropertySets();
212  for (PropertySet pset : propertySets) {
213  Property[] properties = pset.getProperties();
214  for (Property prop : properties) {
215  if (prop.getName().equalsIgnoreCase("threadid")) {
216  try {
217  String threadID = prop.getValue().toString();
218  if (!threadIDList.contains(threadID)) {
219  threadIDList.add(threadID);
220  }
221  } catch (IllegalAccessException | InvocationTargetException ex) {
222  logger.log(Level.WARNING, String.format("Unable to get threadid for node: %s", nodes[0].getDisplayName()), ex);
223  }
224  } else if (prop.getName().equalsIgnoreCase("subject")) {
225  try {
226  subject = prop.getValue().toString();
227  } catch (IllegalAccessException | InvocationTargetException ex) {
228  logger.log(Level.WARNING, String.format("Unable to get subject for node: %s", nodes[0].getDisplayName()), ex);
229  subject = "<unavailable>";
230  }
231  }
232  }
233 
234  }
235 
236  if (!threadIDList.isEmpty()) {
237  threadMessageNodeFactory.refresh(currentSelectionInfo, threadIDList);
238 
239  if (!subject.isEmpty()) {
240  threadNameLabel.setText(subject);
241  } else {
242  threadNameLabel.setText(Bundle.MessageViewer_viewMessage_unthreaded());
243  }
244 
245  showMessagesPane();
246  }
247  }
248 
252  private void showThreadsPane() {
253  switchCard("threads");
254  }
255 
259  private void showMessagesPane() {
260  switchCard("messages");
261  Outline outline = rootTablePane.getOutlineView().getOutline();
262  outline.clearSelection();
263  }
264 
270  private void switchCard(String cardName) {
271  SwingUtilities.invokeLater(new Runnable() {
272  @Override
273  public void run() {
274  CardLayout layout = (CardLayout) getLayout();
275  layout.show(MessageViewer.this, cardName);
276  }
277  });
278  }
279 
289  private Image getScaledImage(Image srcImg, int w, int h) {
290  BufferedImage resizedImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
291  Graphics2D g2 = resizedImg.createGraphics();
292 
293  g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
294  g2.drawImage(srcImg, 0, 0, w, h, null);
295  g2.dispose();
296 
297  return resizedImg;
298  }
299 
305  @SuppressWarnings("unchecked")
306  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
307  private void initComponents() {
308  java.awt.GridBagConstraints gridBagConstraints;
309 
310  rootMessagesPane = new javax.swing.JPanel();
311  threadsLabel = new javax.swing.JLabel();
312  showAllButton = new javax.swing.JButton();
314  messagePanel = new javax.swing.JPanel();
315  threadMessagesPanel = new MessagesPanel();
316  backButton = new javax.swing.JButton();
317  showingMessagesLabel = new javax.swing.JLabel();
318  threadNameLabel = new javax.swing.JLabel();
319 
320  setLayout(new java.awt.CardLayout());
321 
322  rootMessagesPane.setOpaque(false);
323  rootMessagesPane.setLayout(new java.awt.GridBagLayout());
324 
325  org.openide.awt.Mnemonics.setLocalizedText(threadsLabel, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.threadsLabel.text")); // NOI18N
326  gridBagConstraints = new java.awt.GridBagConstraints();
327  gridBagConstraints.gridx = 0;
328  gridBagConstraints.gridy = 0;
329  gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
330  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
331  gridBagConstraints.weightx = 1.0;
332  gridBagConstraints.insets = new java.awt.Insets(15, 15, 9, 0);
333  rootMessagesPane.add(threadsLabel, gridBagConstraints);
334 
335  org.openide.awt.Mnemonics.setLocalizedText(showAllButton, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.showAllButton.text")); // NOI18N
336  showAllButton.addActionListener(new java.awt.event.ActionListener() {
337  public void actionPerformed(java.awt.event.ActionEvent evt) {
338  showAllButtonActionPerformed(evt);
339  }
340  });
341  gridBagConstraints = new java.awt.GridBagConstraints();
342  gridBagConstraints.gridx = 0;
343  gridBagConstraints.gridy = 2;
344  gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
345  gridBagConstraints.insets = new java.awt.Insets(0, 15, 15, 0);
346  rootMessagesPane.add(showAllButton, gridBagConstraints);
347 
348  rootTablePane.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
349  gridBagConstraints = new java.awt.GridBagConstraints();
350  gridBagConstraints.gridx = 0;
351  gridBagConstraints.gridy = 1;
352  gridBagConstraints.gridwidth = 2;
353  gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
354  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
355  gridBagConstraints.weightx = 1.0;
356  gridBagConstraints.weighty = 1.0;
357  gridBagConstraints.insets = new java.awt.Insets(0, 15, 9, 15);
358  rootMessagesPane.add(rootTablePane, gridBagConstraints);
359 
360  add(rootMessagesPane, "threads");
361 
362  messagePanel.setLayout(new java.awt.GridBagLayout());
363  gridBagConstraints = new java.awt.GridBagConstraints();
364  gridBagConstraints.gridx = 0;
365  gridBagConstraints.gridy = 3;
366  gridBagConstraints.gridwidth = 3;
367  gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
368  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
369  gridBagConstraints.weightx = 1.0;
370  gridBagConstraints.weighty = 1.0;
371  gridBagConstraints.insets = new java.awt.Insets(0, 15, 0, 15);
372  messagePanel.add(threadMessagesPanel, gridBagConstraints);
373 
374  org.openide.awt.Mnemonics.setLocalizedText(backButton, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.backButton.text")); // NOI18N
375  backButton.addActionListener(new java.awt.event.ActionListener() {
376  public void actionPerformed(java.awt.event.ActionEvent evt) {
377  backButtonActionPerformed(evt);
378  }
379  });
380  gridBagConstraints = new java.awt.GridBagConstraints();
381  gridBagConstraints.gridx = 2;
382  gridBagConstraints.gridy = 0;
383  gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
384  gridBagConstraints.weightx = 1.0;
385  gridBagConstraints.insets = new java.awt.Insets(9, 0, 9, 15);
386  messagePanel.add(backButton, gridBagConstraints);
387  backButton.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.backButton.AccessibleContext.accessibleDescription")); // NOI18N
388 
389  org.openide.awt.Mnemonics.setLocalizedText(showingMessagesLabel, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.showingMessagesLabel.text")); // NOI18N
390  gridBagConstraints = new java.awt.GridBagConstraints();
391  gridBagConstraints.gridx = 0;
392  gridBagConstraints.gridy = 0;
393  gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
394  gridBagConstraints.insets = new java.awt.Insets(9, 15, 5, 0);
395  messagePanel.add(showingMessagesLabel, gridBagConstraints);
396 
397  org.openide.awt.Mnemonics.setLocalizedText(threadNameLabel, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.threadNameLabel.text")); // NOI18N
398  gridBagConstraints = new java.awt.GridBagConstraints();
399  gridBagConstraints.gridx = 1;
400  gridBagConstraints.gridy = 0;
401  gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
402  gridBagConstraints.insets = new java.awt.Insets(9, 5, 5, 15);
403  messagePanel.add(threadNameLabel, gridBagConstraints);
404 
405  add(messagePanel, "messages");
406  }// </editor-fold>//GEN-END:initComponents
407 
408  private void backButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_backButtonActionPerformed
409  try {
410  rootTablePane.getExplorerManager().setSelectedNodes(new Node[0]);
411  } catch (PropertyVetoException ex) {
412  logger.log(Level.WARNING, "Error setting selected nodes", ex);
413  }
414  showThreadsPane();
415  }//GEN-LAST:event_backButtonActionPerformed
416 
417  private void showAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showAllButtonActionPerformed
418  threadMessageNodeFactory.refresh(currentSelectionInfo, null);
419  threadNameLabel.setText("All Messages");
420 
421  showMessagesPane();
422  }//GEN-LAST:event_showAllButtonActionPerformed
423 
424  // Variables declaration - do not modify//GEN-BEGIN:variables
425  private javax.swing.JButton backButton;
426  private javax.swing.JPanel messagePanel;
427  private javax.swing.JPanel rootMessagesPane;
429  private javax.swing.JButton showAllButton;
430  private javax.swing.JLabel showingMessagesLabel;
431  private org.sleuthkit.autopsy.communications.relationships.MessagesPanel threadMessagesPanel;
432  private javax.swing.JLabel threadNameLabel;
433  private javax.swing.JLabel threadsLabel;
434  // End of variables declaration//GEN-END:variables
435 
439  class ShowThreadMessagesAction extends AbstractAction {
440 
441  @Override
442  public void actionPerformed(ActionEvent e) {
443 
444  SwingUtilities.invokeLater(new Runnable() {
445  @Override
446  public void run() {
447  showSelectedThread();
448  }
449  });
450  }
451  }
452 }
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

Copyright © 2012-2020 Basis Technology. Generated on: Mon Jul 6 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.