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.mxEvent;
32 import com.mxgraph.util.mxEventObject;
33 import com.mxgraph.util.mxEventSource;
34 import com.mxgraph.util.mxPoint;
35 import com.mxgraph.util.mxRectangle;
36 import com.mxgraph.util.mxUndoManager;
37 import com.mxgraph.util.mxUndoableEdit;
38 import com.mxgraph.view.mxCellState;
39 import com.mxgraph.view.mxGraph;
40 import com.mxgraph.view.mxGraphView;
41 import java.awt.BorderLayout;
42 import java.awt.Color;
43 import java.awt.Cursor;
44 import java.awt.Dimension;
46 import java.awt.Frame;
47 import java.awt.Graphics;
48 import java.awt.event.ActionEvent;
49 import java.awt.event.ActionListener;
50 import java.awt.event.MouseAdapter;
51 import java.awt.event.MouseEvent;
52 import java.awt.event.MouseWheelEvent;
53 import java.beans.PropertyChangeEvent;
54 import java.beans.PropertyVetoException;
55 import java.text.DecimalFormat;
56 import java.util.Arrays;
57 import java.util.EnumSet;
58 import java.util.HashMap;
59 import java.util.HashSet;
60 import java.util.List;
63 import java.util.concurrent.ExecutionException;
64 import java.util.concurrent.Future;
65 import java.util.function.BiConsumer;
66 import java.util.logging.Level;
67 import java.util.stream.Collectors;
68 import java.util.stream.Stream;
69 import javafx.application.Platform;
70 import javafx.embed.swing.JFXPanel;
71 import javafx.scene.Scene;
72 import javafx.scene.layout.Pane;
73 import javax.swing.AbstractAction;
74 import javax.swing.ImageIcon;
75 import javax.swing.JButton;
76 import javax.swing.JLabel;
77 import javax.swing.JMenuItem;
78 import javax.swing.JPanel;
79 import javax.swing.JPopupMenu;
80 import javax.swing.JSplitPane;
81 import javax.swing.JTextArea;
82 import javax.swing.JToolBar;
83 import javax.swing.SwingConstants;
84 import javax.swing.SwingUtilities;
85 import javax.swing.SwingWorker;
86 import org.controlsfx.control.Notifications;
87 import org.jdesktop.layout.GroupLayout;
88 import org.jdesktop.layout.LayoutStyle;
89 import org.openide.explorer.ExplorerManager;
90 import org.openide.explorer.ExplorerUtils;
91 import org.openide.nodes.Node;
92 import org.openide.util.Lookup;
93 import org.openide.util.NbBundle;
94 import org.openide.util.lookup.ProxyLookup;
115 @SuppressWarnings(
"PMD.SingularField")
118 private static final long serialVersionUID = 1L;
120 private static final String BASE_IMAGE_PATH =
"/org/sleuthkit/autopsy/communications/images";
121 static final private ImageIcon unlockIcon
123 static final private ImageIcon lockIcon
126 @NbBundle.Messages(
"VisualizationPanel.cancelButton.text=Cancel")
127 private static final String CANCEL = Bundle.VisualizationPanel_cancelButton_text();
129 private final ExplorerManager vizEM =
new ExplorerManager();
130 private final ExplorerManager gacEM =
new ExplorerManager();
138 private final CommunicationsGraph
graph;
140 private final mxUndoManager undoManager =
new mxUndoManager();
144 private SwingWorker<?, ?> worker;
145 private final PinnedAccountModel pinnedAccountModel = new PinnedAccountModel();
146 private final LockedVertexModel lockedVertexModel = new LockedVertexModel();
149 private NamedGraphLayout currentLayout;
151 @NbBundle.Messages("VisalizationPanel.paintingError=Problem painting visualization.")
155 notificationsJFXPanel.setScene(
new Scene(
new Pane()));
157 graph =
new CommunicationsGraph(pinnedAccountModel, lockedVertexModel);
165 graphComponent =
new mxGraphComponent(graph) {
167 protected mxGraphComponent.mxGraphControl createGraphControl() {
169 return new mxGraphControl() {
172 public void paint(Graphics graphics) {
174 super.paint(graphics);
175 }
catch (NullPointerException ex) {
181 logger.log(Level.WARNING,
"There was a NPE while painting the VisualizationPanel", ex);
188 graphComponent.setAutoExtend(
true);
189 graphComponent.setAutoScroll(
true);
190 graphComponent.setAutoscrolls(
true);
191 graphComponent.setConnectable(
false);
192 graphComponent.setDragEnabled(
false);
193 graphComponent.setKeepSelectionVisibleOnZoom(
true);
194 graphComponent.setOpaque(
true);
195 graphComponent.setToolTips(
true);
196 graphComponent.setBackground(Color.WHITE);
197 borderLayoutPanel.add(graphComponent, BorderLayout.CENTER);
200 rubberband =
new mxRubberband(graphComponent);
202 lockedVertexModel.registerhandler(
this);
204 final mxEventSource.mxIEventListener scaleListener = (Object sender, mxEventObject evt)
205 -> zoomLabel.setText(DecimalFormat.getPercentInstance().format(graph.getView().getScale()));
206 graph.getView().addListener(mxEvent.SCALE, scaleListener);
207 graph.getView().addListener(mxEvent.SCALE_AND_TRANSLATE, scaleListener);
210 graphComponent.getGraphControl().addMouseWheelListener(graphMouseListener);
211 graphComponent.getGraphControl().addMouseListener(graphMouseListener);
214 splitPane.setRightComponent(messageBrowser);
215 proxyLookup =
new ProxyLookup(
216 ExplorerUtils.createLookup(vizEM, getActionMap()),
222 final mxEventSource.mxIEventListener undoListener = (Object sender, mxEventObject evt)
223 -> undoManager.undoableEditHappened((mxUndoableEdit) evt.getProperty(
"edit"));
225 graph.getModel().addListener(mxEvent.UNDO, undoListener);
226 graph.getView().addListener(mxEvent.UNDO, undoListener);
231 organicLayout.setMaxIterations(10);
235 BiConsumer<JButton, NamedGraphLayout> configure = (layoutButton, layout) -> {
236 layoutButtons.put(layout, layoutButton);
237 layoutButton.addActionListener(event -> applyLayout(layout));
240 configure.accept(circleLayoutButton, circleLayout);
241 configure.accept(organicLayoutButton, organicLayout);
242 configure.accept(fastOrganicLayoutButton, fastOrganicLayout);
243 configure.accept(hierarchyLayoutButton, hierarchyLayout);
245 applyLayout(fastOrganicLayout);
254 void handle(LockedVertexModel.VertexLockEvent event) {
255 final Set<mxCell> vertices =
event.getVertices();
256 mxGraphView view = graph.getView();
257 vertices.forEach(vertex -> {
258 final mxCellState state = view.getState(vertex,
true);
259 view.updateLabel(state);
260 view.updateLabelBounds(state);
261 view.updateBoundingBox(state);
262 graphComponent.redraw(state);
267 void handle(
final CVTEvents.UnpinAccountsEvent pinEvent) {
268 graph.getModel().beginUpdate();
269 pinnedAccountModel.unpinAccount(pinEvent.getAccountDeviceInstances());
273 graph.getModel().endUpdate();
277 void handle(
final CVTEvents.PinAccountsEvent pinEvent) {
278 graph.getModel().beginUpdate();
279 if (pinEvent.isReplace()) {
282 pinnedAccountModel.pinAccount(pinEvent.getAccountDeviceInstances());
285 graph.getModel().endUpdate();
289 void handle(
final CVTEvents.FilterChangeEvent filterChangeEvent) {
290 graph.getModel().beginUpdate();
292 currentFilter = filterChangeEvent.getNewFilter();
295 graph.getModel().endUpdate();
298 @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
299 private
void rebuildGraph() {
300 if (pinnedAccountModel.isEmpty()) {
301 borderLayoutPanel.remove(graphComponent);
302 borderLayoutPanel.add(placeHolderPanel, BorderLayout.CENTER);
305 borderLayoutPanel.remove(placeHolderPanel);
306 borderLayoutPanel.add(graphComponent, BorderLayout.CENTER);
307 if (worker != null) {
313 worker = graph.rebuild(progress, commsManager, currentFilter);
314 cancelationListener.configure(worker, progress);
315 worker.addPropertyChangeListener((
final PropertyChangeEvent evt) -> {
316 if (worker.isDone()) {
317 if (worker.isCancelled()) {
321 applyLayout(currentLayout);
332 windowAncestor = (Frame) SwingUtilities.getAncestorOfClass(Frame.class,
this);
336 }
catch (TskCoreException ex) {
337 logger.log(Level.SEVERE,
"Error getting CommunicationsManager for the current case.", ex);
339 logger.log(Level.SEVERE,
"Can't get CommunicationsManager when there is no case open.", ex);
343 graph.getModel().beginUpdate();
347 graph.getModel().endUpdate();
349 if (evt.getNewValue() == null) {
352 Case currentCase = (
Case) evt.getNewValue();
355 }
catch (TskCoreException ex) {
356 logger.log(Level.SEVERE,
"Error getting CommunicationsManager for the current case.", ex);
367 @SuppressWarnings(
"unchecked")
369 private
void initComponents() {
371 splitPane =
new JSplitPane();
372 borderLayoutPanel =
new JPanel();
373 placeHolderPanel =
new JPanel();
374 jTextArea1 =
new JTextArea();
375 toolbar =
new JPanel();
376 jLabel1 =
new JLabel();
377 hierarchyLayoutButton =
new JButton();
378 fastOrganicLayoutButton =
new JButton();
379 organicLayoutButton =
new JButton();
380 circleLayoutButton =
new JButton();
381 jSeparator1 =
new JToolBar.Separator();
382 zoomOutButton =
new JButton();
383 zoomInButton =
new JButton();
384 zoomActualButton =
new JButton();
385 fitZoomButton =
new JButton();
386 jLabel2 =
new JLabel();
387 zoomLabel =
new JLabel();
388 clearVizButton =
new JButton();
389 jSeparator2 =
new JToolBar.Separator();
390 notificationsJFXPanel =
new JFXPanel();
392 setLayout(
new BorderLayout());
394 splitPane.setDividerLocation(800);
395 splitPane.setResizeWeight(0.5);
397 borderLayoutPanel.setLayout(
new BorderLayout());
399 jTextArea1.setBackground(
new Color(240, 240, 240));
400 jTextArea1.setColumns(20);
401 jTextArea1.setLineWrap(
true);
402 jTextArea1.setRows(5);
403 jTextArea1.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.jTextArea1.text"));
405 GroupLayout placeHolderPanelLayout =
new GroupLayout(placeHolderPanel);
406 placeHolderPanel.setLayout(placeHolderPanelLayout);
407 placeHolderPanelLayout.setHorizontalGroup(placeHolderPanelLayout.createParallelGroup(GroupLayout.LEADING)
408 .add(placeHolderPanelLayout.createSequentialGroup()
409 .addContainerGap(71, Short.MAX_VALUE)
410 .add(jTextArea1, GroupLayout.PREFERRED_SIZE, 424, GroupLayout.PREFERRED_SIZE)
411 .addContainerGap(248, Short.MAX_VALUE))
413 placeHolderPanelLayout.setVerticalGroup(placeHolderPanelLayout.createParallelGroup(GroupLayout.LEADING)
414 .add(placeHolderPanelLayout.createSequentialGroup()
415 .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
416 .add(jTextArea1, GroupLayout.PREFERRED_SIZE, 47, GroupLayout.PREFERRED_SIZE)
417 .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
420 borderLayoutPanel.add(placeHolderPanel, BorderLayout.CENTER);
422 jLabel1.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.jLabel1.text"));
424 hierarchyLayoutButton.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.hierarchyLayoutButton.text"));
425 hierarchyLayoutButton.setFocusable(
false);
426 hierarchyLayoutButton.setHorizontalTextPosition(SwingConstants.CENTER);
427 hierarchyLayoutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
429 fastOrganicLayoutButton.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.fastOrganicLayoutButton.text"));
430 fastOrganicLayoutButton.setFocusable(
false);
431 fastOrganicLayoutButton.setHorizontalTextPosition(SwingConstants.CENTER);
432 fastOrganicLayoutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
434 organicLayoutButton.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.organicLayoutButton.text"));
435 organicLayoutButton.setFocusable(
false);
436 organicLayoutButton.setHorizontalTextPosition(SwingConstants.CENTER);
437 organicLayoutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
439 circleLayoutButton.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.circleLayoutButton.text"));
440 circleLayoutButton.setFocusable(
false);
441 circleLayoutButton.setHorizontalTextPosition(SwingConstants.CENTER);
442 circleLayoutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
444 jSeparator1.setOrientation(SwingConstants.VERTICAL);
446 zoomOutButton.setIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/communications/images/magnifier-zoom-out-red.png")));
447 zoomOutButton.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.zoomOutButton.text"));
448 zoomOutButton.setToolTipText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.zoomOutButton.toolTipText"));
449 zoomOutButton.setFocusable(
false);
450 zoomOutButton.setHorizontalTextPosition(SwingConstants.CENTER);
451 zoomOutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
452 zoomOutButton.addActionListener(
new ActionListener() {
453 public void actionPerformed(ActionEvent evt) {
454 zoomOutButtonActionPerformed(evt);
458 zoomInButton.setIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/communications/images/magnifier-zoom-in-green.png")));
459 zoomInButton.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.zoomInButton.text"));
460 zoomInButton.setToolTipText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.zoomInButton.toolTipText"));
461 zoomInButton.setFocusable(
false);
462 zoomInButton.setHorizontalTextPosition(SwingConstants.CENTER);
463 zoomInButton.setVerticalTextPosition(SwingConstants.BOTTOM);
464 zoomInButton.addActionListener(
new ActionListener() {
465 public void actionPerformed(ActionEvent evt) {
466 zoomInButtonActionPerformed(evt);
470 zoomActualButton.setIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/communications/images/magnifier-zoom-actual.png")));
471 zoomActualButton.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.zoomActualButton.text"));
472 zoomActualButton.setToolTipText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.zoomActualButton.toolTipText"));
473 zoomActualButton.setFocusable(
false);
474 zoomActualButton.setHorizontalTextPosition(SwingConstants.CENTER);
475 zoomActualButton.setVerticalTextPosition(SwingConstants.BOTTOM);
476 zoomActualButton.addActionListener(
new ActionListener() {
477 public void actionPerformed(ActionEvent evt) {
478 zoomActualButtonActionPerformed(evt);
482 fitZoomButton.setIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/communications/images/magnifier-zoom-fit.png")));
483 fitZoomButton.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.fitZoomButton.text"));
484 fitZoomButton.setToolTipText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.fitZoomButton.toolTipText"));
485 fitZoomButton.setFocusable(
false);
486 fitZoomButton.setHorizontalTextPosition(SwingConstants.CENTER);
487 fitZoomButton.setVerticalTextPosition(SwingConstants.BOTTOM);
488 fitZoomButton.addActionListener(
new ActionListener() {
489 public void actionPerformed(ActionEvent evt) {
490 fitZoomButtonActionPerformed(evt);
494 jLabel2.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.jLabel2.text"));
496 zoomLabel.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.zoomLabel.text"));
498 clearVizButton.setIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/communications/images/broom.png")));
499 clearVizButton.setText(NbBundle.getMessage(
VisualizationPanel.class,
"VisualizationPanel.clearVizButton.text_1"));
500 clearVizButton.addActionListener(
new ActionListener() {
501 public void actionPerformed(ActionEvent evt) {
502 clearVizButtonActionPerformed(evt);
506 jSeparator2.setOrientation(SwingConstants.VERTICAL);
508 GroupLayout toolbarLayout =
new GroupLayout(toolbar);
509 toolbar.setLayout(toolbarLayout);
510 toolbarLayout.setHorizontalGroup(toolbarLayout.createParallelGroup(GroupLayout.LEADING)
511 .add(toolbarLayout.createSequentialGroup()
515 .add(jSeparator1, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE)
518 .addPreferredGap(LayoutStyle.RELATED)
519 .add(fastOrganicLayoutButton)
520 .addPreferredGap(LayoutStyle.RELATED)
521 .add(organicLayoutButton)
522 .addPreferredGap(LayoutStyle.RELATED)
523 .add(hierarchyLayoutButton)
524 .addPreferredGap(LayoutStyle.RELATED)
525 .add(circleLayoutButton)
526 .addPreferredGap(LayoutStyle.RELATED)
527 .add(jSeparator2, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE)
528 .addPreferredGap(LayoutStyle.RELATED)
530 .addPreferredGap(LayoutStyle.RELATED)
532 .addPreferredGap(LayoutStyle.RELATED)
533 .add(zoomOutButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE)
534 .addPreferredGap(LayoutStyle.RELATED)
535 .add(zoomInButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE)
536 .addPreferredGap(LayoutStyle.RELATED)
537 .add(zoomActualButton, GroupLayout.PREFERRED_SIZE, 33, GroupLayout.PREFERRED_SIZE)
538 .addPreferredGap(LayoutStyle.RELATED)
539 .add(fitZoomButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE)
540 .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
542 toolbarLayout.setVerticalGroup(toolbarLayout.createParallelGroup(GroupLayout.LEADING)
543 .add(toolbarLayout.createSequentialGroup()
545 .add(toolbarLayout.createParallelGroup(GroupLayout.CENTER)
546 .add(jLabel1, GroupLayout.PREFERRED_SIZE, 25, GroupLayout.PREFERRED_SIZE)
547 .add(hierarchyLayoutButton)
548 .add(fastOrganicLayoutButton)
549 .add(organicLayoutButton)
550 .add(circleLayoutButton)
551 .add(jSeparator1, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
553 .add(zoomInButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
554 .add(zoomActualButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
555 .add(fitZoomButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
559 .add(jSeparator2, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
563 borderLayoutPanel.add(toolbar, BorderLayout.PAGE_START);
564 borderLayoutPanel.add(notificationsJFXPanel, BorderLayout.PAGE_END);
566 splitPane.setLeftComponent(borderLayoutPanel);
568 add(splitPane, BorderLayout.CENTER);
576 graphComponent.zoomActual();
580 graphComponent.zoomIn();
584 graphComponent.zoomOut();
593 @NbBundle.Messages({
"VisualizationPanel.computingLayout=Computing Layout",
594 "# {0} - layout name",
595 "VisualizationPanel.layoutFailWithLockedVertices.text={0} layout failed with locked vertices. Unlock some vertices or try a different layout.",
596 "# {0} - layout name",
597 "VisualizationPanel.layoutFail.text={0} layout failed. Try a different layout."})
599 currentLayout = layout;
600 layoutButtons.forEach((layoutKey, button)
601 -> button.setFont(button.getFont().deriveFont(layoutKey == layout ? Font.BOLD : Font.PLAIN)));
604 progressIndicator.
start(Bundle.VisualizationPanel_computingLayout());
606 new SwingWorker<Void, Void>() {
608 protected Void doInBackground() {
609 graph.getModel().beginUpdate();
611 layout.execute(graph.getDefaultParent());
614 graph.getModel().endUpdate();
615 progressIndicator.
finish();
621 protected void done() {
624 }
catch (InterruptedException | ExecutionException ex) {
625 logger.log(Level.WARNING,
"CVT graph layout failed.", ex);
626 String message = (lockedVertexModel.isEmpty())
627 ? Bundle.VisualizationPanel_layoutFail_text(layout.
getDisplayName())
628 : Bundle.VisualizationPanel_layoutFailWithLockedVertices_text(layout.
getDisplayName());
631 -> Notifications.create().owner(notificationsJFXPanel.getScene().getWindow())
641 setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
642 graph.getModel().beginUpdate();
643 pinnedAccountModel.clear();
647 graph.getModel().endUpdate();
648 setCursor(Cursor.getDefaultCursor());
652 graphComponent.zoomTo(1,
true);
653 mxPoint translate = graph.getView().getTranslate();
654 if (translate == null || Double.isNaN(translate.getX()) || Double.isNaN(translate.getY())) {
655 translate =
new mxPoint();
658 mxRectangle boundsForCells = graph.getCellBounds(graph.getDefaultParent(),
true,
true,
true);
659 if (boundsForCells == null || Double.isNaN(boundsForCells.getWidth()) || Double.isNaN(boundsForCells.getHeight())) {
660 boundsForCells =
new mxRectangle(0, 0, 1, 1);
662 final mxPoint mxPoint =
new mxPoint(translate.getX() - boundsForCells.getX(), translate.getY() - boundsForCells.getY());
664 graph.cellsMoved(graph.getChildCells(graph.getDefaultParent()), mxPoint.getX(), mxPoint.getY(),
false,
false);
666 boundsForCells = graph.getCellBounds(graph.getDefaultParent(),
true,
true,
true);
667 if (boundsForCells == null || Double.isNaN(boundsForCells.getWidth()) || Double.isNaN(boundsForCells.getHeight())) {
668 boundsForCells =
new mxRectangle(0, 0, 1, 1);
671 final Dimension size = graphComponent.getSize();
672 final double widthFactor = size.getWidth() / boundsForCells.getWidth();
673 final double heightFactor = size.getHeight() / boundsForCells.getHeight();
675 graphComponent.zoom((heightFactor + widthFactor) / 2.0);
708 @SuppressWarnings(
"unchecked")
710 public void invoke(Object sender, mxEventObject evt) {
711 Object[] selectionCells = graph.getSelectionCells();
712 Node rootNode = Node.EMPTY;
713 Node[] selectedNodes =
new Node[0];
714 if (selectionCells.length > 0) {
715 mxICell[] selectedCells = Arrays.asList(selectionCells).toArray(
new mxCell[selectionCells.length]);
716 HashSet<Content> relationshipSources =
new HashSet<>();
717 HashSet<AccountDeviceInstanceKey> adis =
new HashSet<>();
718 for (mxICell cell : selectedCells) {
720 mxICell source = (mxICell) graph.getModel().getTerminal(cell,
true);
721 AccountDeviceInstanceKey account1 = (AccountDeviceInstanceKey) source.getValue();
722 mxICell target = (mxICell) graph.getModel().getTerminal(cell,
false);
723 AccountDeviceInstanceKey account2 = (AccountDeviceInstanceKey) target.getValue();
725 final List<Content> relationshipSources1 = commsManager.getRelationshipSources(
726 account1.getAccountDeviceInstance(),
727 account2.getAccountDeviceInstance(),
729 relationshipSources.addAll(relationshipSources1);
730 }
catch (TskCoreException tskCoreException) {
731 logger.log(Level.SEVERE,
" Error getting relationsips....", tskCoreException);
733 }
else if (cell.isVertex()) {
734 adis.add((AccountDeviceInstanceKey) cell.getValue());
738 rootNode = SelectionNode.createFromAccountsAndRelationships(relationshipSources, adis, currentFilter, commsManager);
739 selectedNodes =
new Node[]{rootNode};
741 vizEM.setRootContext(rootNode);
743 vizEM.setSelectedNodes(selectedNodes);
744 }
catch (PropertyVetoException ex) {
745 logger.log(Level.SEVERE,
"Selection vetoed.", ex);
755 String getDisplayName();
769 return super.isVertexIgnored(vertex)
770 || lockedVertexModel.isVertexLocked((mxCell) vertex);
775 if (isVertexIgnored(vertex)) {
776 return getVertexBounds(vertex);
778 return super.setVertexLocation(vertex, x, y);
784 return "Fast Organic";
800 return super.isVertexIgnored(vertex)
801 || lockedVertexModel.isVertexLocked((mxCell) vertex);
806 if (isVertexIgnored(vertex)) {
807 return getVertexBounds(vertex);
809 return super.setVertexLocation(vertex, x, y);
831 return super.isVertexIgnored(vertex)
832 || lockedVertexModel.isVertexLocked((mxCell) vertex);
837 if (isVertexIgnored(vertex)) {
838 return getVertexBounds(vertex);
840 return super.setVertexLocation(vertex, x, y);
861 return super.isVertexIgnored(vertex)
862 || lockedVertexModel.isVertexLocked((mxCell) vertex);
867 if (isVertexIgnored(vertex)) {
868 return getVertexBounds(vertex);
870 return super.setVertexLocation(vertex, x, y);
876 return "Hierarchical";
890 this.cancellable = cancellable;
891 this.progress = progress;
897 cancellable.cancel(
true);
915 super.mouseWheelMoved(event);
916 if (event.getPreciseWheelRotation() < 0) {
917 graphComponent.zoomIn();
918 }
else if (event.getPreciseWheelRotation() > 0) {
919 graphComponent.zoomOut();
930 super.mouseClicked(event);
931 if (SwingUtilities.isRightMouseButton(event)) {
932 final mxCell cellAt = (mxCell) graphComponent.getCellAt(event.getX(),
event.getY());
933 if (cellAt != null && cellAt.isVertex()) {
934 final JPopupMenu jPopupMenu =
new JPopupMenu();
935 final AccountDeviceInstanceKey adiKey = (AccountDeviceInstanceKey) cellAt.getValue();
937 Set<mxCell> selectedVertices
938 = Stream.of(graph.getSelectionModel().getCells())
939 .map(mxCell.class::cast)
940 .filter(mxCell::isVertex)
941 .collect(Collectors.toSet());
943 if (lockedVertexModel.isVertexLocked(cellAt)) {
944 jPopupMenu.add(
new JMenuItem(
new UnlockAction(selectedVertices)));
946 jPopupMenu.add(
new JMenuItem(
new LockAction(selectedVertices)));
948 if (pinnedAccountModel.isAccountPinned(adiKey)) {
949 jPopupMenu.add(UnpinAccountsAction.getInstance().getPopupPresenter());
951 jPopupMenu.add(PinAccountsAction.getInstance().getPopupPresenter());
952 jPopupMenu.add(ResetAndPinAccountsAction.getInstance().getPopupPresenter());
954 jPopupMenu.show(graphComponent.getGraphControl(),
event.getX(),
event.getY());
964 "VisualizationPanel.unlockAction.singularText=Unlock Selected Account",
965 "VisualizationPanel.unlockAction.pluralText=Unlock Selected Accounts",})
971 super(selectedVertices.size() > 1 ? Bundle.VisualizationPanel_unlockAction_pluralText() : Bundle.VisualizationPanel_unlockAction_singularText(),
973 this.selectedVertices = selectedVertices;
979 lockedVertexModel.unlock(selectedVertices);
987 "VisualizationPanel.lockAction.singularText=Lock Selected Account",
988 "VisualizationPanel.lockAction.pluralText=Lock Selected Accounts"})
994 super(selectedVertices.size() > 1 ? Bundle.VisualizationPanel_lockAction_pluralText() : Bundle.VisualizationPanel_lockAction_singularText(),
996 this.selectedVertices = selectedVertices;
1001 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)
CommunicationsManager commsManager
boolean isVertexIgnored(Object vertex)
void applyLayout(NamedGraphLayout layout)
void actionPerformed(final ActionEvent event)
final mxRubberband rubberband
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
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)
synchronized void finish()