19 package org.sleuthkit.autopsy.communications;
 
   21 import com.google.common.eventbus.Subscribe;
 
   22 import com.mxgraph.layout.hierarchical.mxHierarchicalLayout;
 
   23 import com.mxgraph.layout.mxCircleLayout;
 
   24 import com.mxgraph.layout.mxFastOrganicLayout;
 
   25 import com.mxgraph.layout.mxIGraphLayout;
 
   26 import com.mxgraph.layout.mxOrganicLayout;
 
   27 import com.mxgraph.model.mxCell;
 
   28 import com.mxgraph.model.mxICell;
 
   29 import com.mxgraph.swing.handler.mxRubberband;
 
   30 import com.mxgraph.swing.mxGraphComponent;
 
   31 import com.mxgraph.util.mxCellRenderer;
 
   32 import com.mxgraph.util.mxEvent;
 
   33 import com.mxgraph.util.mxEventObject;
 
   34 import com.mxgraph.util.mxEventSource;
 
   35 import com.mxgraph.util.mxPoint;
 
   36 import com.mxgraph.util.mxRectangle;
 
   37 import com.mxgraph.util.mxUndoManager;
 
   38 import com.mxgraph.util.mxUndoableEdit;
 
   39 import com.mxgraph.view.mxCellState;
 
   40 import com.mxgraph.view.mxGraph;
 
   41 import com.mxgraph.view.mxGraphView;
 
   42 import java.awt.BorderLayout;
 
   43 import java.awt.Color;
 
   44 import java.awt.Cursor;
 
   45 import java.awt.Desktop;
 
   46 import java.awt.Dimension;
 
   48 import java.awt.Frame;
 
   49 import java.awt.Graphics;
 
   50 import java.awt.GridLayout;
 
   51 import java.awt.event.ActionEvent;
 
   52 import java.awt.event.ActionListener;
 
   53 import java.awt.event.MouseAdapter;
 
   54 import java.awt.event.MouseEvent;
 
   55 import java.awt.event.MouseWheelEvent;
 
   56 import java.awt.image.BufferedImage;
 
   57 import java.beans.PropertyChangeEvent;
 
   58 import java.beans.PropertyVetoException;
 
   59 import java.io.IOException;
 
   60 import java.nio.file.Files;
 
   61 import java.nio.file.Path;
 
   62 import java.nio.file.Paths;
 
   63 import java.text.DecimalFormat;
 
   64 import java.text.SimpleDateFormat;
 
   65 import java.util.Arrays;
 
   66 import java.util.Date;
 
   67 import java.util.EnumSet;
 
   68 import java.util.HashMap;
 
   69 import java.util.HashSet;
 
   70 import java.util.List;
 
   73 import java.util.concurrent.ExecutionException;
 
   74 import java.util.concurrent.Future;
 
   75 import java.util.function.BiConsumer;
 
   76 import java.util.logging.Level;
 
   77 import java.util.stream.Collectors;
 
   78 import java.util.stream.Stream;
 
   79 import javafx.application.Platform;
 
   80 import javafx.embed.swing.JFXPanel;
 
   81 import javafx.scene.Scene;
 
   82 import javafx.scene.layout.Pane;
 
   83 import javax.swing.AbstractAction;
 
   84 import javax.swing.ImageIcon;
 
   85 import javax.swing.JButton;
 
   86 import javax.swing.JLabel;
 
   87 import javax.swing.JMenuItem;
 
   88 import javax.swing.JOptionPane;
 
   89 import javax.swing.JPanel;
 
   90 import javax.swing.JPopupMenu;
 
   91 import javax.swing.JSplitPane;
 
   92 import javax.swing.JTextArea;
 
   93 import javax.swing.JTextField;
 
   94 import javax.swing.JToolBar;
 
   95 import javax.swing.SwingConstants;
 
   96 import javax.swing.SwingUtilities;
 
   97 import javax.swing.SwingWorker;
 
   98 import org.apache.commons.lang3.StringUtils;
 
   99 import org.controlsfx.control.Notifications;
 
  100 import org.jdesktop.layout.GroupLayout;
 
  101 import org.jdesktop.layout.LayoutStyle;
 
  102 import org.openide.explorer.ExplorerManager;
 
  103 import org.openide.explorer.ExplorerUtils;
 
  104 import org.openide.nodes.Node;
 
  105 import org.openide.util.Lookup;
 
  106 import org.openide.util.NbBundle;
 
  107 import org.openide.util.lookup.ProxyLookup;
 
  108 import org.openide.windows.WindowManager;
 
  130 @SuppressWarnings(
"PMD.SingularField") 
 
  133     private static final long serialVersionUID = 1L;
 
  135     private static final String BASE_IMAGE_PATH = 
"/org/sleuthkit/autopsy/communications/images";
 
  136     static final private ImageIcon unlockIcon
 
  138     static final private ImageIcon lockIcon
 
  141     @NbBundle.Messages(
"VisualizationPanel.cancelButton.text=Cancel")
 
  142     private static final String CANCEL = Bundle.VisualizationPanel_cancelButton_text();
 
  144     private final ExplorerManager vizEM = 
new ExplorerManager();
 
  145     private final ExplorerManager gacEM = 
new ExplorerManager();
 
  153     private final CommunicationsGraph 
graph;
 
  155     private final mxUndoManager undoManager = 
new mxUndoManager();
 
  159     private SwingWorker<?, ?> worker;
 
  160     private final PinnedAccountModel pinnedAccountModel = new PinnedAccountModel();
 
  161     private final LockedVertexModel lockedVertexModel = new LockedVertexModel();
 
  164     private NamedGraphLayout currentLayout;
 
  166     @NbBundle.Messages("VisalizationPanel.paintingError=Problem painting visualization.")
 
  170         notificationsJFXPanel.setScene(
new Scene(
new Pane()));
 
  172         graph = 
new CommunicationsGraph(pinnedAccountModel, lockedVertexModel);
 
  180         graphComponent = 
new mxGraphComponent(graph) {
 
  182             protected mxGraphComponent.mxGraphControl createGraphControl() {
 
  184                 return new mxGraphControl() {
 
  187                     public void paint(Graphics graphics) {
 
  189                             super.paint(graphics);
 
  190                         } 
catch (NullPointerException ex) { 
 
  196                             logger.log(Level.WARNING, 
"There was a NPE while painting the VisualizationPanel", ex);
 
  203         graphComponent.setAutoExtend(
true);
 
  204         graphComponent.setAutoScroll(
true);
 
  205         graphComponent.setAutoscrolls(
true);
 
  206         graphComponent.setConnectable(
false);
 
  207         graphComponent.setDragEnabled(
false);
 
  208         graphComponent.setKeepSelectionVisibleOnZoom(
true);
 
  209         graphComponent.setOpaque(
true);
 
  210         graphComponent.setToolTips(
true);
 
  211         graphComponent.setBackground(Color.WHITE);
 
  212         borderLayoutPanel.add(graphComponent, BorderLayout.CENTER);
 
  215         rubberband = 
new mxRubberband(graphComponent);
 
  217         lockedVertexModel.registerhandler(
this);
 
  219         final mxEventSource.mxIEventListener scaleListener = (Object sender, mxEventObject evt)
 
  220                 -> zoomLabel.setText(DecimalFormat.getPercentInstance().format(graph.getView().getScale()));
 
  221         graph.getView().addListener(mxEvent.SCALE, scaleListener);
 
  222         graph.getView().addListener(mxEvent.SCALE_AND_TRANSLATE, scaleListener);
 
  225         graphComponent.getGraphControl().addMouseWheelListener(graphMouseListener);
 
  226         graphComponent.getGraphControl().addMouseListener(graphMouseListener);
 
  229         splitPane.setRightComponent(messageBrowser);
 
  230         proxyLookup = 
new ProxyLookup(
 
  231                 ExplorerUtils.createLookup(vizEM, getActionMap()),
 
  237         final mxEventSource.mxIEventListener undoListener = (Object sender, mxEventObject evt)
 
  238                 -> undoManager.undoableEditHappened((mxUndoableEdit) evt.getProperty(
"edit"));
 
  240         graph.getModel().addListener(mxEvent.UNDO, undoListener);
 
  241         graph.getView().addListener(mxEvent.UNDO, undoListener);
 
  246         organicLayout.setMaxIterations(10);
 
  250         BiConsumer<JButton, NamedGraphLayout> configure = (layoutButton, layout) -> {
 
  251             layoutButtons.put(layout, layoutButton);
 
  252             layoutButton.addActionListener(event -> applyLayout(layout));
 
  255         configure.accept(circleLayoutButton, circleLayout);
 
  256         configure.accept(organicLayoutButton, organicLayout);
 
  257         configure.accept(fastOrganicLayoutButton, fastOrganicLayout);
 
  258         configure.accept(hierarchyLayoutButton, hierarchyLayout);
 
  260         applyLayout(fastOrganicLayout);
 
  269     void handle(LockedVertexModel.VertexLockEvent event) {
 
  270         final Set<mxCell> vertices = 
event.getVertices();
 
  271         mxGraphView view = graph.getView();
 
  272         vertices.forEach(vertex -> {
 
  273             final mxCellState state = view.getState(vertex, 
true);
 
  274             view.updateLabel(state);
 
  275             view.updateLabelBounds(state);
 
  276             view.updateBoundingBox(state);
 
  277             graphComponent.redraw(state);
 
  282     void handle(
final CVTEvents.UnpinAccountsEvent pinEvent) {
 
  283         graph.getModel().beginUpdate();
 
  284         pinnedAccountModel.unpinAccount(pinEvent.getAccountDeviceInstances());
 
  288         graph.getModel().endUpdate();
 
  292     void handle(
final CVTEvents.PinAccountsEvent pinEvent) {
 
  293         graph.getModel().beginUpdate();
 
  294         if (pinEvent.isReplace()) {
 
  297         pinnedAccountModel.pinAccount(pinEvent.getAccountDeviceInstances());
 
  300         graph.getModel().endUpdate();
 
  304     void handle(
final CVTEvents.FilterChangeEvent filterChangeEvent) {
 
  305         graph.getModel().beginUpdate();
 
  307         currentFilter = filterChangeEvent.getNewFilter();
 
  310         graph.getModel().endUpdate();
 
  313     @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
 
  314     private 
void rebuildGraph() {
 
  315         if (pinnedAccountModel.isEmpty()) {
 
  316             borderLayoutPanel.remove(graphComponent);
 
  317             borderLayoutPanel.add(placeHolderPanel, BorderLayout.CENTER);
 
  320             borderLayoutPanel.remove(placeHolderPanel);
 
  321             borderLayoutPanel.add(graphComponent, BorderLayout.CENTER);
 
  322             if (worker != null) {
 
  328             worker = graph.rebuild(progress, commsManager, currentFilter);
 
  329             cancelationListener.configure(worker, progress);
 
  330             worker.addPropertyChangeListener((
final PropertyChangeEvent evt) -> {
 
  331                 if (worker.isDone()) {
 
  332                     if (worker.isCancelled()) {
 
  336                     applyLayout(currentLayout);
 
  347         windowAncestor = (Frame) SwingUtilities.getAncestorOfClass(Frame.class, 
this);
 
  351         } 
catch (TskCoreException ex) {
 
  352             logger.log(Level.SEVERE, 
"Error getting CommunicationsManager for the current case.", ex);
 
  354             logger.log(Level.SEVERE, 
"Can't get CommunicationsManager when there is no case open.", ex);
 
  358             graph.getModel().beginUpdate();
 
  362                 graph.getModel().endUpdate();
 
  364             if (evt.getNewValue() == null) {
 
  367                 Case currentCase = (
Case) evt.getNewValue();
 
  370                 } 
catch (TskCoreException ex) {
 
  371                     logger.log(Level.SEVERE, 
"Error getting CommunicationsManager for the current case.", ex);
 
  382     @SuppressWarnings(
"unchecked")
 
  384     private 
void initComponents() {
 
  386         splitPane = 
new JSplitPane();
 
  387         borderLayoutPanel = 
new JPanel();
 
  388         placeHolderPanel = 
new JPanel();
 
  389         jTextArea1 = 
new JTextArea();
 
  390         toolbar = 
new JPanel();
 
  391         jLabel1 = 
new JLabel();
 
  392         hierarchyLayoutButton = 
new JButton();
 
  393         fastOrganicLayoutButton = 
new JButton();
 
  394         organicLayoutButton = 
new JButton();
 
  395         circleLayoutButton = 
new JButton();
 
  396         jSeparator1 = 
new JToolBar.Separator();
 
  397         zoomOutButton = 
new JButton();
 
  398         zoomInButton = 
new JButton();
 
  399         zoomActualButton = 
new JButton();
 
  400         fitZoomButton = 
new JButton();
 
  401         jLabel2 = 
new JLabel();
 
  402         zoomLabel = 
new JLabel();
 
  403         clearVizButton = 
new JButton();
 
  404         jSeparator2 = 
new JToolBar.Separator();
 
  405         snapshotButton = 
new JButton();
 
  406         jSeparator3 = 
new JToolBar.Separator();
 
  407         notificationsJFXPanel = 
new JFXPanel();
 
  409         setLayout(
new BorderLayout());
 
  411         splitPane.setDividerLocation(800);
 
  412         splitPane.setResizeWeight(0.5);
 
  414         borderLayoutPanel.setLayout(
new BorderLayout());
 
  416         jTextArea1.setBackground(
new Color(240, 240, 240));
 
  417         jTextArea1.setColumns(20);
 
  418         jTextArea1.setLineWrap(
true);
 
  419         jTextArea1.setRows(5);
 
  420         jTextArea1.setText(NbBundle.getMessage(
VisualizationPanel.class, 
"VisualizationPanel.jTextArea1.text")); 
 
  422         GroupLayout placeHolderPanelLayout = 
new GroupLayout(placeHolderPanel);
 
  423         placeHolderPanel.setLayout(placeHolderPanelLayout);
 
  424         placeHolderPanelLayout.setHorizontalGroup(placeHolderPanelLayout.createParallelGroup(GroupLayout.LEADING)
 
  425             .add(placeHolderPanelLayout.createSequentialGroup()
 
  426                 .addContainerGap(268, Short.MAX_VALUE)
 
  427                 .add(jTextArea1, GroupLayout.PREFERRED_SIZE, 424, GroupLayout.PREFERRED_SIZE)
 
  428                 .addContainerGap(445, Short.MAX_VALUE))
 
  430         placeHolderPanelLayout.setVerticalGroup(placeHolderPanelLayout.createParallelGroup(GroupLayout.LEADING)
 
  431             .add(placeHolderPanelLayout.createSequentialGroup()
 
  432                 .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  433                 .add(jTextArea1, GroupLayout.PREFERRED_SIZE, 47, GroupLayout.PREFERRED_SIZE)
 
  434                 .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
  437         borderLayoutPanel.add(placeHolderPanel, BorderLayout.CENTER);
 
  439         jLabel1.setText(NbBundle.getMessage(
VisualizationPanel.class, 
"VisualizationPanel.jLabel1.text")); 
 
  441         hierarchyLayoutButton.setText(NbBundle.getMessage(
VisualizationPanel.class, 
"VisualizationPanel.hierarchyLayoutButton.text")); 
 
  442         hierarchyLayoutButton.setFocusable(
false);
 
  443         hierarchyLayoutButton.setHorizontalTextPosition(SwingConstants.CENTER);
 
  444         hierarchyLayoutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
 
  446         fastOrganicLayoutButton.setText(NbBundle.getMessage(
VisualizationPanel.class, 
"VisualizationPanel.fastOrganicLayoutButton.text")); 
 
  447         fastOrganicLayoutButton.setFocusable(
false);
 
  448         fastOrganicLayoutButton.setHorizontalTextPosition(SwingConstants.CENTER);
 
  449         fastOrganicLayoutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
 
  451         organicLayoutButton.setText(NbBundle.getMessage(
VisualizationPanel.class, 
"VisualizationPanel.organicLayoutButton.text")); 
 
  452         organicLayoutButton.setFocusable(
false);
 
  453         organicLayoutButton.setHorizontalTextPosition(SwingConstants.CENTER);
 
  454         organicLayoutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
 
  456         circleLayoutButton.setText(NbBundle.getMessage(
VisualizationPanel.class, 
"VisualizationPanel.circleLayoutButton.text")); 
 
  457         circleLayoutButton.setFocusable(
false);
 
  458         circleLayoutButton.setHorizontalTextPosition(SwingConstants.CENTER);
 
  459         circleLayoutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
 
  461         jSeparator1.setOrientation(SwingConstants.VERTICAL);
 
  463         zoomOutButton.setIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/communications/images/magnifier-zoom-out-red.png"))); 
 
  464         zoomOutButton.setText(NbBundle.getMessage(
VisualizationPanel.class, 
"VisualizationPanel.zoomOutButton.text")); 
 
  465         zoomOutButton.setToolTipText(NbBundle.getMessage(
VisualizationPanel.class, 
"VisualizationPanel.zoomOutButton.toolTipText")); 
 
  466         zoomOutButton.setFocusable(
false);
 
  467         zoomOutButton.setHorizontalTextPosition(SwingConstants.CENTER);
 
  468         zoomOutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
 
  469         zoomOutButton.addActionListener(
new ActionListener() {
 
  470             public void actionPerformed(ActionEvent evt) {
 
  471                 zoomOutButtonActionPerformed(evt);
 
  475         zoomInButton.setIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/communications/images/magnifier-zoom-in-green.png"))); 
 
  476         zoomInButton.setText(NbBundle.getMessage(
VisualizationPanel.class, 
"VisualizationPanel.zoomInButton.text")); 
 
  477         zoomInButton.setToolTipText(NbBundle.getMessage(
VisualizationPanel.class, 
"VisualizationPanel.zoomInButton.toolTipText")); 
 
  478         zoomInButton.setFocusable(
false);
 
  479         zoomInButton.setHorizontalTextPosition(SwingConstants.CENTER);
 
  480         zoomInButton.setVerticalTextPosition(SwingConstants.BOTTOM);
 
  481         zoomInButton.addActionListener(
new ActionListener() {
 
  482             public void actionPerformed(ActionEvent evt) {
 
  483                 zoomInButtonActionPerformed(evt);
 
  487         zoomActualButton.setIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/communications/images/magnifier-zoom-actual.png"))); 
 
  488         zoomActualButton.setText(NbBundle.getMessage(
VisualizationPanel.class, 
"VisualizationPanel.zoomActualButton.text")); 
 
  489         zoomActualButton.setToolTipText(NbBundle.getMessage(
VisualizationPanel.class, 
"VisualizationPanel.zoomActualButton.toolTipText")); 
 
  490         zoomActualButton.setFocusable(
false);
 
  491         zoomActualButton.setHorizontalTextPosition(SwingConstants.CENTER);
 
  492         zoomActualButton.setVerticalTextPosition(SwingConstants.BOTTOM);
 
  493         zoomActualButton.addActionListener(
new ActionListener() {
 
  494             public void actionPerformed(ActionEvent evt) {
 
  495                 zoomActualButtonActionPerformed(evt);
 
  499         fitZoomButton.setIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/communications/images/magnifier-zoom-fit.png"))); 
 
  500         fitZoomButton.setText(NbBundle.getMessage(
VisualizationPanel.class, 
"VisualizationPanel.fitZoomButton.text")); 
 
  501         fitZoomButton.setToolTipText(NbBundle.getMessage(
VisualizationPanel.class, 
"VisualizationPanel.fitZoomButton.toolTipText")); 
 
  502         fitZoomButton.setFocusable(
false);
 
  503         fitZoomButton.setHorizontalTextPosition(SwingConstants.CENTER);
 
  504         fitZoomButton.setVerticalTextPosition(SwingConstants.BOTTOM);
 
  505         fitZoomButton.addActionListener(
new ActionListener() {
 
  506             public void actionPerformed(ActionEvent evt) {
 
  507                 fitZoomButtonActionPerformed(evt);
 
  511         jLabel2.setText(NbBundle.getMessage(
VisualizationPanel.class, 
"VisualizationPanel.jLabel2.text")); 
 
  513         zoomLabel.setText(NbBundle.getMessage(
VisualizationPanel.class, 
"VisualizationPanel.zoomLabel.text")); 
 
  515         clearVizButton.setIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/communications/images/broom.png"))); 
 
  516         clearVizButton.setText(NbBundle.getMessage(
VisualizationPanel.class, 
"VisualizationPanel.clearVizButton.text_1")); 
 
  517         clearVizButton.addActionListener(
new ActionListener() {
 
  518             public void actionPerformed(ActionEvent evt) {
 
  519                 clearVizButtonActionPerformed(evt);
 
  523         jSeparator2.setOrientation(SwingConstants.VERTICAL);
 
  525         snapshotButton.setIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/report/images/image.png"))); 
 
  526         snapshotButton.setText(NbBundle.getMessage(
VisualizationPanel.class, 
"VisualizationPanel.snapshotButton.text_1")); 
 
  527         snapshotButton.addActionListener(
new ActionListener() {
 
  528             public void actionPerformed(ActionEvent evt) {
 
  529                 snapshotButtonActionPerformed(evt);
 
  533         jSeparator3.setOrientation(SwingConstants.VERTICAL);
 
  535         GroupLayout toolbarLayout = 
new GroupLayout(toolbar);
 
  536         toolbar.setLayout(toolbarLayout);
 
  537         toolbarLayout.setHorizontalGroup(toolbarLayout.createParallelGroup(GroupLayout.LEADING)
 
  538             .add(toolbarLayout.createSequentialGroup()
 
  542                 .add(jSeparator1, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE)
 
  545                 .addPreferredGap(LayoutStyle.RELATED)
 
  546                 .add(fastOrganicLayoutButton)
 
  547                 .addPreferredGap(LayoutStyle.RELATED)
 
  548                 .add(organicLayoutButton)
 
  549                 .addPreferredGap(LayoutStyle.RELATED)
 
  550                 .add(hierarchyLayoutButton)
 
  551                 .addPreferredGap(LayoutStyle.RELATED)
 
  552                 .add(circleLayoutButton)
 
  553                 .addPreferredGap(LayoutStyle.RELATED)
 
  554                 .add(jSeparator2, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE)
 
  555                 .addPreferredGap(LayoutStyle.RELATED)
 
  557                 .addPreferredGap(LayoutStyle.RELATED)
 
  559                 .addPreferredGap(LayoutStyle.RELATED)
 
  560                 .add(zoomOutButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE)
 
  561                 .addPreferredGap(LayoutStyle.RELATED)
 
  562                 .add(zoomInButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE)
 
  563                 .addPreferredGap(LayoutStyle.RELATED)
 
  564                 .add(zoomActualButton, GroupLayout.PREFERRED_SIZE, 33, GroupLayout.PREFERRED_SIZE)
 
  565                 .addPreferredGap(LayoutStyle.RELATED)
 
  566                 .add(fitZoomButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE)
 
  567                 .addPreferredGap(LayoutStyle.RELATED)
 
  568                 .add(jSeparator3, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE)
 
  569                 .addPreferredGap(LayoutStyle.RELATED)
 
  571                 .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
  573         toolbarLayout.setVerticalGroup(toolbarLayout.createParallelGroup(GroupLayout.LEADING)
 
  574             .add(toolbarLayout.createSequentialGroup()
 
  576                 .add(toolbarLayout.createParallelGroup(GroupLayout.CENTER)
 
  577                     .add(jLabel1, GroupLayout.PREFERRED_SIZE, 25, GroupLayout.PREFERRED_SIZE)
 
  578                     .add(hierarchyLayoutButton)
 
  579                     .add(fastOrganicLayoutButton)
 
  580                     .add(organicLayoutButton)
 
  581                     .add(circleLayoutButton)
 
  582                     .add(jSeparator1, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  584                     .add(zoomInButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  585                     .add(zoomActualButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  586                     .add(fitZoomButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  590                     .add(jSeparator2, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  592                     .add(jSeparator3, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
  596         borderLayoutPanel.add(toolbar, BorderLayout.PAGE_START);
 
  597         borderLayoutPanel.add(notificationsJFXPanel, BorderLayout.PAGE_END);
 
  599         splitPane.setLeftComponent(borderLayoutPanel);
 
  601         add(splitPane, BorderLayout.CENTER);
 
  609         graphComponent.zoomActual();
 
  613         graphComponent.zoomIn();
 
  617         graphComponent.zoomOut();
 
  626     @NbBundle.Messages({
"VisualizationPanel.computingLayout=Computing Layout",
 
  627         "# {0} - layout name",
 
  628         "VisualizationPanel.layoutFailWithLockedVertices.text={0} layout failed with locked vertices. Unlock some vertices or try a different layout.",
 
  629         "# {0} -  layout name",
 
  630         "VisualizationPanel.layoutFail.text={0} layout failed. Try a different layout."})
 
  632         currentLayout = layout;
 
  633         layoutButtons.forEach((layoutKey, button)
 
  634                 -> button.setFont(button.getFont().deriveFont(layoutKey == layout ? Font.BOLD : Font.PLAIN)));
 
  637         progressIndicator.
start(Bundle.VisualizationPanel_computingLayout());
 
  639         new SwingWorker<Void, Void>() {
 
  641             protected Void doInBackground() {
 
  642                 graph.getModel().beginUpdate();
 
  644                     layout.execute(graph.getDefaultParent());
 
  647                     graph.getModel().endUpdate();
 
  648                     progressIndicator.
finish();
 
  654             protected void done() {
 
  657                 } 
catch (InterruptedException | ExecutionException ex) {
 
  658                     logger.log(Level.WARNING, 
"CVT graph layout failed.", ex);
 
  659                     String message = (lockedVertexModel.isEmpty())
 
  660                             ? Bundle.VisualizationPanel_layoutFail_text(layout.
getDisplayName())
 
  661                             : Bundle.VisualizationPanel_layoutFailWithLockedVertices_text(layout.
getDisplayName());
 
  664                             -> Notifications.create().owner(notificationsJFXPanel.getScene().getWindow())
 
  674         setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
 
  675         graph.getModel().beginUpdate();
 
  676         pinnedAccountModel.clear();
 
  680         graph.getModel().endUpdate();
 
  681         setCursor(Cursor.getDefaultCursor());
 
  685          "VisualizationPanel_snapshot_report_failure=Snapshot report not created. An error occurred during creation." 
  689             handleSnapshotEvent();
 
  691             logger.log(Level.SEVERE, 
"Unable to create communications snapsot report", ex); 
 
  694                     -> Notifications.create().owner(notificationsJFXPanel.getScene().getWindow())
 
  695                             .text(Bundle.VisualizationPanel_snapshot_report_failure())
 
  697         } 
catch( TskCoreException ex) {
 
  698             logger.log(Level.WARNING, 
"Unable to add report to currenct case", ex); 
 
  703         graphComponent.zoomTo(1, 
true);
 
  704         mxPoint translate = graph.getView().getTranslate();
 
  705         if (translate == null || Double.isNaN(translate.getX()) || Double.isNaN(translate.getY())) {
 
  706             translate = 
new mxPoint();
 
  709         mxRectangle boundsForCells = graph.getCellBounds(graph.getDefaultParent(), 
true, 
true, 
true);
 
  710         if (boundsForCells == null || Double.isNaN(boundsForCells.getWidth()) || Double.isNaN(boundsForCells.getHeight())) {
 
  711             boundsForCells = 
new mxRectangle(0, 0, 1, 1);
 
  713         final mxPoint mxPoint = 
new mxPoint(translate.getX() - boundsForCells.getX(), translate.getY() - boundsForCells.getY());
 
  715         graph.cellsMoved(graph.getChildCells(graph.getDefaultParent()), mxPoint.getX(), mxPoint.getY(), 
false, 
false);
 
  717         boundsForCells = graph.getCellBounds(graph.getDefaultParent(), 
true, 
true, 
true);
 
  718         if (boundsForCells == null || Double.isNaN(boundsForCells.getWidth()) || Double.isNaN(boundsForCells.getHeight())) {
 
  719             boundsForCells = 
new mxRectangle(0, 0, 1, 1);
 
  722         final Dimension size = graphComponent.getSize();
 
  723         final double widthFactor = size.getWidth() / boundsForCells.getWidth();
 
  724         final double heightFactor = size.getHeight() / boundsForCells.getHeight();
 
  726         graphComponent.zoom((heightFactor + widthFactor) / 2.0);
 
  736         "VisualizationPanel_action_dialogs_title=Communications",
 
  737         "VisualizationPanel_module_name=Communications",
 
  738         "VisualizationPanel_action_name_text=Snapshot Report",
 
  739         "VisualizationPane_fileName_prompt=Enter name for the Communications Snapshot Report:",
 
  740         "VisualizationPane_reportName=Communications Snapshot",
 
  741         "# {0} -  default name",
 
  742         "VisualizationPane_accept_defaultName=Report name was empty. Press OK to accept default report name: {0}",
 
  743         "VisualizationPane_blank_report_title=Blank Report Name",
 
  744         "# {0} -  report name",
 
  745         "VisualizationPane_overrite_exiting=Overwrite existing report?\n{0}" 
  749         Date generationDate = 
new Date();
 
  753         final JTextField text = 
new JTextField(50);
 
  754         final JPanel panel = 
new JPanel(
new GridLayout(2, 1));
 
  755         panel.add(
new JLabel(Bundle.VisualizationPane_fileName_prompt()));
 
  758         text.setText(defaultReportName);
 
  760         int result = JOptionPane.showConfirmDialog(graphComponent, panel,
 
  761                 Bundle.VisualizationPanel_action_dialogs_title(), JOptionPane.OK_CANCEL_OPTION);
 
  763         if (result == JOptionPane.OK_OPTION) {
 
  764             String enteredReportName = text.getText();
 
  766             if(enteredReportName.trim().isEmpty()){
 
  767                 result = JOptionPane.showConfirmDialog(graphComponent, Bundle.VisualizationPane_accept_defaultName(defaultReportName), Bundle.VisualizationPane_blank_report_title(), JOptionPane.OK_CANCEL_OPTION);
 
  768                 if(result != JOptionPane.OK_OPTION) {
 
  773             String reportName = StringUtils.defaultIfBlank(enteredReportName, defaultReportName);
 
  775             if (Files.exists(reportPath)) {
 
  776                 result = JOptionPane.showConfirmDialog(graphComponent, Bundle.VisualizationPane_overrite_exiting(reportName),
 
  777                         Bundle.VisualizationPanel_action_dialogs_title(), JOptionPane.OK_CANCEL_OPTION);
 
  779                 if (result == JOptionPane.OK_OPTION) {
 
  781                     createReport(currentCase, reportName);
 
  784                 createReport(currentCase, reportName);
 
  785                 currentCase.
addReport(reportPath.toString(), Bundle.VisualizationPanel_module_name(), reportName);
 
  800         "VisualizationPane_DisplayName=Open Report",
 
  801         "VisualizationPane_NoAssociatedEditorMessage=There is no associated editor for reports of this type or the associated application failed to launch.",
 
  802         "VisualizationPane_MessageBoxTitle=Open Report Failure",
 
  803         "VisualizationPane_NoOpenInEditorSupportMessage=This platform (operating system) does not support opening a file in an editor this way.",
 
  804         "VisualizationPane_MissingReportFileMessage=The report file no longer exists.",
 
  805         "VisualizationPane_ReportFileOpenPermissionDeniedMessage=Permission to open the report file was denied.",
 
  806         "# {0} -  report path",
 
  807         "VisualizationPane_Report_Success=Report Successfully create at:\n{0}",
 
  808         "VisualizationPane_Report_OK_Button=OK",
 
  809         "VisualizationPane_Open_Report=Open Report",})
 
  813         Path reportFolderPath = Paths.get(currentCase.
getReportDirectory(), reportName, Bundle.VisualizationPane_reportName()); 
 
  814         BufferedImage image = mxCellRenderer.createBufferedImage(graph, null, graph.getView().getScale(), Color.WHITE, 
true, null);
 
  818         String message = Bundle.VisualizationPane_Report_Success(reportPath.toAbsolutePath());
 
  819         String[] buttons = {Bundle.VisualizationPane_Open_Report(), Bundle.VisualizationPane_Report_OK_Button()};
 
  821         int result = JOptionPane.showOptionDialog(graphComponent, message,
 
  822                 Bundle.VisualizationPanel_action_dialogs_title(),
 
  823                 JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE,
 
  824                 null, buttons, buttons[1]);
 
  825         if (result == JOptionPane.YES_NO_OPTION) {
 
  827                 Desktop.getDesktop().open(reportPath.toFile());
 
  828             } 
catch (IOException ex) {
 
  829                 JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
 
  830                         Bundle.VisualizationPane_NoAssociatedEditorMessage(),
 
  831                         Bundle.VisualizationPane_MessageBoxTitle(),
 
  832                         JOptionPane.ERROR_MESSAGE);
 
  833             } 
catch (UnsupportedOperationException ex) {
 
  834                 JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
 
  835                         Bundle.VisualizationPane_NoOpenInEditorSupportMessage(),
 
  836                         Bundle.VisualizationPane_MessageBoxTitle(),
 
  837                         JOptionPane.ERROR_MESSAGE);
 
  838             } 
catch (IllegalArgumentException ex) {
 
  839                 JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
 
  840                         Bundle.VisualizationPane_MissingReportFileMessage(),
 
  841                         Bundle.VisualizationPane_MessageBoxTitle(),
 
  842                         JOptionPane.ERROR_MESSAGE);
 
  843             } 
catch (SecurityException ex) {
 
  844                 JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
 
  845                         Bundle.VisualizationPane_ReportFileOpenPermissionDeniedMessage(),
 
  846                         Bundle.VisualizationPane_MessageBoxTitle(),
 
  847                         JOptionPane.ERROR_MESSAGE);
 
  883         @SuppressWarnings(
"unchecked")
 
  885         public void invoke(Object sender, mxEventObject evt) {
 
  886             Object[] selectionCells = graph.getSelectionCells();
 
  887             Node rootNode = Node.EMPTY;
 
  888             Node[] selectedNodes = 
new Node[0];
 
  889             if (selectionCells.length > 0) {
 
  890                 mxICell[] selectedCells = Arrays.asList(selectionCells).toArray(
new mxCell[selectionCells.length]);
 
  891                 HashSet<Content> relationshipSources = 
new HashSet<>();
 
  892                 HashSet<AccountDeviceInstanceKey> adis = 
new HashSet<>();
 
  893                 for (mxICell cell : selectedCells) {
 
  895                         mxICell source = (mxICell) graph.getModel().getTerminal(cell, 
true);
 
  896                         AccountDeviceInstanceKey account1 = (AccountDeviceInstanceKey) source.getValue();
 
  897                         mxICell target = (mxICell) graph.getModel().getTerminal(cell, 
false);
 
  898                         AccountDeviceInstanceKey account2 = (AccountDeviceInstanceKey) target.getValue();
 
  900                             final List<Content> relationshipSources1 = commsManager.getRelationshipSources(
 
  901                                     account1.getAccountDeviceInstance(),
 
  902                                     account2.getAccountDeviceInstance(),
 
  904                             relationshipSources.addAll(relationshipSources1);
 
  905                         } 
catch (TskCoreException tskCoreException) {
 
  906                             logger.log(Level.SEVERE, 
" Error getting relationsips....", tskCoreException);
 
  908                     } 
else if (cell.isVertex()) {
 
  909                         adis.add((AccountDeviceInstanceKey) cell.getValue());
 
  913                 rootNode = SelectionNode.createFromAccountsAndRelationships(relationshipSources, adis, currentFilter, commsManager);
 
  914                 selectedNodes = 
new Node[]{rootNode};
 
  916             vizEM.setRootContext(rootNode);
 
  918                 vizEM.setSelectedNodes(selectedNodes);
 
  919             } 
catch (PropertyVetoException ex) {
 
  920                 logger.log(Level.SEVERE, 
"Selection vetoed.", ex);
 
  930         String getDisplayName();
 
  944             return super.isVertexIgnored(vertex)
 
  945                    || lockedVertexModel.isVertexLocked((mxCell) vertex);
 
  950             if (isVertexIgnored(vertex)) {
 
  951                 return getVertexBounds(vertex);
 
  953                 return super.setVertexLocation(vertex, x, y);
 
  959             return "Fast Organic";
 
  975             return super.isVertexIgnored(vertex)
 
  976                    || lockedVertexModel.isVertexLocked((mxCell) vertex);
 
  981             if (isVertexIgnored(vertex)) {
 
  982                 return getVertexBounds(vertex);
 
  984                 return super.setVertexLocation(vertex, x, y);
 
 1001             setResetEdges(
true);
 
 1006             return super.isVertexIgnored(vertex)
 
 1007                    || lockedVertexModel.isVertexLocked((mxCell) vertex);
 
 1012             if (isVertexIgnored(vertex)) {
 
 1013                 return getVertexBounds(vertex);
 
 1015                 return super.setVertexLocation(vertex, x, y);
 
 1036             return super.isVertexIgnored(vertex)
 
 1037                    || lockedVertexModel.isVertexLocked((mxCell) vertex);
 
 1042             if (isVertexIgnored(vertex)) {
 
 1043                 return getVertexBounds(vertex);
 
 1045                 return super.setVertexLocation(vertex, x, y);
 
 1051             return "Hierarchical";
 
 1065             this.cancellable = cancellable;
 
 1066             this.progress = progress;
 
 1072             cancellable.cancel(
true);
 
 1090             super.mouseWheelMoved(event);
 
 1091             if (event.getPreciseWheelRotation() < 0) {
 
 1092                 graphComponent.zoomIn();
 
 1093             } 
else if (event.getPreciseWheelRotation() > 0) {
 
 1094                 graphComponent.zoomOut();
 
 1105             super.mouseClicked(event);
 
 1106             if (SwingUtilities.isRightMouseButton(event)) {
 
 1107                 final mxCell cellAt = (mxCell) graphComponent.getCellAt(event.getX(), 
event.getY());
 
 1108                 if (cellAt != null && cellAt.isVertex()) {
 
 1109                     final JPopupMenu jPopupMenu = 
new JPopupMenu();
 
 1110                     final AccountDeviceInstanceKey adiKey = (AccountDeviceInstanceKey) cellAt.getValue();
 
 1112                     Set<mxCell> selectedVertices
 
 1113                             = Stream.of(graph.getSelectionModel().getCells())
 
 1114                                     .map(mxCell.class::cast)
 
 1115                                     .filter(mxCell::isVertex)
 
 1116                                     .collect(Collectors.toSet());
 
 1118                     if (lockedVertexModel.isVertexLocked(cellAt)) {
 
 1119                         jPopupMenu.add(
new JMenuItem(
new UnlockAction(selectedVertices)));
 
 1121                         jPopupMenu.add(
new JMenuItem(
new LockAction(selectedVertices)));
 
 1123                     if (pinnedAccountModel.isAccountPinned(adiKey)) {
 
 1124                         jPopupMenu.add(UnpinAccountsAction.getInstance().getPopupPresenter());
 
 1126                         jPopupMenu.add(PinAccountsAction.getInstance().getPopupPresenter());
 
 1127                         jPopupMenu.add(ResetAndPinAccountsAction.getInstance().getPopupPresenter());
 
 1129                     jPopupMenu.show(graphComponent.getGraphControl(), 
event.getX(), 
event.getY());
 
 1138     @NbBundle.Messages({
 
 1139         "VisualizationPanel.unlockAction.singularText=Unlock Selected Account",
 
 1140         "VisualizationPanel.unlockAction.pluralText=Unlock Selected Accounts",})
 
 1146             super(selectedVertices.size() > 1 ? Bundle.VisualizationPanel_unlockAction_pluralText() : Bundle.VisualizationPanel_unlockAction_singularText(),
 
 1148             this.selectedVertices = selectedVertices;
 
 1154             lockedVertexModel.unlock(selectedVertices);
 
 1161     @NbBundle.Messages({
 
 1162         "VisualizationPanel.lockAction.singularText=Lock Selected Account",
 
 1163         "VisualizationPanel.lockAction.pluralText=Lock Selected Accounts"})
 
 1169             super(selectedVertices.size() > 1 ? Bundle.VisualizationPanel_lockAction_pluralText() : Bundle.VisualizationPanel_lockAction_singularText(),
 
 1171             this.selectedVertices = selectedVertices;
 
 1176             lockedVertexModel.lock(selectedVertices);
 
void zoomOutButtonActionPerformed(ActionEvent evt)
final Set< mxCell > selectedVertices
boolean isVertexIgnored(Object vertex)
void invoke(Object sender, mxEventObject evt)
JFXPanel notificationsJFXPanel
void mouseClicked(final MouseEvent event)
void createReport(Case currentCase, String reportName)
CommunicationsManager commsManager
boolean isVertexIgnored(Object vertex)
void applyLayout(NamedGraphLayout layout)
void actionPerformed(final ActionEvent event)
final mxRubberband rubberband
static boolean deleteFileDir(File path)
String getReportDirectory()
JToolBar.Separator jSeparator3
void addReport(String localPath, String srcModuleName, String reportName)
JToolBar.Separator jSeparator2
ModalDialogProgressIndicator progress
mxRectangle setVertexLocation(Object vertex, double x, double y)
JButton hierarchyLayoutButton
synchronized void start(String message, int totalWorkUnits)
JButton organicLayoutButton
final ProxyLookup proxyLookup
synchronized void setCancelling(String cancellingMessage)
final CommunicationsGraph graph
void actionPerformed(final ActionEvent event)
boolean isVertexIgnored(Object vertex)
CommunicationsFilter currentFilter
void fitZoomButtonActionPerformed(ActionEvent evt)
SleuthkitCase getSleuthkitCase()
void mouseWheelMoved(final MouseWheelEvent event)
JButton circleLayoutButton
JToolBar.Separator jSeparator1
void handleSnapshotEvent()
static String escapeFileName(String fileName)
mxRectangle setVertexLocation(Object vertex, double x, double y)
boolean isVertexIgnored(Object vertex)
mxRectangle setVertexLocation(Object vertex, double x, double y)
final mxGraphComponent graphComponent
synchronized static Logger getLogger(String name)
static Case getCurrentCaseThrows()
void actionPerformed(ActionEvent event)
static void addEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
mxRectangle setVertexLocation(Object vertex, double x, double y)
JButton fastOrganicLayoutButton
void zoomInButtonActionPerformed(ActionEvent evt)
final Set< mxCell > selectedVertices
void zoomActualButtonActionPerformed(ActionEvent evt)
void clearVizButtonActionPerformed(ActionEvent evt)
void snapshotButtonActionPerformed(ActionEvent evt)
synchronized void finish()