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.Desktop;
45 import java.awt.Dimension;
47 import java.awt.Frame;
48 import java.awt.Graphics;
49 import java.awt.GridLayout;
50 import java.awt.event.ActionEvent;
51 import java.awt.event.ActionListener;
52 import java.awt.event.MouseAdapter;
53 import java.awt.event.MouseEvent;
54 import java.awt.event.MouseWheelEvent;
55 import java.awt.image.BufferedImage;
56 import java.beans.PropertyChangeEvent;
57 import java.io.IOException;
58 import java.nio.file.Files;
59 import java.nio.file.Path;
60 import java.nio.file.Paths;
61 import java.text.DecimalFormat;
62 import java.text.SimpleDateFormat;
63 import java.util.Arrays;
64 import java.util.Date;
65 import java.util.EnumSet;
66 import java.util.HashMap;
67 import java.util.HashSet;
70 import java.util.concurrent.ExecutionException;
71 import java.util.concurrent.Future;
72 import java.util.function.BiConsumer;
73 import java.util.logging.Level;
74 import java.util.stream.Collectors;
75 import java.util.stream.Stream;
76 import javafx.application.Platform;
77 import javafx.embed.swing.JFXPanel;
78 import javafx.scene.Scene;
79 import javafx.scene.layout.Pane;
80 import javax.swing.AbstractAction;
81 import javax.swing.ImageIcon;
82 import javax.swing.JButton;
83 import javax.swing.JLabel;
84 import javax.swing.JMenuItem;
85 import javax.swing.JOptionPane;
86 import javax.swing.JPanel;
87 import javax.swing.JPopupMenu;
88 import javax.swing.JTextArea;
89 import javax.swing.JTextField;
90 import javax.swing.JToolBar;
91 import javax.swing.SwingConstants;
92 import javax.swing.SwingUtilities;
93 import javax.swing.SwingWorker;
94 import org.apache.commons.lang3.StringUtils;
95 import org.controlsfx.control.Notifications;
96 import org.jdesktop.layout.GroupLayout;
97 import org.openide.util.NbBundle;
98 import org.openide.windows.WindowManager;
123 @SuppressWarnings(
"PMD.SingularField")
126 private static final long serialVersionUID = 1L;
128 private static final String BASE_IMAGE_PATH =
"/org/sleuthkit/autopsy/communications/images";
129 static final private ImageIcon unlockIcon
131 static final private ImageIcon lockIcon
134 @NbBundle.Messages(
"VisualizationPanel.cancelButton.text=Cancel")
135 private static final String CANCEL = Bundle.VisualizationPanel_cancelButton_text();
143 private final CommunicationsGraph
graph;
145 private final mxUndoManager undoManager =
new mxUndoManager();
149 private SwingWorker<?, ?> worker;
150 private final PinnedAccountModel pinnedAccountModel = new PinnedAccountModel();
151 private final LockedVertexModel lockedVertexModel = new LockedVertexModel();
154 private NamedGraphLayout currentLayout;
158 private final StateManager stateManager;
160 @NbBundle.Messages("VisalizationPanel.paintingError=Problem painting visualization.")
162 this.relationshipBrowser = relationshipBrowser;
165 notificationsJFXPanel.setScene(
new Scene(
new Pane()));
167 graph =
new CommunicationsGraph(pinnedAccountModel, lockedVertexModel);
175 graphComponent =
new mxGraphComponent(graph) {
177 protected mxGraphComponent.mxGraphControl createGraphControl() {
179 return new mxGraphControl() {
182 public void paint(Graphics graphics) {
184 super.paint(graphics);
185 }
catch (NullPointerException ex) {
191 logger.log(Level.WARNING,
"There was a NPE while painting the VisualizationPanel", ex);
198 graphComponent.setAutoExtend(
true);
199 graphComponent.setAutoScroll(
true);
200 graphComponent.setAutoscrolls(
true);
201 graphComponent.setConnectable(
false);
202 graphComponent.setDragEnabled(
false);
203 graphComponent.setKeepSelectionVisibleOnZoom(
true);
204 graphComponent.setOpaque(
true);
205 graphComponent.setToolTips(
true);
206 graphComponent.setBackground(Color.WHITE);
207 borderLayoutPanel.add(graphComponent, BorderLayout.CENTER);
210 rubberband =
new mxRubberband(graphComponent);
212 lockedVertexModel.registerhandler(
this);
214 final mxEventSource.mxIEventListener scaleListener = (Object sender, mxEventObject evt)
215 -> zoomPercentLabel.setText(DecimalFormat.getPercentInstance().format(graph.getView().getScale()));
216 graph.getView().addListener(mxEvent.SCALE, scaleListener);
217 graph.getView().addListener(mxEvent.SCALE_AND_TRANSLATE, scaleListener);
220 graphComponent.getGraphControl().addMouseWheelListener(graphMouseListener);
221 graphComponent.getGraphControl().addMouseListener(graphMouseListener);
225 final mxEventSource.mxIEventListener undoListener = (Object sender, mxEventObject evt)
226 -> undoManager.undoableEditHappened((mxUndoableEdit) evt.getProperty(
"edit"));
228 graph.getModel().addListener(mxEvent.UNDO, undoListener);
229 graph.getView().addListener(mxEvent.UNDO, undoListener);
234 BiConsumer<JButton, NamedGraphLayout> configure = (layoutButton, layout) -> {
235 layoutButtons.put(layout, layoutButton);
236 layoutButton.addActionListener(event -> applyLayout(layout));
239 configure.accept(fastOrganicLayoutButton, fastOrganicLayout);
241 applyLayout(fastOrganicLayout);
243 stateManager =
new StateManager(pinnedAccountModel);
245 setStateButtonsEnabled();
251 void handle(LockedVertexModel.VertexLockEvent event) {
252 final Set<mxCell> vertices =
event.getVertices();
253 mxGraphView view = graph.getView();
254 vertices.forEach(vertex -> {
255 final mxCellState state = view.getState(vertex,
true);
256 view.updateLabel(state);
257 view.updateLabelBounds(state);
258 view.updateBoundingBox(state);
259 graphComponent.redraw(state);
264 void handle(
final CVTEvents.UnpinAccountsEvent pinEvent) {
265 graph.getModel().beginUpdate();
266 pinnedAccountModel.unpinAccount(pinEvent.getAccountDeviceInstances());
270 graph.getModel().endUpdate();
272 setStateButtonsEnabled();
276 void handle(
final CVTEvents.PinAccountsEvent pinEvent) {
277 graph.getModel().beginUpdate();
278 if (pinEvent.isReplace()) {
281 pinnedAccountModel.pinAccount(pinEvent.getAccountDeviceInstances());
284 graph.getModel().endUpdate();
286 setStateButtonsEnabled();
290 void handle(
final CVTEvents.FilterChangeEvent filterChangeEvent) {
291 graph.getModel().beginUpdate();
293 currentFilter = filterChangeEvent.getNewFilter();
296 graph.getModel().endUpdate();
298 setStateButtonsEnabled();
301 @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
302 private
void rebuildGraph() {
303 if (pinnedAccountModel.isEmpty()) {
304 borderLayoutPanel.remove(graphComponent);
305 borderLayoutPanel.add(placeHolderPanel, BorderLayout.CENTER);
308 borderLayoutPanel.remove(placeHolderPanel);
309 borderLayoutPanel.add(graphComponent, BorderLayout.CENTER);
310 if (worker != null) {
316 worker = graph.rebuild(progress, commsManager, currentFilter);
317 cancelationListener.configure(worker, progress);
318 worker.addPropertyChangeListener((
final PropertyChangeEvent evt) -> {
319 if (worker.isDone()) {
320 if (worker.isCancelled()) {
324 applyLayout(currentLayout);
335 windowAncestor = (Frame) SwingUtilities.getAncestorOfClass(Frame.class,
this);
339 }
catch (TskCoreException ex) {
340 logger.log(Level.SEVERE,
"Error getting CommunicationsManager for the current case.", ex);
342 logger.log(Level.SEVERE,
"Can't get CommunicationsManager when there is no case open.", ex);
346 graph.getModel().beginUpdate();
350 graph.getModel().endUpdate();
352 if (evt.getNewValue() == null) {
355 Case currentCase = (
Case) evt.getNewValue();
358 }
catch (TskCoreException ex) {
359 logger.log(Level.SEVERE,
"Error getting CommunicationsManager for the current case.", ex);
370 @SuppressWarnings(
"unchecked")
372 private
void initComponents() {
374 borderLayoutPanel =
new JPanel();
375 placeHolderPanel =
new JPanel();
376 jTextArea1 =
new JTextArea();
377 notificationsJFXPanel =
new JFXPanel();
378 toolbar =
new JToolBar();
379 backButton =
new JButton();
380 forwardButton =
new JButton();
381 jSeparator3 =
new JToolBar.Separator();
382 clearVizButton =
new JButton();
383 fastOrganicLayoutButton =
new JButton();
384 jSeparator2 =
new JToolBar.Separator();
385 zoomLabel =
new JLabel();
386 zoomPercentLabel =
new JLabel();
387 zoomOutButton =
new JButton();
388 fitZoomButton =
new JButton();
389 zoomActualButton =
new JButton();
390 zoomInButton =
new JButton();
391 jSeparator1 =
new JToolBar.Separator();
392 snapshotButton =
new JButton();
394 setLayout(
new BorderLayout());
396 borderLayoutPanel.setLayout(
new BorderLayout());
398 jTextArea1.setBackground(
new Color(240, 240, 240));
399 jTextArea1.setColumns(20);
400 jTextArea1.setLineWrap(
true);
401 jTextArea1.setRows(5);
402 jTextArea1.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.jTextArea1.text"));
404 GroupLayout placeHolderPanelLayout =
new GroupLayout(placeHolderPanel);
405 placeHolderPanel.setLayout(placeHolderPanelLayout);
406 placeHolderPanelLayout.setHorizontalGroup(placeHolderPanelLayout.createParallelGroup(GroupLayout.LEADING)
407 .add(placeHolderPanelLayout.createSequentialGroup()
408 .addContainerGap(316, Short.MAX_VALUE)
409 .add(jTextArea1, GroupLayout.PREFERRED_SIZE, 424, GroupLayout.PREFERRED_SIZE)
410 .addContainerGap(481, Short.MAX_VALUE))
412 placeHolderPanelLayout.setVerticalGroup(placeHolderPanelLayout.createParallelGroup(GroupLayout.LEADING)
413 .add(placeHolderPanelLayout.createSequentialGroup()
414 .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
415 .add(jTextArea1, GroupLayout.PREFERRED_SIZE, 47, GroupLayout.PREFERRED_SIZE)
416 .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
419 borderLayoutPanel.add(placeHolderPanel, BorderLayout.CENTER);
420 borderLayoutPanel.add(notificationsJFXPanel, BorderLayout.PAGE_END);
422 add(borderLayoutPanel, BorderLayout.CENTER);
424 toolbar.setRollover(
true);
426 backButton.setIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/images/resultset_previous.png")));
427 backButton.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.backButton.text_1"));
428 backButton.setToolTipText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.backButton.toolTipText"));
429 backButton.setFocusable(
false);
430 backButton.setHorizontalTextPosition(SwingConstants.CENTER);
431 backButton.setVerticalTextPosition(SwingConstants.BOTTOM);
432 backButton.addActionListener(
new ActionListener() {
433 public void actionPerformed(ActionEvent evt) {
434 backButtonActionPerformed(evt);
437 toolbar.add(backButton);
439 forwardButton.setIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/images/resultset_next.png")));
440 forwardButton.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.forwardButton.text"));
441 forwardButton.setToolTipText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.forwardButton.toolTipText"));
442 forwardButton.setFocusable(
false);
443 forwardButton.setHorizontalTextPosition(SwingConstants.CENTER);
444 forwardButton.setVerticalTextPosition(SwingConstants.BOTTOM);
445 forwardButton.addActionListener(
new ActionListener() {
446 public void actionPerformed(ActionEvent evt) {
447 forwardButtonActionPerformed(evt);
450 toolbar.add(forwardButton);
451 toolbar.add(jSeparator3);
453 clearVizButton.setIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/communications/images/broom.png")));
454 clearVizButton.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.clearVizButton.text_1"));
455 clearVizButton.setToolTipText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.clearVizButton.toolTipText"));
456 clearVizButton.setActionCommand(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.clearVizButton.actionCommand"));
457 clearVizButton.setFocusable(
false);
458 clearVizButton.setHorizontalTextPosition(SwingConstants.CENTER);
459 clearVizButton.setVerticalTextPosition(SwingConstants.BOTTOM);
460 clearVizButton.addActionListener(
new ActionListener() {
461 public void actionPerformed(ActionEvent evt) {
462 clearVizButtonActionPerformed(evt);
465 toolbar.add(clearVizButton);
467 fastOrganicLayoutButton.setIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/communications/images/arrow-circle-double-135.png")));
468 fastOrganicLayoutButton.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.fastOrganicLayoutButton.text"));
469 fastOrganicLayoutButton.setToolTipText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.fastOrganicLayoutButton.toolTipText"));
470 fastOrganicLayoutButton.setFocusable(
false);
471 fastOrganicLayoutButton.setHorizontalTextPosition(SwingConstants.CENTER);
472 fastOrganicLayoutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
473 fastOrganicLayoutButton.addActionListener(
new ActionListener() {
474 public void actionPerformed(ActionEvent evt) {
475 fastOrganicLayoutButtonActionPerformed(evt);
478 toolbar.add(fastOrganicLayoutButton);
479 toolbar.add(jSeparator2);
481 zoomLabel.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.zoomLabel.text"));
482 toolbar.add(zoomLabel);
484 zoomPercentLabel.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.zoomPercentLabel.text"));
485 toolbar.add(zoomPercentLabel);
487 zoomOutButton.setIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/communications/images/magnifier-zoom-out-red.png")));
488 zoomOutButton.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.zoomOutButton.text"));
489 zoomOutButton.setToolTipText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.zoomOutButton.toolTipText"));
490 zoomOutButton.setFocusable(
false);
491 zoomOutButton.setHorizontalTextPosition(SwingConstants.CENTER);
492 zoomOutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
493 zoomOutButton.addActionListener(
new ActionListener() {
494 public void actionPerformed(ActionEvent evt) {
495 zoomOutButtonActionPerformed(evt);
498 toolbar.add(zoomOutButton);
500 fitZoomButton.setIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/communications/images/magnifier-zoom-fit.png")));
501 fitZoomButton.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.fitZoomButton.text"));
502 fitZoomButton.setToolTipText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.fitZoomButton.toolTipText"));
503 fitZoomButton.setFocusable(
false);
504 fitZoomButton.setHorizontalTextPosition(SwingConstants.CENTER);
505 fitZoomButton.setVerticalTextPosition(SwingConstants.BOTTOM);
506 fitZoomButton.addActionListener(
new ActionListener() {
507 public void actionPerformed(ActionEvent evt) {
508 fitZoomButtonActionPerformed(evt);
511 toolbar.add(fitZoomButton);
513 zoomActualButton.setIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/communications/images/magnifier-zoom-actual.png")));
514 zoomActualButton.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.zoomActualButton.text"));
515 zoomActualButton.setToolTipText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.zoomActualButton.toolTipText"));
516 zoomActualButton.setFocusable(
false);
517 zoomActualButton.setHorizontalTextPosition(SwingConstants.CENTER);
518 zoomActualButton.setVerticalTextPosition(SwingConstants.BOTTOM);
519 zoomActualButton.addActionListener(
new ActionListener() {
520 public void actionPerformed(ActionEvent evt) {
521 zoomActualButtonActionPerformed(evt);
524 toolbar.add(zoomActualButton);
526 zoomInButton.setIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/communications/images/magnifier-zoom-in-green.png")));
527 zoomInButton.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.zoomInButton.text"));
528 zoomInButton.setToolTipText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.zoomInButton.toolTipText"));
529 zoomInButton.setFocusable(
false);
530 zoomInButton.setHorizontalTextPosition(SwingConstants.CENTER);
531 zoomInButton.setVerticalTextPosition(SwingConstants.BOTTOM);
532 zoomInButton.addActionListener(
new ActionListener() {
533 public void actionPerformed(ActionEvent evt) {
534 zoomInButtonActionPerformed(evt);
537 toolbar.add(zoomInButton);
538 toolbar.add(jSeparator1);
540 snapshotButton.setIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/report/images/image.png")));
541 snapshotButton.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.snapshotButton.text_1"));
542 snapshotButton.setToolTipText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.snapshotButton.toolTipText"));
543 snapshotButton.setFocusable(
false);
544 snapshotButton.setHorizontalTextPosition(SwingConstants.CENTER);
545 snapshotButton.setVerticalTextPosition(SwingConstants.BOTTOM);
546 snapshotButton.addActionListener(
new ActionListener() {
547 public void actionPerformed(ActionEvent evt) {
548 snapshotButtonActionPerformed(evt);
551 toolbar.add(snapshotButton);
553 add(toolbar, BorderLayout.NORTH);
561 graphComponent.zoomActual();
562 CVTEvents.getCVTEventBus().post(
new CVTEvents.ScaleChangeEvent(graph.getView().getScale()));
566 graphComponent.zoomIn();
567 CVTEvents.getCVTEventBus().post(
new CVTEvents.ScaleChangeEvent(graph.getView().getScale()));
571 graphComponent.zoomOut();
572 CVTEvents.getCVTEventBus().post(
new CVTEvents.ScaleChangeEvent(graph.getView().getScale()));
581 @NbBundle.Messages({
"VisualizationPanel.computingLayout=Computing Layout",
582 "# {0} - layout name",
583 "VisualizationPanel.layoutFailWithLockedVertices.text={0} layout failed with locked vertices. Unlock some vertices or try a different layout.",
584 "# {0} - layout name",
585 "VisualizationPanel.layoutFail.text={0} layout failed. Try a different layout."})
587 currentLayout = layout;
588 layoutButtons.forEach((layoutKey, button)
589 -> button.setFont(button.getFont().deriveFont(layoutKey == layout ? Font.BOLD : Font.PLAIN)));
592 progressIndicator.
start(Bundle.VisualizationPanel_computingLayout());
594 new SwingWorker<Void, Void>() {
596 protected Void doInBackground() {
597 graph.getModel().beginUpdate();
599 layout.execute(graph.getDefaultParent());
602 graph.getModel().endUpdate();
603 progressIndicator.
finish();
609 protected void done() {
612 }
catch (InterruptedException | ExecutionException ex) {
613 logger.log(Level.WARNING,
"CVT graph layout failed.", ex);
620 CVTEvents.getCVTEventBus().post(
new CVTEvents.UnpinAccountsEvent(pinnedAccountModel.getPinnedAccounts()));
624 handleStateChange(stateManager.advance());
628 handleStateChange(stateManager.retreat());
637 if(newState == null) {
642 if(newState.isZoomChange()) {
643 graph.getView().setScale(newState.getZoomValue());
648 CVTEvents.getCVTEventBus().post(
new CVTEvents.StateChangeEvent(newState));
649 setStateButtonsEnabled();
651 graph.getModel().beginUpdate();
654 if(newState.getPinnedList() != null) {
655 pinnedAccountModel.pinAccount(newState.getPinnedList());
657 pinnedAccountModel.clear();
660 currentFilter = newState.getCommunicationsFilter();
664 graph.getModel().endUpdate();
671 backButton.setEnabled(stateManager.canRetreat());
672 forwardButton.setEnabled(stateManager.canAdvance());
676 "VisualizationPanel_snapshot_report_failure=Snapshot report not created. An error occurred during creation."
680 handleSnapshotEvent();
682 logger.log(Level.SEVERE,
"Unable to create communications snapsot report", ex);
685 -> Notifications.create().owner(notificationsJFXPanel.getScene().getWindow())
686 .text(Bundle.VisualizationPanel_snapshot_report_failure())
688 }
catch( TskCoreException ex) {
689 logger.log(Level.WARNING,
"Unable to add report to currenct case", ex);
698 graphComponent.zoomTo(1,
true);
699 mxPoint translate = graph.getView().getTranslate();
700 if (translate == null || Double.isNaN(translate.getX()) || Double.isNaN(translate.getY())) {
701 translate =
new mxPoint();
704 mxRectangle boundsForCells = graph.getCellBounds(graph.getDefaultParent(),
true,
true,
true);
705 if (boundsForCells == null || Double.isNaN(boundsForCells.getWidth()) || Double.isNaN(boundsForCells.getHeight())) {
706 boundsForCells =
new mxRectangle(0, 0, 1, 1);
708 final mxPoint mxPoint =
new mxPoint(translate.getX() - boundsForCells.getX(), translate.getY() - boundsForCells.getY());
710 graph.cellsMoved(graph.getChildCells(graph.getDefaultParent()), mxPoint.getX(), mxPoint.getY(),
false,
false);
712 boundsForCells = graph.getCellBounds(graph.getDefaultParent(),
true,
true,
true);
713 if (boundsForCells == null || Double.isNaN(boundsForCells.getWidth()) || Double.isNaN(boundsForCells.getHeight())) {
714 boundsForCells =
new mxRectangle(0, 0, 1, 1);
717 final Dimension size = graphComponent.getSize();
718 final double widthFactor = size.getWidth() / boundsForCells.getWidth();
719 final double heightFactor = size.getHeight() / boundsForCells.getHeight();
721 graphComponent.zoom((heightFactor + widthFactor) / 2.0);
731 "VisualizationPanel_action_dialogs_title=Communications",
732 "VisualizationPanel_module_name=Communications",
733 "VisualizationPanel_action_name_text=Snapshot Report",
734 "VisualizationPane_fileName_prompt=Enter name for the Communications Snapshot Report:",
735 "VisualizationPane_reportName=Communications Snapshot",
736 "# {0} - default name",
737 "VisualizationPane_accept_defaultName=Report name was empty. Press OK to accept default report name: {0}",
738 "VisualizationPane_blank_report_title=Blank Report Name",
739 "# {0} - report name",
740 "VisualizationPane_overrite_exiting=Overwrite existing report?\n{0}"
744 Date generationDate =
new Date();
748 final JTextField text =
new JTextField(50);
749 final JPanel panel =
new JPanel(
new GridLayout(2, 1));
750 panel.add(
new JLabel(Bundle.VisualizationPane_fileName_prompt()));
753 text.setText(defaultReportName);
755 int result = JOptionPane.showConfirmDialog(graphComponent, panel,
756 Bundle.VisualizationPanel_action_dialogs_title(), JOptionPane.OK_CANCEL_OPTION);
758 if (result == JOptionPane.OK_OPTION) {
759 String enteredReportName = text.getText();
761 if(enteredReportName.trim().isEmpty()){
762 result = JOptionPane.showConfirmDialog(graphComponent, Bundle.VisualizationPane_accept_defaultName(defaultReportName), Bundle.VisualizationPane_blank_report_title(), JOptionPane.OK_CANCEL_OPTION);
763 if(result != JOptionPane.OK_OPTION) {
768 String reportName = StringUtils.defaultIfBlank(enteredReportName, defaultReportName);
770 if (Files.exists(reportPath)) {
771 result = JOptionPane.showConfirmDialog(graphComponent, Bundle.VisualizationPane_overrite_exiting(reportName),
772 Bundle.VisualizationPanel_action_dialogs_title(), JOptionPane.OK_CANCEL_OPTION);
774 if (result == JOptionPane.OK_OPTION) {
776 createReport(currentCase, reportName);
779 createReport(currentCase, reportName);
780 currentCase.
addReport(reportPath.toString(), Bundle.VisualizationPanel_module_name(), reportName);
795 "VisualizationPane_DisplayName=Open Report",
796 "VisualizationPane_NoAssociatedEditorMessage=There is no associated editor for reports of this type or the associated application failed to launch.",
797 "VisualizationPane_MessageBoxTitle=Open Report Failure",
798 "VisualizationPane_NoOpenInEditorSupportMessage=This platform (operating system) does not support opening a file in an editor this way.",
799 "VisualizationPane_MissingReportFileMessage=The report file no longer exists.",
800 "VisualizationPane_ReportFileOpenPermissionDeniedMessage=Permission to open the report file was denied.",
801 "# {0} - report path",
802 "VisualizationPane_Report_Success=Report Successfully create at:\n{0}",
803 "VisualizationPane_Report_OK_Button=OK",
804 "VisualizationPane_Open_Report=Open Report",})
808 Path reportFolderPath = Paths.get(currentCase.
getReportDirectory(), reportName, Bundle.VisualizationPane_reportName());
809 BufferedImage image = mxCellRenderer.createBufferedImage(graph, null, graph.getView().getScale(), Color.WHITE,
true, null);
813 String message = Bundle.VisualizationPane_Report_Success(reportPath.toAbsolutePath());
814 String[] buttons = {Bundle.VisualizationPane_Open_Report(), Bundle.VisualizationPane_Report_OK_Button()};
816 int result = JOptionPane.showOptionDialog(graphComponent, message,
817 Bundle.VisualizationPanel_action_dialogs_title(),
818 JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE,
819 null, buttons, buttons[1]);
820 if (result == JOptionPane.YES_NO_OPTION) {
822 Desktop.getDesktop().open(reportPath.toFile());
823 }
catch (IOException ex) {
824 JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
825 Bundle.VisualizationPane_NoAssociatedEditorMessage(),
826 Bundle.VisualizationPane_MessageBoxTitle(),
827 JOptionPane.ERROR_MESSAGE);
828 }
catch (UnsupportedOperationException ex) {
829 JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
830 Bundle.VisualizationPane_NoOpenInEditorSupportMessage(),
831 Bundle.VisualizationPane_MessageBoxTitle(),
832 JOptionPane.ERROR_MESSAGE);
833 }
catch (IllegalArgumentException ex) {
834 JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
835 Bundle.VisualizationPane_MissingReportFileMessage(),
836 Bundle.VisualizationPane_MessageBoxTitle(),
837 JOptionPane.ERROR_MESSAGE);
838 }
catch (SecurityException ex) {
839 JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
840 Bundle.VisualizationPane_ReportFileOpenPermissionDeniedMessage(),
841 Bundle.VisualizationPane_MessageBoxTitle(),
842 JOptionPane.ERROR_MESSAGE);
875 @SuppressWarnings(
"unchecked")
877 public void invoke(Object sender, mxEventObject evt) {
878 Object[] selectionCells = graph.getSelectionCells();
879 if (selectionCells.length > 0) {
880 mxICell[] selectedCells = Arrays.asList(selectionCells).toArray(
new mxCell[selectionCells.length]);
881 HashSet<AccountDeviceInstance> selectedNodes =
new HashSet<>();
883 for (mxICell cell : selectedCells) {
885 mxICell source = (mxICell) graph.getModel().getTerminal(cell,
true);
886 mxICell target = (mxICell) graph.getModel().getTerminal(cell,
false);
888 selectedEdges.add(
new SelectionInfo.
GraphEdge(((AccountDeviceInstanceKey) source.getValue()).getAccountDeviceInstance(),
889 ((AccountDeviceInstanceKey) target.getValue()).getAccountDeviceInstance()));
891 }
else if (cell.isVertex()) {
892 selectedNodes.add(((AccountDeviceInstanceKey) cell.getValue()).getAccountDeviceInstance());
896 relationshipBrowser.setSelectionInfo(
new SelectionInfo(selectedNodes, selectedEdges, currentFilter));
898 relationshipBrowser.setSelectionInfo(
new SelectionInfo(
new HashSet<>(),
new HashSet<>(), currentFilter));
908 String getDisplayName();
922 return super.isVertexIgnored(vertex)
923 || lockedVertexModel.isVertexLocked((mxCell) vertex);
928 if (isVertexIgnored(vertex)) {
929 return getVertexBounds(vertex);
931 return super.setVertexLocation(vertex, x, y);
937 return "Fast Organic";
953 return super.isVertexIgnored(vertex)
954 || lockedVertexModel.isVertexLocked((mxCell) vertex);
959 if (isVertexIgnored(vertex)) {
960 return getVertexBounds(vertex);
962 return super.setVertexLocation(vertex, x, y);
984 return super.isVertexIgnored(vertex)
985 || lockedVertexModel.isVertexLocked((mxCell) vertex);
990 if (isVertexIgnored(vertex)) {
991 return getVertexBounds(vertex);
993 return super.setVertexLocation(vertex, x, y);
1014 return super.isVertexIgnored(vertex)
1015 || lockedVertexModel.isVertexLocked((mxCell) vertex);
1020 if (isVertexIgnored(vertex)) {
1021 return getVertexBounds(vertex);
1023 return super.setVertexLocation(vertex, x, y);
1029 return "Hierarchical";
1043 this.cancellable = cancellable;
1044 this.progress = progress;
1050 cancellable.cancel(
true);
1068 super.mouseWheelMoved(event);
1069 if (event.getPreciseWheelRotation() < 0) {
1070 graphComponent.zoomIn();
1071 }
else if (event.getPreciseWheelRotation() > 0) {
1072 graphComponent.zoomOut();
1075 CVTEvents.getCVTEventBus().post(
new CVTEvents.ScaleChangeEvent(graph.getView().getScale()));
1085 super.mouseClicked(event);
1086 if (SwingUtilities.isRightMouseButton(event)) {
1087 final mxCell cellAt = (mxCell) graphComponent.getCellAt(event.getX(),
event.getY());
1088 if (cellAt != null && cellAt.isVertex()) {
1089 final JPopupMenu jPopupMenu =
new JPopupMenu();
1090 final AccountDeviceInstanceKey adiKey = (AccountDeviceInstanceKey) cellAt.getValue();
1092 Set<mxCell> selectedVertices
1093 = Stream.of(graph.getSelectionModel().getCells())
1094 .map(mxCell.class::cast)
1095 .filter(mxCell::isVertex)
1096 .collect(Collectors.toSet());
1098 if (lockedVertexModel.isVertexLocked(cellAt)) {
1099 jPopupMenu.add(
new JMenuItem(
new UnlockAction(selectedVertices)));
1101 jPopupMenu.add(
new JMenuItem(
new LockAction(selectedVertices)));
1103 if (pinnedAccountModel.isAccountPinned(adiKey.getAccountDeviceInstance())) {
1104 jPopupMenu.add(UnpinAccountsAction.getInstance().getPopupPresenter());
1106 jPopupMenu.add(PinAccountsAction.getInstance().getPopupPresenter());
1107 jPopupMenu.add(ResetAndPinAccountsAction.getInstance().getPopupPresenter());
1109 jPopupMenu.show(graphComponent.getGraphControl(),
event.getX(),
event.getY());
1118 @NbBundle.Messages({
1119 "VisualizationPanel.unlockAction.singularText=Unlock Selected Account",
1120 "VisualizationPanel.unlockAction.pluralText=Unlock Selected Accounts",})
1126 super(selectedVertices.size() > 1 ? Bundle.VisualizationPanel_unlockAction_pluralText() : Bundle.VisualizationPanel_unlockAction_singularText(),
1128 this.selectedVertices = selectedVertices;
1134 lockedVertexModel.unlock(selectedVertices);
1141 @NbBundle.Messages({
1142 "VisualizationPanel.lockAction.singularText=Lock Selected Account",
1143 "VisualizationPanel.lockAction.pluralText=Lock Selected Accounts"})
1149 super(selectedVertices.size() > 1 ? Bundle.VisualizationPanel_lockAction_pluralText() : Bundle.VisualizationPanel_lockAction_singularText(),
1151 this.selectedVertices = selectedVertices;
1156 lockedVertexModel.lock(selectedVertices);
void zoomOutButtonActionPerformed(ActionEvent evt)
final Set< mxCell > selectedVertices
boolean isVertexIgnored(Object vertex)
void invoke(Object sender, mxEventObject evt)
JFXPanel notificationsJFXPanel
void forwardButtonActionPerformed(ActionEvent evt)
void mouseClicked(final MouseEvent event)
void createReport(Case currentCase, String reportName)
CommunicationsManager commsManager
boolean isVertexIgnored(Object vertex)
void handleStateChange(StateManager.CommunicationsState newState)
void applyLayout(NamedGraphLayout layout)
void actionPerformed(final ActionEvent event)
final mxRubberband rubberband
static boolean deleteFileDir(File path)
String getReportDirectory()
JToolBar.Separator jSeparator3
void fastOrganicLayoutButtonActionPerformed(ActionEvent evt)
void addReport(String localPath, String srcModuleName, String reportName)
JToolBar.Separator jSeparator2
ModalDialogProgressIndicator progress
mxRectangle setVertexLocation(Object vertex, double x, double y)
synchronized void start(String message, int totalWorkUnits)
synchronized void setCancelling(String cancellingMessage)
final CommunicationsGraph graph
void actionPerformed(final ActionEvent event)
boolean isVertexIgnored(Object vertex)
CommunicationsFilter currentFilter
void backButtonActionPerformed(ActionEvent evt)
void fitZoomButtonActionPerformed(ActionEvent evt)
SleuthkitCase getSleuthkitCase()
void mouseWheelMoved(final MouseWheelEvent event)
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)
void setStateButtonsEnabled()
final Set< mxCell > selectedVertices
void zoomActualButtonActionPerformed(ActionEvent evt)
void clearVizButtonActionPerformed(ActionEvent evt)
void snapshotButtonActionPerformed(ActionEvent evt)
synchronized void finish()