19 package org.sleuthkit.autopsy.communications.relationships;
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;
59 @SuppressWarnings(
"PMD.SingularField")
74 "MessageViewer_tabTitle=Messages",
75 "MessageViewer_columnHeader_From=From",
76 "MessageViewer_columnHeader_Date=Date",
77 "MessageViewer_columnHeader_To=To",
78 "MessageViewer_columnHeader_EarlyDate=Earliest Message",
79 "MessageViewer_columnHeader_Subject=Subject",
80 "MessageViewer_columnHeader_Attms=Attachments",
81 "MessageViewer_no_messages=<No messages found for selected account>",
82 "MessageViewer_viewMessage_all=All",
83 "MessageViewer_viewMessage_selected=Selected",
84 "MessageViewer_viewMessage_unthreaded=Unthreaded",
85 "MessageViewer_viewMessage_calllogs=Call Logs"})
93 currentPanel = rootTablePane;
94 proxyLookup =
new ModifiableProxyLookup(createLookup(rootTablePane.getExplorerManager(), getActionMap()));
95 rootMessageFactory =
new ThreadChildNodeFactory(
new ShowThreadMessagesAction());
100 focusPropertyListener = (
final PropertyChangeEvent focusEvent) -> {
101 if (focusEvent.getPropertyName().equalsIgnoreCase(
"focusOwner")) {
102 final Component newFocusOwner = (Component) focusEvent.getNewValue();
104 if (newFocusOwner == null) {
107 if (isDescendingFrom(newFocusOwner, rootTablePane)) {
108 proxyLookup.
setNewLookups(createLookup(rootTablePane.getExplorerManager(), getActionMap()));
109 }
else if (isDescendingFrom(newFocusOwner,
MessageViewer.this)) {
115 rootTablePane.getExplorerManager().setRootContext(
116 new AbstractNode(Children.create(rootMessageFactory,
true)));
118 rootTablePane.getOutlineView().setPopupAllowed(
false);
120 Outline outline = rootTablePane.getOutlineView().getOutline();
121 rootTablePane.getOutlineView().setPropertyColumns(
122 "Date", Bundle.MessageViewer_columnHeader_EarlyDate(),
123 "Subject", Bundle.MessageViewer_columnHeader_Subject()
125 outline.setRootVisible(
false);
126 ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(
"Type");
127 outline.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
129 rootTablePane.getExplorerManager().addPropertyChangeListener((PropertyChangeEvent evt) -> {
130 if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
131 showSelectedThread();
135 threadMessagesPanel.setChildFactory(threadMessageNodeFactory);
137 rootTablePane.setTableColumnsWidth(10, 20, 70);
139 Image image = getScaledImage((
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/timeline/images/arrow-180.png"))).getImage(), 16, 16);
140 backButton.setIcon(
new ImageIcon(image) );
145 return Bundle.MessageViewer_tabTitle();
155 currentSelectionInfo = info;
157 currentPanel = rootTablePane;
159 CardLayout layout = (CardLayout) this.getLayout();
160 layout.show(
this,
"threads");
162 rootMessageFactory.refresh(info);
174 KeyboardFocusManager.getCurrentKeyboardFocusManager()
175 .addPropertyChangeListener(
"focusOwner", focusPropertyListener);
180 super.removeNotify();
181 KeyboardFocusManager.getCurrentKeyboardFocusManager()
182 .removePropertyChangeListener(
"focusOwner", focusPropertyListener);
185 @SuppressWarnings(
"rawtypes")
186 private
void showSelectedThread() {
187 final Node[] nodes = rootTablePane.getExplorerManager().getSelectedNodes();
193 if (nodes.length == 0 || nodes.length > 1) {
197 ArrayList<String> threadIDList =
new ArrayList<>();
200 PropertySet[] propertySets = nodes[0].getPropertySets();
201 for (PropertySet pset : propertySets) {
202 Property[] properties = pset.getProperties();
203 for (Property prop : properties) {
204 if (prop.getName().equalsIgnoreCase(
"threadid")) {
206 String threadID = prop.getValue().toString();
207 if (!threadIDList.contains(threadID)) {
208 threadIDList.add(threadID);
210 }
catch (IllegalAccessException | InvocationTargetException ex) {
211 logger.log(Level.WARNING, String.format(
"Unable to get threadid for node: %s", nodes[0].getDisplayName()), ex);
213 }
else if (prop.getName().equalsIgnoreCase(
"subject")) {
215 subject = prop.getValue().toString();
216 }
catch (IllegalAccessException | InvocationTargetException ex) {
217 logger.log(Level.WARNING, String.format(
"Unable to get subject for node: %s", nodes[0].getDisplayName()), ex);
218 subject =
"<unavailable>";
225 if (!threadIDList.isEmpty()) {
226 threadMessageNodeFactory.
refresh(currentSelectionInfo, threadIDList);
228 if (!subject.isEmpty()) {
229 threadNameLabel.setText(subject);
231 threadNameLabel.setText(Bundle.MessageViewer_viewMessage_unthreaded());
242 switchCard(
"threads");
249 switchCard(
"messages");
258 SwingUtilities.invokeLater(
new Runnable() {
261 CardLayout layout = (CardLayout)getLayout();
277 BufferedImage resizedImg =
new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
278 Graphics2D g2 = resizedImg.createGraphics();
280 g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
281 g2.drawImage(srcImg, 0, 0, w, h, null);
292 @SuppressWarnings(
"unchecked")
294 private
void initComponents() {
295 java.awt.GridBagConstraints gridBagConstraints;
297 rootMessagesPane =
new javax.swing.JPanel();
298 threadsLabel =
new javax.swing.JLabel();
299 showAllButton =
new javax.swing.JButton();
301 messagePanel =
new javax.swing.JPanel();
303 backButton =
new javax.swing.JButton();
304 showingMessagesLabel =
new javax.swing.JLabel();
305 threadNameLabel =
new javax.swing.JLabel();
307 setLayout(
new java.awt.CardLayout());
309 rootMessagesPane.setOpaque(
false);
310 rootMessagesPane.setLayout(
new java.awt.GridBagLayout());
312 org.openide.awt.Mnemonics.setLocalizedText(threadsLabel,
org.openide.util.NbBundle.getMessage(
MessageViewer.class,
"MessageViewer.threadsLabel.text"));
313 gridBagConstraints =
new java.awt.GridBagConstraints();
314 gridBagConstraints.gridx = 0;
315 gridBagConstraints.gridy = 0;
316 gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
317 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
318 gridBagConstraints.weightx = 1.0;
319 gridBagConstraints.insets =
new java.awt.Insets(15, 15, 9, 0);
320 rootMessagesPane.add(threadsLabel, gridBagConstraints);
322 org.openide.awt.Mnemonics.setLocalizedText(showAllButton,
org.openide.util.NbBundle.getMessage(
MessageViewer.class,
"MessageViewer.showAllButton.text"));
323 showAllButton.addActionListener(
new java.awt.event.ActionListener() {
324 public void actionPerformed(java.awt.event.ActionEvent evt) {
325 showAllButtonActionPerformed(evt);
328 gridBagConstraints =
new java.awt.GridBagConstraints();
329 gridBagConstraints.gridx = 0;
330 gridBagConstraints.gridy = 2;
331 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
332 gridBagConstraints.insets =
new java.awt.Insets(0, 15, 15, 0);
333 rootMessagesPane.add(showAllButton, gridBagConstraints);
335 rootTablePane.setBorder(javax.swing.BorderFactory.createLineBorder(
new java.awt.Color(0, 0, 0)));
336 gridBagConstraints =
new java.awt.GridBagConstraints();
337 gridBagConstraints.gridx = 0;
338 gridBagConstraints.gridy = 1;
339 gridBagConstraints.gridwidth = 2;
340 gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
341 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
342 gridBagConstraints.weightx = 1.0;
343 gridBagConstraints.weighty = 1.0;
344 gridBagConstraints.insets =
new java.awt.Insets(0, 15, 9, 15);
345 rootMessagesPane.add(rootTablePane, gridBagConstraints);
347 add(rootMessagesPane,
"threads");
349 messagePanel.setLayout(
new java.awt.GridBagLayout());
350 gridBagConstraints =
new java.awt.GridBagConstraints();
351 gridBagConstraints.gridx = 0;
352 gridBagConstraints.gridy = 3;
353 gridBagConstraints.gridwidth = 3;
354 gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
355 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
356 gridBagConstraints.weightx = 1.0;
357 gridBagConstraints.weighty = 1.0;
358 gridBagConstraints.insets =
new java.awt.Insets(0, 15, 0, 15);
359 messagePanel.add(threadMessagesPanel, gridBagConstraints);
361 org.openide.awt.Mnemonics.setLocalizedText(backButton,
org.openide.util.NbBundle.getMessage(
MessageViewer.class,
"MessageViewer.backButton.text"));
362 backButton.addActionListener(
new java.awt.event.ActionListener() {
363 public void actionPerformed(java.awt.event.ActionEvent evt) {
364 backButtonActionPerformed(evt);
367 gridBagConstraints =
new java.awt.GridBagConstraints();
368 gridBagConstraints.gridx = 2;
369 gridBagConstraints.gridy = 0;
370 gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
371 gridBagConstraints.weightx = 1.0;
372 gridBagConstraints.insets =
new java.awt.Insets(9, 0, 9, 15);
373 messagePanel.add(backButton, gridBagConstraints);
374 backButton.getAccessibleContext().setAccessibleDescription(
org.openide.util.NbBundle.getMessage(
MessageViewer.class,
"MessageViewer.backButton.AccessibleContext.accessibleDescription"));
376 org.openide.awt.Mnemonics.setLocalizedText(showingMessagesLabel,
org.openide.util.NbBundle.getMessage(
MessageViewer.class,
"MessageViewer.showingMessagesLabel.text"));
377 gridBagConstraints =
new java.awt.GridBagConstraints();
378 gridBagConstraints.gridx = 0;
379 gridBagConstraints.gridy = 0;
380 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
381 gridBagConstraints.insets =
new java.awt.Insets(9, 15, 5, 0);
382 messagePanel.add(showingMessagesLabel, gridBagConstraints);
384 org.openide.awt.Mnemonics.setLocalizedText(threadNameLabel,
org.openide.util.NbBundle.getMessage(
MessageViewer.class,
"MessageViewer.threadNameLabel.text"));
385 gridBagConstraints =
new java.awt.GridBagConstraints();
386 gridBagConstraints.gridx = 1;
387 gridBagConstraints.gridy = 0;
388 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
389 gridBagConstraints.insets =
new java.awt.Insets(9, 5, 5, 15);
390 messagePanel.add(threadNameLabel, gridBagConstraints);
392 add(messagePanel,
"messages");
397 rootTablePane.getExplorerManager().setSelectedNodes(
new Node[0]);
398 }
catch (PropertyVetoException ex) {
399 logger.log(Level.WARNING,
"Error setting selected nodes", ex);
405 threadMessageNodeFactory.
refresh(currentSelectionInfo, null);
406 threadNameLabel.setText(
"All Messages");
426 class ShowThreadMessagesAction
extends AbstractAction {
429 public void actionPerformed(ActionEvent e) {
431 SwingUtilities.invokeLater(
new Runnable() {
434 showSelectedThread();
ExplorerManager getExplorerManager()
final PropertyChangeListener focusPropertyListener
javax.swing.JPanel messagePanel
void setSelectionInfo(SelectionInfo info)
final MessagesChildNodeFactory threadMessageNodeFactory
javax.swing.JPanel rootMessagesPane
javax.swing.JLabel showingMessagesLabel
void setNewLookups(final Lookup...lookups)
Image getScaledImage(Image srcImg, int w, int h)
javax.swing.JLabel threadsLabel
void showAllButtonActionPerformed(java.awt.event.ActionEvent evt)
final ThreadChildNodeFactory rootMessageFactory
final ModifiableProxyLookup proxyLookup
void backButtonActionPerformed(java.awt.event.ActionEvent evt)
void refresh(SelectionInfo selectionInfo, List< String > threadIDs)
org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel rootTablePane
synchronized static Logger getLogger(String name)
javax.swing.JButton showAllButton
javax.swing.JButton backButton
org.sleuthkit.autopsy.communications.relationships.MessagesPanel threadMessagesPanel
javax.swing.JLabel threadNameLabel
void switchCard(String cardName)