Autopsy  4.11.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
VisualizationPanel.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2017-2018 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.communications;
20 
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;
46 import java.awt.Font;
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.Collections;
65 import java.util.Date;
66 import java.util.EnumSet;
67 import java.util.HashMap;
68 import java.util.HashSet;
69 import java.util.Map;
70 import java.util.Set;
71 import java.util.concurrent.ExecutionException;
72 import java.util.concurrent.Future;
73 import java.util.function.BiConsumer;
74 import java.util.logging.Level;
75 import java.util.stream.Collectors;
76 import java.util.stream.Stream;
77 import javafx.application.Platform;
78 import javafx.embed.swing.JFXPanel;
79 import javafx.scene.Scene;
80 import javafx.scene.layout.Pane;
81 import javax.swing.AbstractAction;
82 import javax.swing.ImageIcon;
83 import javax.swing.JButton;
84 import javax.swing.JLabel;
85 import javax.swing.JMenuItem;
86 import javax.swing.JOptionPane;
87 import javax.swing.JPanel;
88 import javax.swing.JPopupMenu;
89 import javax.swing.JSplitPane;
90 import javax.swing.JTextArea;
91 import javax.swing.JTextField;
92 import javax.swing.JToolBar;
93 import javax.swing.SwingConstants;
94 import javax.swing.SwingUtilities;
95 import javax.swing.SwingWorker;
96 import org.apache.commons.lang3.StringUtils;
97 import org.controlsfx.control.Notifications;
98 import org.jdesktop.layout.GroupLayout;
99 import org.jdesktop.layout.LayoutStyle;
100 import org.openide.util.NbBundle;
101 import org.openide.windows.WindowManager;
111 import org.sleuthkit.datamodel.AccountDeviceInstance;
112 import org.sleuthkit.datamodel.CommunicationsFilter;
113 import org.sleuthkit.datamodel.CommunicationsManager;
114 import org.sleuthkit.datamodel.TskCoreException;
125 @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
126 final public class VisualizationPanel extends JPanel {
127 
128  private static final long serialVersionUID = 1L;
129  private static final Logger logger = Logger.getLogger(VisualizationPanel.class.getName());
130  private static final String BASE_IMAGE_PATH = "/org/sleuthkit/autopsy/communications/images";
131  static final private ImageIcon unlockIcon
132  = new ImageIcon(VisualizationPanel.class.getResource(BASE_IMAGE_PATH + "/lock_large_unlocked.png"));
133  static final private ImageIcon lockIcon
134  = new ImageIcon(VisualizationPanel.class.getResource(BASE_IMAGE_PATH + "/lock_large_locked.png"));
135 
136  @NbBundle.Messages("VisualizationPanel.cancelButton.text=Cancel")
137  private static final String CANCEL = Bundle.VisualizationPanel_cancelButton_text();
138 
139  private Frame windowAncestor;
140 
141  private CommunicationsManager commsManager;
142  private CommunicationsFilter currentFilter;
143 
144  private final mxGraphComponent graphComponent;
145  private final CommunicationsGraph graph;
146 
147  private final mxUndoManager undoManager = new mxUndoManager();
148  private final mxRubberband rubberband; //NOPMD We keep a referenec as insurance to prevent garbage collection
149 
151  private SwingWorker<?, ?> worker;
152  private final PinnedAccountModel pinnedAccountModel = new PinnedAccountModel();
153  private final LockedVertexModel lockedVertexModel = new LockedVertexModel();
154 
155  private final Map<NamedGraphLayout, JButton> layoutButtons = new HashMap<>();
156  private NamedGraphLayout currentLayout;
157 
158  private final RelationshipBrowser relationshipBrowser;
159 
160  private final StateManager stateManager;
161 
162  @NbBundle.Messages("VisalizationPanel.paintingError=Problem painting visualization.")
164  initComponents();
165  //initialize invisible JFXPanel that is used to show JFXNotifications over this window.
166  notificationsJFXPanel.setScene(new Scene(new Pane()));
167 
168  graph = new CommunicationsGraph(pinnedAccountModel, lockedVertexModel);
169 
170  /*
171  * custom implementation of mxGraphComponent that uses... a custom
172  * implementation of mxGraphControl ... that overrides paint so we can
173  * catch the NPEs we are getting and deal with them. For now that means
174  * just ignoring them.
175  */
176  graphComponent = new mxGraphComponent(graph) {
177  @Override
178  protected mxGraphComponent.mxGraphControl createGraphControl() {
179 
180  return new mxGraphControl() {
181 
182  @Override
183  public void paint(Graphics graphics) {
184  try {
185  super.paint(graphics);
186  } catch (NullPointerException ex) { //NOPMD
187  /* We can't find the underlying cause of the NPE in
188  * jgraphx, but it doesn't seem to cause any
189  * noticeable problems, so we are just logging it
190  * and moving on.
191  */
192  logger.log(Level.WARNING, "There was a NPE while painting the VisualizationPanel", ex);
193  }
194  }
195 
196  };
197  }
198  };
199  graphComponent.setAutoExtend(true);
200  graphComponent.setAutoScroll(true);
201  graphComponent.setAutoscrolls(true);
202  graphComponent.setConnectable(false);
203  graphComponent.setDragEnabled(false);
204  graphComponent.setKeepSelectionVisibleOnZoom(true);
205  graphComponent.setOpaque(true);
206  graphComponent.setToolTips(true);
207  graphComponent.setBackground(Color.WHITE);
208  borderLayoutPanel.add(graphComponent, BorderLayout.CENTER);
209 
210  //install rubber band other handlers
211  rubberband = new mxRubberband(graphComponent);
212 
213  lockedVertexModel.registerhandler(this);
214 
215  final mxEventSource.mxIEventListener scaleListener = (Object sender, mxEventObject evt)
216  -> zoomLabel.setText(DecimalFormat.getPercentInstance().format(graph.getView().getScale()));
217  graph.getView().addListener(mxEvent.SCALE, scaleListener);
218  graph.getView().addListener(mxEvent.SCALE_AND_TRANSLATE, scaleListener);
219 
220  final GraphMouseListener graphMouseListener = new GraphMouseListener();
221  graphComponent.getGraphControl().addMouseWheelListener(graphMouseListener);
222  graphComponent.getGraphControl().addMouseListener(graphMouseListener);
223 
224  relationshipBrowser = new RelationshipBrowser();
225  splitPane.setRightComponent(relationshipBrowser);
226 
227  //feed selection to explorermanager
228  graph.getSelectionModel().addListener(mxEvent.CHANGE, new SelectionListener());
229  final mxEventSource.mxIEventListener undoListener = (Object sender, mxEventObject evt)
230  -> undoManager.undoableEditHappened((mxUndoableEdit) evt.getProperty("edit"));
231 
232  graph.getModel().addListener(mxEvent.UNDO, undoListener);
233  graph.getView().addListener(mxEvent.UNDO, undoListener);
234 
235  FastOrganicLayoutImpl fastOrganicLayout = new FastOrganicLayoutImpl(graph);
236 
237  //local method to configure layout buttons
238  BiConsumer<JButton, NamedGraphLayout> configure = (layoutButton, layout) -> {
239  layoutButtons.put(layout, layoutButton);
240  layoutButton.addActionListener(event -> applyLayout(layout));
241  };
242  //configure layout buttons.
243  configure.accept(fastOrganicLayoutButton, fastOrganicLayout);
244 
245  applyLayout(fastOrganicLayout);
246 
247  stateManager = new StateManager(pinnedAccountModel);
248 
249  setStateButtonsEnabled();
250  }
251 
252  @Subscribe
253  void handle(LockedVertexModel.VertexLockEvent event) {
254  final Set<mxCell> vertices = event.getVertices();
255  mxGraphView view = graph.getView();
256  vertices.forEach(vertex -> {
257  final mxCellState state = view.getState(vertex, true);
258  view.updateLabel(state);
259  view.updateLabelBounds(state);
260  view.updateBoundingBox(state);
261  graphComponent.redraw(state);
262  });
263  }
264 
265  @Subscribe
266  void handle(final CVTEvents.UnpinAccountsEvent pinEvent) {
267  graph.getModel().beginUpdate();
268  pinnedAccountModel.unpinAccount(pinEvent.getAccountDeviceInstances());
269  graph.clear();
270  rebuildGraph();
271  // Updates the display
272  graph.getModel().endUpdate();
273 
274  setStateButtonsEnabled();
275  }
276 
277  @Subscribe
278  void handle(final CVTEvents.PinAccountsEvent pinEvent) {
279  graph.getModel().beginUpdate();
280  if (pinEvent.isReplace()) {
281  graph.resetGraph();
282  }
283  pinnedAccountModel.pinAccount(pinEvent.getAccountDeviceInstances());
284  rebuildGraph();
285  // Updates the display
286  graph.getModel().endUpdate();
287 
288  setStateButtonsEnabled();
289  }
290 
291  @Subscribe
292  void handle(final CVTEvents.FilterChangeEvent filterChangeEvent) {
293  graph.getModel().beginUpdate();
294  graph.clear();
295  currentFilter = filterChangeEvent.getNewFilter();
296  rebuildGraph();
297  // Updates the display
298  graph.getModel().endUpdate();
299 
300  setStateButtonsEnabled();
301  }
302 
303  @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
304  private void rebuildGraph() {
305  if (pinnedAccountModel.isEmpty()) {
306  borderLayoutPanel.remove(graphComponent);
307  borderLayoutPanel.add(placeHolderPanel, BorderLayout.CENTER);
308  repaint();
309  } else {
310  borderLayoutPanel.remove(placeHolderPanel);
311  borderLayoutPanel.add(graphComponent, BorderLayout.CENTER);
312  if (worker != null) {
313  worker.cancel(true);
314  }
315 
316  final CancelationListener cancelationListener = new CancelationListener();
317  final ModalDialogProgressIndicator progress = new ModalDialogProgressIndicator(windowAncestor, "Loading Visualization", new String[]{CANCEL}, CANCEL, cancelationListener);
318  worker = graph.rebuild(progress, commsManager, currentFilter);
319  cancelationListener.configure(worker, progress);
320  worker.addPropertyChangeListener((final PropertyChangeEvent evt) -> {
321  if (worker.isDone()) {
322  if (worker.isCancelled()) {
323  graph.resetGraph();
324  rebuildGraph();
325  }
326  applyLayout(currentLayout);
327  }
328  });
329 
330  worker.execute();
331  }
332  }
333 
334  @Override
335  public void addNotify() {
336  super.addNotify();
337  windowAncestor = (Frame) SwingUtilities.getAncestorOfClass(Frame.class, this);
338 
339  try {
340  commsManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
341  } catch (TskCoreException ex) {
342  logger.log(Level.SEVERE, "Error getting CommunicationsManager for the current case.", ex); //NON-NLS
343  } catch (NoCurrentCaseException ex) {
344  logger.log(Level.SEVERE, "Can't get CommunicationsManager when there is no case open.", ex); //NON-NLS
345  }
346 
347  Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), evt -> {
348  graph.getModel().beginUpdate();
349  try {
350  graph.resetGraph();
351  } finally {
352  graph.getModel().endUpdate();
353  }
354  if (evt.getNewValue() == null) {
355  commsManager = null;
356  } else {
357  Case currentCase = (Case) evt.getNewValue();
358  try {
359  commsManager = currentCase.getSleuthkitCase().getCommunicationsManager();
360  } catch (TskCoreException ex) {
361  logger.log(Level.SEVERE, "Error getting CommunicationsManager for the current case.", ex); //NON-NLS
362  }
363  }
364  });
365  }
366 
372  @SuppressWarnings("unchecked")
373  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
374  private void initComponents() {
375 
376  splitPane = new javax.swing.JSplitPane();
377  borderLayoutPanel = new javax.swing.JPanel();
378  placeHolderPanel = new javax.swing.JPanel();
379  jTextArea1 = new javax.swing.JTextArea();
380  toolbar = new javax.swing.JPanel();
381  fastOrganicLayoutButton = new javax.swing.JButton();
382  zoomOutButton = new javax.swing.JButton();
383  zoomInButton = new javax.swing.JButton();
384  zoomActualButton = new javax.swing.JButton();
385  fitZoomButton = new javax.swing.JButton();
386  jLabel2 = new javax.swing.JLabel();
387  zoomLabel = new javax.swing.JLabel();
388  clearVizButton = new javax.swing.JButton();
389  jSeparator2 = new javax.swing.JToolBar.Separator();
390  backButton = new javax.swing.JButton();
391  forwardButton = new javax.swing.JButton();
392  snapshotButton = new javax.swing.JButton();
393  jSeparator3 = new javax.swing.JToolBar.Separator();
394  jSeparator4 = new javax.swing.JToolBar.Separator();
395  notificationsJFXPanel = new javafx.embed.swing.JFXPanel();
396 
397  setLayout(new java.awt.BorderLayout());
398 
399  splitPane.setDividerLocation(800);
400  splitPane.setResizeWeight(0.5);
401 
402  borderLayoutPanel.setLayout(new java.awt.BorderLayout());
403 
404  jTextArea1.setBackground(new java.awt.Color(240, 240, 240));
405  jTextArea1.setColumns(20);
406  jTextArea1.setLineWrap(true);
407  jTextArea1.setRows(5);
408  jTextArea1.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.jTextArea1.text")); // NOI18N
409 
410  org.jdesktop.layout.GroupLayout placeHolderPanelLayout = new org.jdesktop.layout.GroupLayout(placeHolderPanel);
411  placeHolderPanel.setLayout(placeHolderPanelLayout);
412  placeHolderPanelLayout.setHorizontalGroup(
413  placeHolderPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
414  .add(placeHolderPanelLayout.createSequentialGroup()
415  .addContainerGap(250, Short.MAX_VALUE)
416  .add(jTextArea1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 424, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
417  .addContainerGap(423, Short.MAX_VALUE))
418  );
419  placeHolderPanelLayout.setVerticalGroup(
420  placeHolderPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
421  .add(placeHolderPanelLayout.createSequentialGroup()
422  .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
423  .add(jTextArea1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 47, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
424  .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
425  );
426 
427  borderLayoutPanel.add(placeHolderPanel, java.awt.BorderLayout.CENTER);
428 
429  fastOrganicLayoutButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/arrow-circle-double-135.png"))); // NOI18N
430  fastOrganicLayoutButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fastOrganicLayoutButton.text")); // NOI18N
431  fastOrganicLayoutButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fastOrganicLayoutButton.toolTipText")); // NOI18N
432  fastOrganicLayoutButton.setFocusable(false);
433  fastOrganicLayoutButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
434 
435  zoomOutButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-out-red.png"))); // NOI18N
436  zoomOutButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomOutButton.text")); // NOI18N
437  zoomOutButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomOutButton.toolTipText")); // NOI18N
438  zoomOutButton.setFocusable(false);
439  zoomOutButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
440  zoomOutButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
441  zoomOutButton.addActionListener(new java.awt.event.ActionListener() {
442  public void actionPerformed(java.awt.event.ActionEvent evt) {
443  zoomOutButtonActionPerformed(evt);
444  }
445  });
446 
447  zoomInButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-in-green.png"))); // NOI18N
448  zoomInButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomInButton.text")); // NOI18N
449  zoomInButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomInButton.toolTipText")); // NOI18N
450  zoomInButton.setFocusable(false);
451  zoomInButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
452  zoomInButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
453  zoomInButton.addActionListener(new java.awt.event.ActionListener() {
454  public void actionPerformed(java.awt.event.ActionEvent evt) {
455  zoomInButtonActionPerformed(evt);
456  }
457  });
458 
459  zoomActualButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-actual.png"))); // NOI18N
460  zoomActualButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomActualButton.text")); // NOI18N
461  zoomActualButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomActualButton.toolTipText")); // NOI18N
462  zoomActualButton.setFocusable(false);
463  zoomActualButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
464  zoomActualButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
465  zoomActualButton.addActionListener(new java.awt.event.ActionListener() {
466  public void actionPerformed(java.awt.event.ActionEvent evt) {
467  zoomActualButtonActionPerformed(evt);
468  }
469  });
470 
471  fitZoomButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-fit.png"))); // NOI18N
472  fitZoomButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fitZoomButton.text")); // NOI18N
473  fitZoomButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fitZoomButton.toolTipText")); // NOI18N
474  fitZoomButton.setFocusable(false);
475  fitZoomButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
476  fitZoomButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
477  fitZoomButton.addActionListener(new java.awt.event.ActionListener() {
478  public void actionPerformed(java.awt.event.ActionEvent evt) {
479  fitZoomButtonActionPerformed(evt);
480  }
481  });
482 
483  jLabel2.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.jLabel2.text")); // NOI18N
484 
485  zoomLabel.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomLabel.text")); // NOI18N
486 
487  clearVizButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/broom.png"))); // NOI18N
488  clearVizButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.text_1")); // NOI18N
489  clearVizButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.toolTipText")); // NOI18N
490  clearVizButton.setActionCommand(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.actionCommand")); // NOI18N
491  clearVizButton.addActionListener(new java.awt.event.ActionListener() {
492  public void actionPerformed(java.awt.event.ActionEvent evt) {
493  clearVizButtonActionPerformed(evt);
494  }
495  });
496 
497  jSeparator2.setOrientation(javax.swing.SwingConstants.VERTICAL);
498 
499  backButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/resultset_previous.png"))); // NOI18N
500  backButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.backButton.text_1")); // NOI18N
501  backButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.backButton.toolTipText")); // NOI18N
502  backButton.addActionListener(new java.awt.event.ActionListener() {
503  public void actionPerformed(java.awt.event.ActionEvent evt) {
504  backButtonActionPerformed(evt);
505  }
506  });
507 
508  forwardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/resultset_next.png"))); // NOI18N
509  forwardButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.forwardButton.text")); // NOI18N
510  forwardButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.forwardButton.toolTipText")); // NOI18N
511  forwardButton.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
512  forwardButton.addActionListener(new java.awt.event.ActionListener() {
513  public void actionPerformed(java.awt.event.ActionEvent evt) {
514  forwardButtonActionPerformed(evt);
515  }
516  });
517 
518  snapshotButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/report/images/image.png"))); // NOI18N
519  snapshotButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.snapshotButton.text_1")); // NOI18N
520  snapshotButton.addActionListener(new java.awt.event.ActionListener() {
521  public void actionPerformed(java.awt.event.ActionEvent evt) {
522  snapshotButtonActionPerformed(evt);
523  }
524  });
525 
526  jSeparator3.setOrientation(javax.swing.SwingConstants.VERTICAL);
527 
528  jSeparator4.setOrientation(javax.swing.SwingConstants.VERTICAL);
529 
530  org.jdesktop.layout.GroupLayout toolbarLayout = new org.jdesktop.layout.GroupLayout(toolbar);
531  toolbar.setLayout(toolbarLayout);
532  toolbarLayout.setHorizontalGroup(
533  toolbarLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
534  .add(toolbarLayout.createSequentialGroup()
535  .addContainerGap()
536  .add(backButton)
537  .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
538  .add(forwardButton)
539  .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
540  .add(jSeparator4, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 10, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
541  .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
542  .add(fastOrganicLayoutButton)
543  .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
544  .add(clearVizButton)
545  .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
546  .add(jSeparator2, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 10, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
547  .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
548  .add(jLabel2)
549  .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
550  .add(zoomLabel)
551  .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
552  .add(zoomOutButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 32, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
553  .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
554  .add(zoomInButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 32, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
555  .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
556  .add(zoomActualButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 33, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
557  .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
558  .add(fitZoomButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 32, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
559  .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
560  .add(jSeparator3, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 10, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
561  .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
562  .add(snapshotButton)
563  .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
564  );
565  toolbarLayout.setVerticalGroup(
566  toolbarLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
567  .add(toolbarLayout.createSequentialGroup()
568  .add(3, 3, 3)
569  .add(toolbarLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.CENTER)
570  .add(fastOrganicLayoutButton)
571  .add(zoomOutButton)
572  .add(zoomInButton, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
573  .add(zoomActualButton, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
574  .add(fitZoomButton, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
575  .add(jLabel2)
576  .add(zoomLabel)
577  .add(clearVizButton)
578  .add(jSeparator2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
579  .add(backButton)
580  .add(forwardButton)
581  .add(snapshotButton)
582  .add(jSeparator3, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
583  .add(jSeparator4, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
584  .add(3, 3, 3))
585  );
586 
587  borderLayoutPanel.add(toolbar, java.awt.BorderLayout.PAGE_START);
588  borderLayoutPanel.add(notificationsJFXPanel, java.awt.BorderLayout.PAGE_END);
589 
590  splitPane.setLeftComponent(borderLayoutPanel);
591 
592  add(splitPane, java.awt.BorderLayout.CENTER);
593  }// </editor-fold>//GEN-END:initComponents
594 
595  private void fitZoomButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_fitZoomButtonActionPerformed
596  fitGraph();
597  }//GEN-LAST:event_fitZoomButtonActionPerformed
598 
599  private void zoomActualButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_zoomActualButtonActionPerformed
600  graphComponent.zoomActual();
601  CVTEvents.getCVTEventBus().post(new CVTEvents.ScaleChangeEvent(graph.getView().getScale()));
602  }//GEN-LAST:event_zoomActualButtonActionPerformed
603 
604  private void zoomInButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_zoomInButtonActionPerformed
605  graphComponent.zoomIn();
606  CVTEvents.getCVTEventBus().post(new CVTEvents.ScaleChangeEvent(graph.getView().getScale()));
607  }//GEN-LAST:event_zoomInButtonActionPerformed
608 
609  private void zoomOutButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_zoomOutButtonActionPerformed
610  graphComponent.zoomOut();
611  CVTEvents.getCVTEventBus().post(new CVTEvents.ScaleChangeEvent(graph.getView().getScale()));
612  }//GEN-LAST:event_zoomOutButtonActionPerformed
613 
620  @NbBundle.Messages({"VisualizationPanel.computingLayout=Computing Layout",
621  "# {0} - layout name",
622  "VisualizationPanel.layoutFailWithLockedVertices.text={0} layout failed with locked vertices. Unlock some vertices or try a different layout.",
623  "# {0} - layout name",
624  "VisualizationPanel.layoutFail.text={0} layout failed. Try a different layout."})
625  private void applyLayout(NamedGraphLayout layout) {
626  currentLayout = layout;
627  layoutButtons.forEach((layoutKey, button)
628  -> button.setFont(button.getFont().deriveFont(layoutKey == layout ? Font.BOLD : Font.PLAIN)));
629 
630  ModalDialogProgressIndicator progressIndicator = new ModalDialogProgressIndicator(windowAncestor, Bundle.VisualizationPanel_computingLayout());
631  progressIndicator.start(Bundle.VisualizationPanel_computingLayout());
632 
633  new SwingWorker<Void, Void>() {
634  @Override
635  protected Void doInBackground() {
636  graph.getModel().beginUpdate();
637  try {
638  layout.execute(graph.getDefaultParent());
639  fitGraph();
640  } finally {
641  graph.getModel().endUpdate();
642  progressIndicator.finish();
643  }
644  return null;
645  }
646 
647  @Override
648  protected void done() {
649  try {
650  get();
651  } catch (InterruptedException | ExecutionException ex) {
652  logger.log(Level.WARNING, "CVT graph layout failed.", ex);
653  }
654  }
655  }.execute();
656  }
657 
658  private void clearVizButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_clearVizButtonActionPerformed
659  CVTEvents.getCVTEventBus().post(new CVTEvents.UnpinAccountsEvent(pinnedAccountModel.getPinnedAccounts()));
660  }//GEN-LAST:event_clearVizButtonActionPerformed
661 
662  private void forwardButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_forwardButtonActionPerformed
663  handleStateChange(stateManager.advance());
664  }//GEN-LAST:event_forwardButtonActionPerformed
665 
666  private void backButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_backButtonActionPerformed
667  handleStateChange(stateManager.retreat());
668  }//GEN-LAST:event_backButtonActionPerformed
669 
675  private void handleStateChange(StateManager.CommunicationsState newState ){
676  if(newState == null) {
677  return;
678  }
679 
680  // If the zoom was changed, only change the zoom.
681  if(newState.isZoomChange()) {
682  graph.getView().setScale(newState.getZoomValue());
683  return;
684  }
685 
686  // This will cause the FilterPane to update its controls
687  CVTEvents.getCVTEventBus().post(new CVTEvents.StateChangeEvent(newState));
688  setStateButtonsEnabled();
689 
690  graph.getModel().beginUpdate();
691  graph.resetGraph();
692 
693  if(newState.getPinnedList() != null) {
694  pinnedAccountModel.pinAccount(newState.getPinnedList());
695  } else {
696  pinnedAccountModel.clear();
697  }
698 
699  currentFilter = newState.getCommunicationsFilter();
700 
701  rebuildGraph();
702  // Updates the display
703  graph.getModel().endUpdate();
704 
705  fitGraph();
706 
707  }
708 
709  private void setStateButtonsEnabled() {
710  backButton.setEnabled(stateManager.canRetreat());
711  forwardButton.setEnabled(stateManager.canAdvance());
712  }
713 
714  @NbBundle.Messages({
715  "VisualizationPanel_snapshot_report_failure=Snapshot report not created. An error occurred during creation."
716  })
717  private void snapshotButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_snapshotButtonActionPerformed
718  try {
719  handleSnapshotEvent();
720  } catch (NoCurrentCaseException | IOException ex) {
721  logger.log(Level.SEVERE, "Unable to create communications snapsot report", ex); //NON-NLS
722 
723  Platform.runLater(()
724  -> Notifications.create().owner(notificationsJFXPanel.getScene().getWindow())
725  .text(Bundle.VisualizationPanel_snapshot_report_failure())
726  .showWarning());
727  } catch( TskCoreException ex) {
728  logger.log(Level.WARNING, "Unable to add report to currenct case", ex); //NON-NLS
729  }
730  }//GEN-LAST:event_snapshotButtonActionPerformed
731 
732  private void fitGraph() {
733  graphComponent.zoomTo(1, true);
734  mxPoint translate = graph.getView().getTranslate();
735  if (translate == null || Double.isNaN(translate.getX()) || Double.isNaN(translate.getY())) {
736  translate = new mxPoint();
737  }
738 
739  mxRectangle boundsForCells = graph.getCellBounds(graph.getDefaultParent(), true, true, true);
740  if (boundsForCells == null || Double.isNaN(boundsForCells.getWidth()) || Double.isNaN(boundsForCells.getHeight())) {
741  boundsForCells = new mxRectangle(0, 0, 1, 1);
742  }
743  final mxPoint mxPoint = new mxPoint(translate.getX() - boundsForCells.getX(), translate.getY() - boundsForCells.getY());
744 
745  graph.cellsMoved(graph.getChildCells(graph.getDefaultParent()), mxPoint.getX(), mxPoint.getY(), false, false);
746 
747  boundsForCells = graph.getCellBounds(graph.getDefaultParent(), true, true, true);
748  if (boundsForCells == null || Double.isNaN(boundsForCells.getWidth()) || Double.isNaN(boundsForCells.getHeight())) {
749  boundsForCells = new mxRectangle(0, 0, 1, 1);
750  }
751 
752  final Dimension size = graphComponent.getSize();
753  final double widthFactor = size.getWidth() / boundsForCells.getWidth();
754  final double heightFactor = size.getHeight() / boundsForCells.getHeight();
755 
756  graphComponent.zoom((heightFactor + widthFactor) / 2.0);
757  }
758 
765  @NbBundle.Messages({
766  "VisualizationPanel_action_dialogs_title=Communications",
767  "VisualizationPanel_module_name=Communications",
768  "VisualizationPanel_action_name_text=Snapshot Report",
769  "VisualizationPane_fileName_prompt=Enter name for the Communications Snapshot Report:",
770  "VisualizationPane_reportName=Communications Snapshot",
771  "# {0} - default name",
772  "VisualizationPane_accept_defaultName=Report name was empty. Press OK to accept default report name: {0}",
773  "VisualizationPane_blank_report_title=Blank Report Name",
774  "# {0} - report name",
775  "VisualizationPane_overrite_exiting=Overwrite existing report?\n{0}"
776  })
777  private void handleSnapshotEvent() throws NoCurrentCaseException, IOException, TskCoreException {
778  Case currentCase = Case.getCurrentCaseThrows();
779  Date generationDate = new Date();
780 
781  final String defaultReportName = FileUtil.escapeFileName(currentCase.getDisplayName() + " " + new SimpleDateFormat("MMddyyyyHHmmss").format(generationDate)); //NON_NLS
782 
783  final JTextField text = new JTextField(50);
784  final JPanel panel = new JPanel(new GridLayout(2, 1));
785  panel.add(new JLabel(Bundle.VisualizationPane_fileName_prompt()));
786  panel.add(text);
787 
788  text.setText(defaultReportName);
789 
790  int result = JOptionPane.showConfirmDialog(graphComponent, panel,
791  Bundle.VisualizationPanel_action_dialogs_title(), JOptionPane.OK_CANCEL_OPTION);
792 
793  if (result == JOptionPane.OK_OPTION) {
794  String enteredReportName = text.getText();
795 
796  if(enteredReportName.trim().isEmpty()){
797  result = JOptionPane.showConfirmDialog(graphComponent, Bundle.VisualizationPane_accept_defaultName(defaultReportName), Bundle.VisualizationPane_blank_report_title(), JOptionPane.OK_CANCEL_OPTION);
798  if(result != JOptionPane.OK_OPTION) {
799  return;
800  }
801  }
802 
803  String reportName = StringUtils.defaultIfBlank(enteredReportName, defaultReportName);
804  Path reportPath = Paths.get(currentCase.getReportDirectory(), reportName);
805  if (Files.exists(reportPath)) {
806  result = JOptionPane.showConfirmDialog(graphComponent, Bundle.VisualizationPane_overrite_exiting(reportName),
807  Bundle.VisualizationPanel_action_dialogs_title(), JOptionPane.OK_CANCEL_OPTION);
808 
809  if (result == JOptionPane.OK_OPTION) {
810  FileUtil.deleteFileDir(reportPath.toFile());
811  createReport(currentCase, reportName);
812  }
813  } else {
814  createReport(currentCase, reportName);
815  currentCase.addReport(reportPath.toString(), Bundle.VisualizationPanel_module_name(), reportName);
816 
817  }
818  }
819  }
820 
829  @NbBundle.Messages({
830  "VisualizationPane_DisplayName=Open Report",
831  "VisualizationPane_NoAssociatedEditorMessage=There is no associated editor for reports of this type or the associated application failed to launch.",
832  "VisualizationPane_MessageBoxTitle=Open Report Failure",
833  "VisualizationPane_NoOpenInEditorSupportMessage=This platform (operating system) does not support opening a file in an editor this way.",
834  "VisualizationPane_MissingReportFileMessage=The report file no longer exists.",
835  "VisualizationPane_ReportFileOpenPermissionDeniedMessage=Permission to open the report file was denied.",
836  "# {0} - report path",
837  "VisualizationPane_Report_Success=Report Successfully create at:\n{0}",
838  "VisualizationPane_Report_OK_Button=OK",
839  "VisualizationPane_Open_Report=Open Report",})
840  private void createReport(Case currentCase, String reportName) throws IOException {
841 
842  // Create the report.
843  Path reportFolderPath = Paths.get(currentCase.getReportDirectory(), reportName, Bundle.VisualizationPane_reportName()); //NON_NLS
844  BufferedImage image = mxCellRenderer.createBufferedImage(graph, null, graph.getView().getScale(), Color.WHITE, true, null);
845  Path reportPath = new CommSnapShotReportWriter(currentCase, reportFolderPath, reportName, new Date(), image, currentFilter).writeReport();
846 
847  // Report success to the user and offer to open the report.
848  String message = Bundle.VisualizationPane_Report_Success(reportPath.toAbsolutePath());
849  String[] buttons = {Bundle.VisualizationPane_Open_Report(), Bundle.VisualizationPane_Report_OK_Button()};
850 
851  int result = JOptionPane.showOptionDialog(graphComponent, message,
852  Bundle.VisualizationPanel_action_dialogs_title(),
853  JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE,
854  null, buttons, buttons[1]);
855  if (result == JOptionPane.YES_NO_OPTION) {
856  try {
857  Desktop.getDesktop().open(reportPath.toFile());
858  } catch (IOException ex) {
859  JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
860  Bundle.VisualizationPane_NoAssociatedEditorMessage(),
861  Bundle.VisualizationPane_MessageBoxTitle(),
862  JOptionPane.ERROR_MESSAGE);
863  } catch (UnsupportedOperationException ex) {
864  JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
865  Bundle.VisualizationPane_NoOpenInEditorSupportMessage(),
866  Bundle.VisualizationPane_MessageBoxTitle(),
867  JOptionPane.ERROR_MESSAGE);
868  } catch (IllegalArgumentException ex) {
869  JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
870  Bundle.VisualizationPane_MissingReportFileMessage(),
871  Bundle.VisualizationPane_MessageBoxTitle(),
872  JOptionPane.ERROR_MESSAGE);
873  } catch (SecurityException ex) {
874  JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
875  Bundle.VisualizationPane_ReportFileOpenPermissionDeniedMessage(),
876  Bundle.VisualizationPane_MessageBoxTitle(),
877  JOptionPane.ERROR_MESSAGE);
878  }
879  }
880  }
881 
882  // Variables declaration - do not modify//GEN-BEGIN:variables
883  private javax.swing.JButton backButton;
884  private javax.swing.JPanel borderLayoutPanel;
885  private javax.swing.JButton clearVizButton;
886  private javax.swing.JButton fastOrganicLayoutButton;
887  private javax.swing.JButton fitZoomButton;
888  private javax.swing.JButton forwardButton;
889  private javax.swing.JLabel jLabel2;
890  private javax.swing.JToolBar.Separator jSeparator2;
891  private javax.swing.JToolBar.Separator jSeparator3;
892  private javax.swing.JToolBar.Separator jSeparator4;
893  private javax.swing.JTextArea jTextArea1;
894  private javafx.embed.swing.JFXPanel notificationsJFXPanel;
895  private javax.swing.JPanel placeHolderPanel;
896  private javax.swing.JButton snapshotButton;
897  private javax.swing.JSplitPane splitPane;
898  private javax.swing.JPanel toolbar;
899  private javax.swing.JButton zoomActualButton;
900  private javax.swing.JButton zoomInButton;
901  private javax.swing.JLabel zoomLabel;
902  private javax.swing.JButton zoomOutButton;
903  // End of variables declaration//GEN-END:variables
904 
909  final private class SelectionListener implements mxEventSource.mxIEventListener {
910 
911  @SuppressWarnings("unchecked")
912  @Override
913  public void invoke(Object sender, mxEventObject evt) {
914  Object[] selectionCells = graph.getSelectionCells();
915  if (selectionCells.length > 0) {
916  mxICell[] selectedCells = Arrays.asList(selectionCells).toArray(new mxCell[selectionCells.length]);
917  HashSet<AccountDeviceInstance> deviceInstances = new HashSet<>();
918  for (mxICell cell : selectedCells) {
919  if (cell.isEdge()) {
920  mxICell source = (mxICell) graph.getModel().getTerminal(cell, true);
921  mxICell target = (mxICell) graph.getModel().getTerminal(cell, false);
922 
923  deviceInstances.add(((AccountDeviceInstanceKey) source.getValue()).getAccountDeviceInstance());
924  deviceInstances.add(((AccountDeviceInstanceKey) target.getValue()).getAccountDeviceInstance());
925 
926  } else if (cell.isVertex()) {
927  deviceInstances.add(((AccountDeviceInstanceKey) cell.getValue()).getAccountDeviceInstance());
928  }
929  }
930 
931  relationshipBrowser.setSelectionInfo(new SelectionInfo(deviceInstances, currentFilter));
932  } else {
933  relationshipBrowser.setSelectionInfo(new SelectionInfo(Collections.EMPTY_SET, currentFilter));
934  }
935  }
936  }
937 
941  private interface NamedGraphLayout extends mxIGraphLayout {
942 
943  String getDisplayName();
944  }
945 
949  final private class FastOrganicLayoutImpl extends mxFastOrganicLayout implements NamedGraphLayout {
950 
951  FastOrganicLayoutImpl(mxGraph graph) {
952  super(graph);
953  }
954 
955  @Override
956  public boolean isVertexIgnored(Object vertex) {
957  return super.isVertexIgnored(vertex)
958  || lockedVertexModel.isVertexLocked((mxCell) vertex);
959  }
960 
961  @Override
962  public mxRectangle setVertexLocation(Object vertex, double x, double y) { //NOPMD x, y are standard coordinate names
963  if (isVertexIgnored(vertex)) {
964  return getVertexBounds(vertex);
965  } else {
966  return super.setVertexLocation(vertex, x, y);
967  }
968  }
969 
970  @Override
971  public String getDisplayName() {
972  return "Fast Organic";
973  }
974  }
975 
979  final private class CircleLayoutImpl extends mxCircleLayout implements NamedGraphLayout {
980 
981  CircleLayoutImpl(mxGraph graph) {
982  super(graph);
983  setResetEdges(true);
984  }
985 
986  @Override
987  public boolean isVertexIgnored(Object vertex) {
988  return super.isVertexIgnored(vertex)
989  || lockedVertexModel.isVertexLocked((mxCell) vertex);
990  }
991 
992  @Override
993  public mxRectangle setVertexLocation(Object vertex, double x, double y) { //NOPMD x, y are standard coordinate names
994  if (isVertexIgnored(vertex)) {
995  return getVertexBounds(vertex);
996  } else {
997  return super.setVertexLocation(vertex, x, y);
998  }
999  }
1000 
1001  @Override
1002  public String getDisplayName() {
1003  return "Circle";
1004  }
1005  }
1006 
1010  final private class OrganicLayoutImpl extends mxOrganicLayout implements NamedGraphLayout {
1011 
1012  OrganicLayoutImpl(mxGraph graph) {
1013  super(graph);
1014  setResetEdges(true);
1015  }
1016 
1017  @Override
1018  public boolean isVertexIgnored(Object vertex) {
1019  return super.isVertexIgnored(vertex)
1020  || lockedVertexModel.isVertexLocked((mxCell) vertex);
1021  }
1022 
1023  @Override
1024  public mxRectangle setVertexLocation(Object vertex, double x, double y) { //NOPMD x, y are standard coordinate names
1025  if (isVertexIgnored(vertex)) {
1026  return getVertexBounds(vertex);
1027  } else {
1028  return super.setVertexLocation(vertex, x, y);
1029  }
1030  }
1031 
1032  @Override
1033  public String getDisplayName() {
1034  return "Organic";
1035  }
1036  }
1037 
1041  final private class HierarchicalLayoutImpl extends mxHierarchicalLayout implements NamedGraphLayout {
1042 
1043  HierarchicalLayoutImpl(mxGraph graph) {
1044  super(graph);
1045  }
1046 
1047  @Override
1048  public boolean isVertexIgnored(Object vertex) {
1049  return super.isVertexIgnored(vertex)
1050  || lockedVertexModel.isVertexLocked((mxCell) vertex);
1051  }
1052 
1053  @Override
1054  public mxRectangle setVertexLocation(Object vertex, double x, double y) { //NOPMD x, y are standard coordinate names
1055  if (isVertexIgnored(vertex)) {
1056  return getVertexBounds(vertex);
1057  } else {
1058  return super.setVertexLocation(vertex, x, y);
1059  }
1060  }
1061 
1062  @Override
1063  public String getDisplayName() {
1064  return "Hierarchical";
1065  }
1066  }
1067 
1072  private class CancelationListener implements ActionListener {
1073 
1074  private Future<?> cancellable;
1076 
1077  void configure(Future<?> cancellable, ModalDialogProgressIndicator progress) {
1078  this.cancellable = cancellable;
1079  this.progress = progress;
1080  }
1081 
1082  @Override
1083  public void actionPerformed(ActionEvent event) {
1084  progress.setCancelling("Cancelling...");
1085  cancellable.cancel(true);
1086  progress.finish();
1087  }
1088  }
1089 
1094  private class GraphMouseListener extends MouseAdapter {
1095 
1101  @Override
1102  public void mouseWheelMoved(final MouseWheelEvent event) {
1103  super.mouseWheelMoved(event);
1104  if (event.getPreciseWheelRotation() < 0) {
1105  graphComponent.zoomIn();
1106  } else if (event.getPreciseWheelRotation() > 0) {
1107  graphComponent.zoomOut();
1108  }
1109 
1110  CVTEvents.getCVTEventBus().post(new CVTEvents.ScaleChangeEvent(graph.getView().getScale()));
1111  }
1112 
1118  @Override
1119  public void mouseClicked(final MouseEvent event) {
1120  super.mouseClicked(event);
1121  if (SwingUtilities.isRightMouseButton(event)) {
1122  final mxCell cellAt = (mxCell) graphComponent.getCellAt(event.getX(), event.getY());
1123  if (cellAt != null && cellAt.isVertex()) {
1124  final JPopupMenu jPopupMenu = new JPopupMenu();
1125  final AccountDeviceInstanceKey adiKey = (AccountDeviceInstanceKey) cellAt.getValue();
1126 
1127  Set<mxCell> selectedVertices
1128  = Stream.of(graph.getSelectionModel().getCells())
1129  .map(mxCell.class::cast)
1130  .filter(mxCell::isVertex)
1131  .collect(Collectors.toSet());
1132 
1133  if (lockedVertexModel.isVertexLocked(cellAt)) {
1134  jPopupMenu.add(new JMenuItem(new UnlockAction(selectedVertices)));
1135  } else {
1136  jPopupMenu.add(new JMenuItem(new LockAction(selectedVertices)));
1137  }
1138  if (pinnedAccountModel.isAccountPinned(adiKey)) {
1139  jPopupMenu.add(UnpinAccountsAction.getInstance().getPopupPresenter());
1140  } else {
1141  jPopupMenu.add(PinAccountsAction.getInstance().getPopupPresenter());
1142  jPopupMenu.add(ResetAndPinAccountsAction.getInstance().getPopupPresenter());
1143  }
1144  jPopupMenu.show(graphComponent.getGraphControl(), event.getX(), event.getY());
1145  }
1146  }
1147  }
1148  }
1149 
1153  @NbBundle.Messages({
1154  "VisualizationPanel.unlockAction.singularText=Unlock Selected Account",
1155  "VisualizationPanel.unlockAction.pluralText=Unlock Selected Accounts",})
1156  private final class UnlockAction extends AbstractAction {
1157 
1158  private final Set<mxCell> selectedVertices;
1159 
1160  UnlockAction(Set<mxCell> selectedVertices) {
1161  super(selectedVertices.size() > 1 ? Bundle.VisualizationPanel_unlockAction_pluralText() : Bundle.VisualizationPanel_unlockAction_singularText(),
1162  unlockIcon);
1163  this.selectedVertices = selectedVertices;
1164  }
1165 
1166  @Override
1167 
1168  public void actionPerformed(final ActionEvent event) {
1169  lockedVertexModel.unlock(selectedVertices);
1170  }
1171  }
1172 
1176  @NbBundle.Messages({
1177  "VisualizationPanel.lockAction.singularText=Lock Selected Account",
1178  "VisualizationPanel.lockAction.pluralText=Lock Selected Accounts"})
1179  private final class LockAction extends AbstractAction {
1180 
1181  private final Set<mxCell> selectedVertices;
1182 
1183  LockAction(Set<mxCell> selectedVertices) {
1184  super(selectedVertices.size() > 1 ? Bundle.VisualizationPanel_lockAction_pluralText() : Bundle.VisualizationPanel_lockAction_singularText(),
1185  lockIcon);
1186  this.selectedVertices = selectedVertices;
1187  }
1188 
1189  @Override
1190  public void actionPerformed(final ActionEvent event) {
1191  lockedVertexModel.lock(selectedVertices);
1192  }
1193  }
1194 }
void createReport(Case currentCase, String reportName)
void handleStateChange(StateManager.CommunicationsState newState)
static boolean deleteFileDir(File path)
Definition: FileUtil.java:87
void addReport(String localPath, String srcModuleName, String reportName)
Definition: Case.java:1534
synchronized void start(String message, int totalWorkUnits)
static String escapeFileName(String fileName)
Definition: FileUtil.java:169
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static void addEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:441

Copyright © 2012-2018 Basis Technology. Generated on: Fri Jun 21 2019
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.