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");
250 Outline outline = rootTablePane.getOutlineView().getOutline();
251 outline.clearSelection();
260 SwingUtilities.invokeLater(
new Runnable() {
263 CardLayout layout = (CardLayout)getLayout();
279 BufferedImage resizedImg =
new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
280 Graphics2D g2 = resizedImg.createGraphics();
282 g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
283 g2.drawImage(srcImg, 0, 0, w, h, null);
294 @SuppressWarnings(
"unchecked")
296 private
void initComponents() {
297 java.awt.GridBagConstraints gridBagConstraints;
299 rootMessagesPane =
new javax.swing.JPanel();
300 threadsLabel =
new javax.swing.JLabel();
301 showAllButton =
new javax.swing.JButton();
303 messagePanel =
new javax.swing.JPanel();
305 backButton =
new javax.swing.JButton();
306 showingMessagesLabel =
new javax.swing.JLabel();
307 threadNameLabel =
new javax.swing.JLabel();
309 setLayout(
new java.awt.CardLayout());
311 rootMessagesPane.setOpaque(
false);
312 rootMessagesPane.setLayout(
new java.awt.GridBagLayout());
314 org.openide.awt.Mnemonics.setLocalizedText(threadsLabel,
org.openide.util.NbBundle.getMessage(
MessageViewer.class,
"MessageViewer.threadsLabel.text"));
315 gridBagConstraints =
new java.awt.GridBagConstraints();
316 gridBagConstraints.gridx = 0;
317 gridBagConstraints.gridy = 0;
318 gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
319 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
320 gridBagConstraints.weightx = 1.0;
321 gridBagConstraints.insets =
new java.awt.Insets(15, 15, 9, 0);
322 rootMessagesPane.add(threadsLabel, gridBagConstraints);
324 org.openide.awt.Mnemonics.setLocalizedText(showAllButton,
org.openide.util.NbBundle.getMessage(
MessageViewer.class,
"MessageViewer.showAllButton.text"));
325 showAllButton.addActionListener(
new java.awt.event.ActionListener() {
326 public void actionPerformed(java.awt.event.ActionEvent evt) {
327 showAllButtonActionPerformed(evt);
330 gridBagConstraints =
new java.awt.GridBagConstraints();
331 gridBagConstraints.gridx = 0;
332 gridBagConstraints.gridy = 2;
333 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
334 gridBagConstraints.insets =
new java.awt.Insets(0, 15, 15, 0);
335 rootMessagesPane.add(showAllButton, gridBagConstraints);
337 rootTablePane.setBorder(javax.swing.BorderFactory.createLineBorder(
new java.awt.Color(0, 0, 0)));
338 gridBagConstraints =
new java.awt.GridBagConstraints();
339 gridBagConstraints.gridx = 0;
340 gridBagConstraints.gridy = 1;
341 gridBagConstraints.gridwidth = 2;
342 gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
343 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
344 gridBagConstraints.weightx = 1.0;
345 gridBagConstraints.weighty = 1.0;
346 gridBagConstraints.insets =
new java.awt.Insets(0, 15, 9, 15);
347 rootMessagesPane.add(rootTablePane, gridBagConstraints);
349 add(rootMessagesPane,
"threads");
351 messagePanel.setLayout(
new java.awt.GridBagLayout());
352 gridBagConstraints =
new java.awt.GridBagConstraints();
353 gridBagConstraints.gridx = 0;
354 gridBagConstraints.gridy = 3;
355 gridBagConstraints.gridwidth = 3;
356 gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
357 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
358 gridBagConstraints.weightx = 1.0;
359 gridBagConstraints.weighty = 1.0;
360 gridBagConstraints.insets =
new java.awt.Insets(0, 15, 0, 15);
361 messagePanel.add(threadMessagesPanel, gridBagConstraints);
363 org.openide.awt.Mnemonics.setLocalizedText(backButton,
org.openide.util.NbBundle.getMessage(
MessageViewer.class,
"MessageViewer.backButton.text"));
364 backButton.addActionListener(
new java.awt.event.ActionListener() {
365 public void actionPerformed(java.awt.event.ActionEvent evt) {
366 backButtonActionPerformed(evt);
369 gridBagConstraints =
new java.awt.GridBagConstraints();
370 gridBagConstraints.gridx = 2;
371 gridBagConstraints.gridy = 0;
372 gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
373 gridBagConstraints.weightx = 1.0;
374 gridBagConstraints.insets =
new java.awt.Insets(9, 0, 9, 15);
375 messagePanel.add(backButton, gridBagConstraints);
376 backButton.getAccessibleContext().setAccessibleDescription(
org.openide.util.NbBundle.getMessage(
MessageViewer.class,
"MessageViewer.backButton.AccessibleContext.accessibleDescription"));
378 org.openide.awt.Mnemonics.setLocalizedText(showingMessagesLabel,
org.openide.util.NbBundle.getMessage(
MessageViewer.class,
"MessageViewer.showingMessagesLabel.text"));
379 gridBagConstraints =
new java.awt.GridBagConstraints();
380 gridBagConstraints.gridx = 0;
381 gridBagConstraints.gridy = 0;
382 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
383 gridBagConstraints.insets =
new java.awt.Insets(9, 15, 5, 0);
384 messagePanel.add(showingMessagesLabel, gridBagConstraints);
386 org.openide.awt.Mnemonics.setLocalizedText(threadNameLabel,
org.openide.util.NbBundle.getMessage(
MessageViewer.class,
"MessageViewer.threadNameLabel.text"));
387 gridBagConstraints =
new java.awt.GridBagConstraints();
388 gridBagConstraints.gridx = 1;
389 gridBagConstraints.gridy = 0;
390 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
391 gridBagConstraints.insets =
new java.awt.Insets(9, 5, 5, 15);
392 messagePanel.add(threadNameLabel, gridBagConstraints);
394 add(messagePanel,
"messages");
399 rootTablePane.getExplorerManager().setSelectedNodes(
new Node[0]);
400 }
catch (PropertyVetoException ex) {
401 logger.log(Level.WARNING,
"Error setting selected nodes", ex);
407 threadMessageNodeFactory.
refresh(currentSelectionInfo, null);
408 threadNameLabel.setText(
"All Messages");
428 class ShowThreadMessagesAction
extends AbstractAction {
431 public void actionPerformed(ActionEvent e) {
433 SwingUtilities.invokeLater(
new Runnable() {
436 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)