From 08cc853fa8e8e447268ecde3c18f4f980508c11f Mon Sep 17 00:00:00 2001 From: millmanorama Date: Wed, 4 Apr 2018 16:22:45 +0200 Subject: [PATCH 01/11] refactor to use LockedVertexLayoutWrapper --- .../communications/LockedVertexModel.java | 123 ++++++++++++++++ .../communications/VisualizationPanel.form | 6 +- .../communications/VisualizationPanel.java | 131 ++++-------------- 3 files changed, 151 insertions(+), 109 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java b/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java index f26e9515b3..cde4eb5698 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java @@ -19,8 +19,13 @@ package org.sleuthkit.autopsy.communications; import com.google.common.eventbus.EventBus; +import com.mxgraph.layout.mxGraphLayout; import com.mxgraph.model.mxCell; +import com.mxgraph.util.mxPoint; +import com.mxgraph.util.mxRectangle; +import com.mxgraph.view.mxGraph; import java.util.HashSet; +import java.util.List; import java.util.Set; class LockedVertexModel { @@ -95,4 +100,122 @@ class LockedVertexModel { this.locked = locked; } } + + mxGraphLayout createLockedVertexWrapper(L layout) { + return new LockedVertexLayoutWrapper<>(layout, this); + } + + /** An mxGraphLayout that wrapps an other layout and ignores locked vertes. + * + * @param + */ + private static final class LockedVertexLayoutWrapper extends mxGraphLayout { + + private final L wrappedLayout; + private final LockedVertexModel lockedVertexModel; + + /** + * + * + * @param layout the value of graph + * @param lockedVertexModel the value of lockedVertexModel2 + */ + private LockedVertexLayoutWrapper(L layout, LockedVertexModel lockedVertexModel) { + super(layout.getGraph()); + this.lockedVertexModel = lockedVertexModel; + wrappedLayout = layout; + } + + @Override + public boolean isVertexIgnored(Object vertex) { + return wrappedLayout.isVertexIgnored(vertex) + || lockedVertexModel.isVertexLocked((mxCell) vertex); + } + + @Override + public mxRectangle setVertexLocation(Object vertex, double x, double y) { + if (isVertexIgnored(vertex)) { + return getVertexBounds(vertex); + } else { + return wrappedLayout.setVertexLocation(vertex, x, y); + } + } + + @Override + public void execute(Object parent) { + wrappedLayout.execute(parent); + } + + @Override + public void moveCell(Object cell, double x, double y) { + wrappedLayout.moveCell(cell, x, y); + } + + @Override + public mxGraph getGraph() { + return wrappedLayout.getGraph(); + } + + @Override + public Object getConstraint(Object key, Object cell) { + return wrappedLayout.getConstraint(key, cell); + } + + @Override + public Object getConstraint(Object key, Object cell, Object edge, boolean source) { + return wrappedLayout.getConstraint(key, cell, edge, source); + } + + @Override + public boolean isUseBoundingBox() { + return wrappedLayout.isUseBoundingBox(); + } + + @Override + public void setUseBoundingBox(boolean useBoundingBox) { + wrappedLayout.setUseBoundingBox(useBoundingBox); + } + + @Override + public boolean isVertexMovable(Object vertex) { + return wrappedLayout.isVertexMovable(vertex); + } + + @Override + public boolean isEdgeIgnored(Object edge) { + return wrappedLayout.isEdgeIgnored(edge); + } + + @Override + public void setEdgeStyleEnabled(Object edge, boolean value) { + wrappedLayout.setEdgeStyleEnabled(edge, value); + } + + @Override + public void setOrthogonalEdge(Object edge, boolean value) { + wrappedLayout.setOrthogonalEdge(edge, value); + } + + @Override + public mxPoint getParentOffset(Object parent) { + return wrappedLayout.getParentOffset(parent); + } + + @Override + public void setEdgePoints(Object edge, List points) { + wrappedLayout.setEdgePoints(edge, points); + } + + @Override + public mxRectangle getVertexBounds(Object vertex) { + return wrappedLayout.getVertexBounds(vertex); + } + + @Override + public void arrangeGroups(Object[] groups, int border) { + wrappedLayout.arrangeGroups(groups, border); + } + + } + } diff --git a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.form b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.form index a847f700c7..deae56fd17 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.form +++ b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.form @@ -11,7 +11,7 @@ - + @@ -106,7 +106,7 @@ - + @@ -120,7 +120,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java index 965832b3bd..a5175cfb4b 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java @@ -21,10 +21,12 @@ package org.sleuthkit.autopsy.communications; import com.google.common.eventbus.Subscribe; import com.mxgraph.layout.hierarchical.mxHierarchicalLayout; import com.mxgraph.layout.mxCircleLayout; +import com.mxgraph.layout.mxEdgeLabelLayout; import com.mxgraph.layout.mxFastOrganicLayout; import com.mxgraph.layout.mxGraphLayout; import com.mxgraph.layout.mxIGraphLayout; import com.mxgraph.layout.mxOrganicLayout; +import com.mxgraph.layout.mxParallelEdgeLayout; import com.mxgraph.model.mxCell; import com.mxgraph.model.mxICell; import com.mxgraph.swing.handler.mxRubberband; @@ -61,8 +63,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.Future; import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Function; import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.ImageIcon; @@ -139,10 +139,11 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider private final mxUndoManager undoManager = new mxUndoManager(); private final mxRubberband rubberband; - private final mxFastOrganicLayout fastOrganicLayout; - private final mxCircleLayout circleLayout; - private final mxOrganicLayout organicLayout; - private final mxHierarchicalLayout hierarchyLayout; + + private final mxGraphLayout fastOrganicLayout; + private final mxGraphLayout circleLayout; + private final mxGraphLayout organicLayout; + private final mxGraphLayout hierarchyLayout; @ThreadConfined(type = ThreadConfined.ThreadType.AWT) private SwingWorker worker; @@ -158,7 +159,6 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider pinnedAccountModel = graph.getPinnedAccountModel(); lockedVertexModel = graph.getLockedVertexModel(); - graphComponent = new mxGraphComponent(graph); graphComponent.setAutoExtend(true); @@ -198,12 +198,20 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider graph.getModel().addListener(mxEvent.UNDO, undoListener); graph.getView().addListener(mxEvent.UNDO, undoListener); - - fastOrganicLayout = new mxFastOrganicLayoutImpl(graph); - circleLayout = new mxCircleLayoutImpl(graph); - organicLayout = new mxOrganicLayoutImpl(graph); - organicLayout.setMaxIterations(10); - hierarchyLayout = new mxHierarchicalLayoutImpl(graph); + + fastOrganicLayout = lockedVertexModel.createLockedVertexWrapper(new mxFastOrganicLayout(graph)); + hierarchyLayout = lockedVertexModel.createLockedVertexWrapper(new mxHierarchicalLayout(graph)); + circleLayout = lockedVertexModel.createLockedVertexWrapper(new mxCircleLayout(graph) { + { + setResetEdges(true); + } + }); + organicLayout = lockedVertexModel.createLockedVertexWrapper(new mxOrganicLayout(graph) { + { + setResetEdges(true); + setMaxIterations(10); + } + }); //local method to configure layout buttons BiConsumer configure = (layoutButton, layout) -> { @@ -502,7 +510,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider .add(hierarchyLayoutButton) .addPreferredGap(LayoutStyle.RELATED) .add(circleLayoutButton) - .addPreferredGap(LayoutStyle.RELATED) + .addPreferredGap(LayoutStyle.UNRELATED) .add(jSeparator2, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE) .addPreferredGap(LayoutStyle.RELATED) .add(jLabel2) @@ -516,7 +524,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider .add(zoomActualButton, GroupLayout.PREFERRED_SIZE, 33, GroupLayout.PREFERRED_SIZE) .addPreferredGap(LayoutStyle.RELATED) .add(fitZoomButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE) - .addContainerGap(12, Short.MAX_VALUE)) + .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); toolbarLayout.setVerticalGroup(toolbarLayout.createParallelGroup(GroupLayout.LEADING) .add(toolbarLayout.createSequentialGroup() @@ -570,7 +578,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider private void applyLayout(mxGraphLayout layout) { currentLayout = layout; layoutButtons.forEach((layoutKey, button) - -> button.setFont(button.getFont().deriveFont(layoutKey == layout ? Font.BOLD : Font.PLAIN)) ); + -> button.setFont(button.getFont().deriveFont(layoutKey == layout ? Font.BOLD : Font.PLAIN))); morph(layout); } @@ -727,96 +735,6 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } } - final private class mxFastOrganicLayoutImpl extends mxFastOrganicLayout { - - mxFastOrganicLayoutImpl(mxGraph graph) { - super(graph); - } - - @Override - public boolean isVertexIgnored(Object vertex) { - return super.isVertexIgnored(vertex) - || lockedVertexModel.isVertexLocked((mxCell) vertex); - } - - @Override - public mxRectangle setVertexLocation(Object vertex, double x, double y) { - if (isVertexIgnored(vertex)) { - return getVertexBounds(vertex); - } else { - return super.setVertexLocation(vertex, x, y); - } - } - } - - final private class mxCircleLayoutImpl extends mxCircleLayout { - - mxCircleLayoutImpl(mxGraph graph) { - super(graph); - setResetEdges(true); - } - - @Override - public boolean isVertexIgnored(Object vertex) { - return super.isVertexIgnored(vertex) - || lockedVertexModel.isVertexLocked((mxCell) vertex); - } - - @Override - public mxRectangle setVertexLocation(Object vertex, double x, double y) { - if (isVertexIgnored(vertex)) { - return getVertexBounds(vertex); - } else { - return super.setVertexLocation(vertex, x, y); - } - } - } - - final private class mxOrganicLayoutImpl extends mxOrganicLayout { - - mxOrganicLayoutImpl(mxGraph graph) { - super(graph); - setResetEdges(true); - } - - @Override - public boolean isVertexIgnored(Object vertex) { - return super.isVertexIgnored(vertex) - || lockedVertexModel.isVertexLocked((mxCell) vertex); - } - - @Override - public mxRectangle setVertexLocation(Object vertex, double x, double y) { - if (isVertexIgnored(vertex)) { - return getVertexBounds(vertex); - } else { - return super.setVertexLocation(vertex, x, y); - } - } - } - - final private class mxHierarchicalLayoutImpl extends mxHierarchicalLayout { - - mxHierarchicalLayoutImpl(mxGraph graph) { - super(graph); - } - - @Override - public boolean isVertexIgnored(Object vertex) { - return super.isVertexIgnored(vertex) - || lockedVertexModel.isVertexLocked((mxCell) vertex); - } - - @Override - public mxRectangle setVertexLocation(Object vertex, double x, double y) { - if (isVertexIgnored(vertex)) { - return getVertexBounds(vertex); - } else { - return super.setVertexLocation(vertex, x, y); - } - } - } - private class CancelationListener implements ActionListener { private Future cancellable; @@ -908,4 +826,5 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } } } + } From 32868a97f1d49b0142ed703b1fbf016bcd6a0f7e Mon Sep 17 00:00:00 2001 From: millmanorama Date: Thu, 5 Apr 2018 12:06:13 +0200 Subject: [PATCH 02/11] WIP - broken --- .../communications/AbstractCVTAction.java | 47 ++++++++++ .../AccountDeviceInstanceNode.java | 54 ----------- .../autopsy/communications/Bundle.properties | 3 - .../autopsy/communications/CVTEvents.java | 2 +- .../communications/PinAccountsAction.java | 55 +++++++++++ .../ResetAndPinAccountsAction.java | 59 ++++++++++++ .../communications/UnpinAccountsAction.java | 55 +++++++++++ .../communications/VisualizationPanel.java | 94 +++++++------------ 8 files changed, 251 insertions(+), 118 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java create mode 100644 Core/src/org/sleuthkit/autopsy/communications/PinAccountsAction.java create mode 100644 Core/src/org/sleuthkit/autopsy/communications/ResetAndPinAccountsAction.java create mode 100644 Core/src/org/sleuthkit/autopsy/communications/UnpinAccountsAction.java diff --git a/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java b/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java new file mode 100644 index 0000000000..c2b43f2041 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java @@ -0,0 +1,47 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.communications; + +import java.util.Collection; +import javax.swing.AbstractAction; +import javax.swing.ImageIcon; +import javax.swing.JMenuItem; +import org.openide.util.Utilities; +import org.openide.util.actions.Presenter; + +/** + * + * + */ +abstract class AbstractCVTAction extends AbstractAction implements Presenter.Popup { + + /** + * Get the selected accounts that will be acted upon. + * + * @return The selected accounts + */ + Collection getSelectedAccounts() { + return Utilities.actionsGlobalContext().lookupAll(AccountDeviceInstanceKey.class); + } + + @Override + final public void putValue(String key, Object newValue) { + super.putValue(key, newValue); + } + + @Override + public JMenuItem getPopupPresenter() { + JMenuItem presenter = new JMenuItem(this); + presenter.setText(getActionDisplayName()); + presenter.setIcon(getIcon()); + return presenter; + } + + abstract String getActionDisplayName(); + + abstract ImageIcon getIcon(); + +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceNode.java b/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceNode.java index 40cb15d27d..044cec322f 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceNode.java @@ -18,17 +18,13 @@ */ package org.sleuthkit.autopsy.communications; -import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; -import javax.swing.AbstractAction; import javax.swing.Action; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; -import org.openide.util.Utilities; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.datamodel.NodeProperty; import org.sleuthkit.datamodel.Account; @@ -106,54 +102,4 @@ final class AccountDeviceInstanceNode extends AbstractNode { actions.add(ResetAndPinAccountsAction.getInstance()); return actions.toArray(new Action[actions.size()]); } - - /** - * Action that pins the selected AccountDeviceInstances to the - * visualization. - */ - static private class PinAccountsAction extends AbstractAction { - - private static final long serialVersionUID = 1L; - private final static PinAccountsAction instance = new PinAccountsAction(); - - private static PinAccountsAction getInstance() { - return instance; - } - - private PinAccountsAction() { - super("Add Account(s) to Visualization"); - } - - @Override - public void actionPerformed(ActionEvent e) { - Collection lookupAll = - Utilities.actionsGlobalContext().lookupAll(AccountDeviceInstanceKey.class); - CVTEvents.getCVTEventBus().post(new CVTEvents.PinAccountsEvent(lookupAll, false)); - } - } - - /** - * Action that pins the selected AccountDeviceInstances to the - * visualization. - */ - static private class ResetAndPinAccountsAction extends AbstractAction { - - private static final long serialVersionUID = 1L; - private final static ResetAndPinAccountsAction instance = new ResetAndPinAccountsAction(); - - private static ResetAndPinAccountsAction getInstance() { - return instance; - } - - private ResetAndPinAccountsAction() { - super("Visualize Account(s)"); - } - - @Override - public void actionPerformed(ActionEvent e) { - Collection lookupAll = - Utilities.actionsGlobalContext().lookupAll(AccountDeviceInstanceKey.class); - CVTEvents.getCVTEventBus().post(new CVTEvents.PinAccountsEvent(lookupAll, true)); - } - } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties index 559e9bba86..ea3049f895 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties @@ -36,9 +36,6 @@ VisualizationPanel.zoomInButton.toolTipText=Zoom in VisualizationPanel.zoomInButton.text= VisualizationPanel.zoomOutButton.toolTipText=Zoom out VisualizationPanel.zoomOutButton.text= -# To change this license header, choose License Headers in Project Properties. -# To change this template file, choose Tools | Templates -# and open the template in the editor. VisualizationPanel.circleLayoutButton.text=Circle VisualizationPanel.organicLayoutButton.text=Organic VisualizationPanel.fastOrganicLayoutButton.text=Fast Organic diff --git a/Core/src/org/sleuthkit/autopsy/communications/CVTEvents.java b/Core/src/org/sleuthkit/autopsy/communications/CVTEvents.java index e0f945bb69..54e5b8a1ef 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/CVTEvents.java +++ b/Core/src/org/sleuthkit/autopsy/communications/CVTEvents.java @@ -79,7 +79,7 @@ final class CVTEvents { return accountDeviceInstances; } - public UnpinAccountsEvent(Set accountDeviceInstances) { + UnpinAccountsEvent(Collection accountDeviceInstances) { this.accountDeviceInstances = ImmutableSet.copyOf(accountDeviceInstances); } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/PinAccountsAction.java b/Core/src/org/sleuthkit/autopsy/communications/PinAccountsAction.java new file mode 100644 index 0000000000..d820373284 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/PinAccountsAction.java @@ -0,0 +1,55 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.communications; + +import java.awt.event.ActionEvent; +import javax.swing.ImageIcon; +import org.openide.util.ImageUtilities; +import org.openide.util.NbBundle; + +@NbBundle.Messages({"PinAccountsAction.pluralText=Add Selected Accounts to Visualization", + "PinAccountsAction.singularText=Add Selected Account to Visualization"}) +final class PinAccountsAction extends AbstractCVTAction { + + static private final ImageIcon ICON = ImageUtilities.loadImageIcon( + "/org/sleuthkit/autopsy/communications/images/marker--plus.png", false); + private static final String SINGULAR_TEXT = Bundle.PinAccountsAction_singularText(); + private static final String PLURAL_TEXT = Bundle.PinAccountsAction_pluralText(); + + private static final PinAccountsAction instance = new PinAccountsAction(); + + static PinAccountsAction getInstance() { + return instance; + } + + @Override + public void actionPerformed(ActionEvent e) { + CVTEvents.getCVTEventBus().post(new CVTEvents.PinAccountsEvent(getSelectedAccounts(), false)); + } + + @Override + protected String getActionDisplayName() { + return getSelectedAccounts().size() > 1 ? PLURAL_TEXT : SINGULAR_TEXT; + } + + @Override + ImageIcon getIcon() { + return ICON; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/ResetAndPinAccountsAction.java b/Core/src/org/sleuthkit/autopsy/communications/ResetAndPinAccountsAction.java new file mode 100644 index 0000000000..a42b2882ed --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/ResetAndPinAccountsAction.java @@ -0,0 +1,59 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.communications; + +import java.awt.event.ActionEvent; +import javax.swing.ImageIcon; +import org.openide.util.ImageUtilities; +import org.openide.util.NbBundle; + +/** + * + */ +@NbBundle.Messages(value = {"ResetAndPinAccountsAction.singularText=Visualize Only Selected Account", + "ResetAndPinAccountsAction.pluralText=Visualize Only Selected Accounts"}) +final class ResetAndPinAccountsAction extends AbstractCVTAction { + + private static final ImageIcon ICON = ImageUtilities.loadImageIcon( + "/org/sleuthkit/autopsy/communications/images/marker--pin.png", false); + private static final String SINGULAR_TEXT = Bundle.ResetAndPinAccountsAction_singularText(); + private static final String PLURAL_TEXT = Bundle.ResetAndPinAccountsAction_pluralText(); + + private static final ResetAndPinAccountsAction instance = new ResetAndPinAccountsAction(); + + static ResetAndPinAccountsAction getInstance() { + return instance; + } + + @Override + public void actionPerformed(ActionEvent e) { + CVTEvents.getCVTEventBus().post(new CVTEvents.PinAccountsEvent(getSelectedAccounts(), true)); + } + + @Override + protected String getActionDisplayName() { + return getSelectedAccounts().size() > 1 ? PLURAL_TEXT : SINGULAR_TEXT; + } + + @Override + ImageIcon getIcon() { + return ICON; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/UnpinAccountsAction.java b/Core/src/org/sleuthkit/autopsy/communications/UnpinAccountsAction.java new file mode 100644 index 0000000000..357f5a0451 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/UnpinAccountsAction.java @@ -0,0 +1,55 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.communications; + +import java.awt.event.ActionEvent; +import javax.swing.ImageIcon; +import org.openide.util.ImageUtilities; +import org.openide.util.NbBundle; + +@NbBundle.Messages({"UnpinAccountsAction.pluralText=Remove Selected Accounts", + "UnpinAccountsAction.singularText=Remove Selected Account"}) +final class UnpinAccountsAction extends AbstractCVTAction { + + static final private ImageIcon ICON = ImageUtilities.loadImageIcon( + "/org/sleuthkit/autopsy/communications/images/marker--minus.png", false); + private static final String SINGULAR_TEXT = Bundle.UnpinAccountsAction_singularText(); + private static final String PLURAL_TEXT = Bundle.UnpinAccountsAction_pluralText(); + + private static final UnpinAccountsAction instance = new UnpinAccountsAction(); + + static UnpinAccountsAction getInstance() { + return instance; + } + + @Override + public void actionPerformed(final ActionEvent event) { + CVTEvents.getCVTEventBus().post(new CVTEvents.UnpinAccountsEvent(getSelectedAccounts())); + } + + @Override + String getActionDisplayName() { + return getSelectedAccounts().size() > 1 ? PLURAL_TEXT : SINGULAR_TEXT; + } + + @Override + ImageIcon getIcon() { + return ICON; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java index cd75ab5185..fa095fd0a8 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java @@ -51,7 +51,6 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyVetoException; import java.text.DecimalFormat; import java.util.Arrays; -import static java.util.Collections.singleton; import java.util.EnumSet; import java.util.HashSet; import java.util.List; @@ -106,12 +105,6 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(VisualizationPanel.class.getName()); private static final String BASE_IMAGE_PATH = "/org/sleuthkit/autopsy/communications/images"; - static final private ImageIcon pinIcon - = new ImageIcon(VisualizationPanel.class.getResource(BASE_IMAGE_PATH + "/marker--pin.png")); - static final private ImageIcon addPinIcon - = new ImageIcon(VisualizationPanel.class.getResource(BASE_IMAGE_PATH + "/marker--plus.png")); - static final private ImageIcon unpinIcon - = new ImageIcon(VisualizationPanel.class.getResource(BASE_IMAGE_PATH + "/marker--minus.png")); static final private ImageIcon unlockIcon = new ImageIcon(VisualizationPanel.class.getResource(BASE_IMAGE_PATH + "/lock_large_unlocked.png")); static final private ImageIcon lockIcon @@ -132,6 +125,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider private final mxUndoManager undoManager = new mxUndoManager(); private final mxRubberband rubberband; + private final mxFastOrganicLayout fastOrganicLayout; private final mxCircleLayout circleLayout; private final mxOrganicLayout organicLayout; @@ -199,52 +193,40 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider @Override public void mouseClicked(final MouseEvent event) { super.mouseClicked(event); - if (SwingUtilities.isRightMouseButton(event)) { - final mxCell cellAt = (mxCell) graphComponent.getCellAt(event.getX(), event.getY()); - if (cellAt != null && cellAt.isVertex()) { - final JPopupMenu jPopupMenu = new JPopupMenu(); - final AccountDeviceInstanceKey adiKey = (AccountDeviceInstanceKey) cellAt.getValue(); + SwingUtilities.invokeLater(() -> { + if (SwingUtilities.isRightMouseButton(event)) { + final mxCell cellAt = (mxCell) graphComponent.getCellAt(event.getX(), event.getY()); + if (cellAt != null && cellAt.isVertex()) { + final JPopupMenu jPopupMenu = new JPopupMenu(); + final AccountDeviceInstanceKey adiKey = (AccountDeviceInstanceKey) cellAt.getValue(); - if (lockedVertexModel.isVertexLocked(cellAt)) { - jPopupMenu.add(new JMenuItem(new AbstractAction("UnLock " + cellAt.getId(), unlockIcon) { - @Override - public void actionPerformed(final ActionEvent event) { - lockedVertexModel.unlockVertex(cellAt); - } - })); - } else { - jPopupMenu.add(new JMenuItem(new AbstractAction("Lock " + cellAt.getId(), lockIcon) { - @Override - public void actionPerformed(final ActionEvent event) { - lockedVertexModel.lockVertex(cellAt); - } - })); + if (lockedVertexModel.isVertexLocked(cellAt)) { + jPopupMenu.add(new JMenuItem(new AbstractAction("UnLock", unlockIcon) { + @Override + public void actionPerformed(final ActionEvent event) { + lockedVertexModel.unlockVertex(cellAt); + } + })); + } else { + jPopupMenu.add(new JMenuItem(new AbstractAction("Lock", lockIcon) { + @Override + public void actionPerformed(final ActionEvent event) { + lockedVertexModel.lockVertex(cellAt); + } + })); + } + if (pinnedAccountModel.isAccountPinned(adiKey)) { + jPopupMenu.add(UnpinAccountsAction.getInstance().getPopupPresenter()); + } else { + jPopupMenu.add(PinAccountsAction.getInstance().getPopupPresenter()); + jPopupMenu.add(ResetAndPinAccountsAction.getInstance().getPopupPresenter()); + } + jPopupMenu.show(graphComponent.getGraphControl(), event.getX(), event.getY()); } - if (pinnedAccountModel.isAccountPinned(adiKey)) { - jPopupMenu.add(new JMenuItem(new AbstractAction("Unpin " + cellAt.getId(), unpinIcon) { - @Override - public void actionPerformed(final ActionEvent event) { - handleUnPinEvent(new CVTEvents.UnpinAccountsEvent(singleton((AccountDeviceInstanceKey) cellAt.getValue()))); - } - })); - } else { - jPopupMenu.add(new JMenuItem(new AbstractAction("Pin " + cellAt.getId(), addPinIcon) { - @Override - public void actionPerformed(final ActionEvent event) { - handlePinEvent(new CVTEvents.PinAccountsEvent(singleton((AccountDeviceInstanceKey) cellAt.getValue()), false)); - } - })); - jPopupMenu.add(new JMenuItem(new AbstractAction("Pin only " + cellAt.getId(), pinIcon) { - @Override - public void actionPerformed(final ActionEvent event) { - handlePinEvent(new CVTEvents.PinAccountsEvent(singleton((AccountDeviceInstanceKey) cellAt.getValue()), true)); - } - })); - } - jPopupMenu.show(graphComponent.getGraphControl(), event.getX(), event.getY()); } - } + }); } + }); final MessageBrowser messageBrowser = new MessageBrowser(vizEM, gacEM); @@ -255,7 +237,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider ExplorerUtils.createLookup(vizEM, getActionMap())); //feed selection to explorermanager - graph.getSelectionModel().addListener(null, new SelectionListener()); + graph.getSelectionModel().addListener(mxEvent.CHANGE, new SelectionListener()); final mxEventSource.mxIEventListener undoListener = (Object sender, mxEventObject evt) -> undoManager.undoableEditHappened((mxUndoableEdit) evt.getProperty("edit")); @@ -277,7 +259,6 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider rebuildGraph(); // Updates the display graph.getModel().endUpdate(); - } @Subscribe @@ -290,7 +271,6 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider rebuildGraph(); // Updates the display graph.getModel().endUpdate(); - } @Subscribe @@ -302,7 +282,6 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider rebuildGraph(); // Updates the display graph.getModel().endUpdate(); - } @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @@ -328,13 +307,12 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider graph.resetGraph(); rebuildGraph(); } else { - morph(fastOrganicLayout); + morph(fastOrganicLayout); } } }); worker.execute(); - } } @@ -372,11 +350,6 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider }); } - @Override - public void removeNotify() { - super.removeNotify(); - } - /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -901,4 +874,5 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } } + } From 1882690b727012cf0e4833d272360038716779ed Mon Sep 17 00:00:00 2001 From: millmanorama Date: Fri, 6 Apr 2018 15:55:44 +0200 Subject: [PATCH 03/11] refactor actions to support multiselect in VisualizationPanel via the ActionsGlobalContext lookup --- .../communications/AbstractCVTAction.java | 41 ++++++++--- .../communications/MessageBrowser.java | 4 +- .../autopsy/communications/SelectionNode.java | 18 +++-- .../communications/VisualizationPanel.java | 71 +++++++++---------- 4 files changed, 79 insertions(+), 55 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java b/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java index c2b43f2041..82cbe5e0f8 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java +++ b/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.sleuthkit.autopsy.communications; @@ -14,7 +27,9 @@ import org.openide.util.actions.Presenter; /** * - * + * Base class for actions that act on the selected AccountDeviceInstanceKeys. + * getPopupPresenter() provides a JMenuItem that works (i.e., has an icon) in + * custom context menus and also in the Netbeans Explorer views. */ abstract class AbstractCVTAction extends AbstractAction implements Presenter.Popup { @@ -24,12 +39,8 @@ abstract class AbstractCVTAction extends AbstractAction implements Presenter.Pop * @return The selected accounts */ Collection getSelectedAccounts() { - return Utilities.actionsGlobalContext().lookupAll(AccountDeviceInstanceKey.class); - } - - @Override - final public void putValue(String key, Object newValue) { - super.putValue(key, newValue); + final Collection lookupAll = Utilities.actionsGlobalContext().lookupAll(AccountDeviceInstanceKey.class); + return lookupAll; } @Override @@ -40,8 +51,18 @@ abstract class AbstractCVTAction extends AbstractAction implements Presenter.Pop return presenter; } + /** + * The name/text of the action as displayed in a menu. + * + * @return The diaplay name of this action + */ abstract String getActionDisplayName(); + /** + * The icon to use for this icon. + * + * @return An ImageIcon used to represent this action. + */ abstract ImageIcon getIcon(); } diff --git a/Core/src/org/sleuthkit/autopsy/communications/MessageBrowser.java b/Core/src/org/sleuthkit/autopsy/communications/MessageBrowser.java index 68309f5195..7c0bf99c62 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/MessageBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/communications/MessageBrowser.java @@ -151,10 +151,10 @@ public final class MessageBrowser extends JPanel implements ExplorerManager.Prov //Use lookup here? final AccountDeviceInstanceNode adiNode = (AccountDeviceInstanceNode) selectedNodes[0]; - final Set accountDeviceInstances = new HashSet<>(); + final Set accountDeviceInstances = new HashSet<>(); for (final Node n : selectedNodes) { //Use lookup here? - accountDeviceInstances.add(((AccountDeviceInstanceNode) n).getAccountDeviceInstance()); + accountDeviceInstances.add(((AccountDeviceInstanceNode) n).getAccountDeviceInstanceKey()); } return SelectionNode.createFromAccounts(accountDeviceInstances, adiNode.getFilter(), adiNode.getCommsManager()); } diff --git a/Core/src/org/sleuthkit/autopsy/communications/SelectionNode.java b/Core/src/org/sleuthkit/autopsy/communications/SelectionNode.java index 40739b49cc..be564c01cc 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/SelectionNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/SelectionNode.java @@ -20,14 +20,18 @@ package org.sleuthkit.autopsy.communications; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; import java.util.logging.Level; +import java.util.stream.Collectors; import org.openide.nodes.AbstractNode; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; +import org.openide.util.Lookup; +import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AccountDeviceInstance; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -44,23 +48,27 @@ import org.sleuthkit.datamodel.TskCoreException; */ final class SelectionNode extends AbstractNode { - private SelectionNode(Children children) { - super(children); + SelectionNode(Children children, Lookup lookup) { + super(children, lookup); } static SelectionNode createFromAccountsAndRelationships( Set edgeRelationshipArtifacts, - Set accountDeviceInstances, + Set accountDeviceInstanceKeys, CommunicationsFilter filter, CommunicationsManager commsManager) { + Set accountDeviceInstances = accountDeviceInstanceKeys.stream() + .map(AccountDeviceInstanceKey::getAccountDeviceInstance) + .collect(Collectors.toSet()); + SelectionNode node = new SelectionNode(Children.create( new RelationshipChildren( edgeRelationshipArtifacts, accountDeviceInstances, commsManager, filter), - true)); + true), Lookups.fixed(accountDeviceInstanceKeys.toArray())); //This is not good for internationalization!!! String name = ""; @@ -82,7 +90,7 @@ final class SelectionNode extends AbstractNode { } static SelectionNode createFromAccounts( - Set accountDeviceInstances, + Set accountDeviceInstances, CommunicationsFilter filter, CommunicationsManager commsManager) { diff --git a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java index fa095fd0a8..559bdf2bd5 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java @@ -193,48 +193,47 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider @Override public void mouseClicked(final MouseEvent event) { super.mouseClicked(event); - SwingUtilities.invokeLater(() -> { - if (SwingUtilities.isRightMouseButton(event)) { - final mxCell cellAt = (mxCell) graphComponent.getCellAt(event.getX(), event.getY()); - if (cellAt != null && cellAt.isVertex()) { - final JPopupMenu jPopupMenu = new JPopupMenu(); - final AccountDeviceInstanceKey adiKey = (AccountDeviceInstanceKey) cellAt.getValue(); + if (SwingUtilities.isRightMouseButton(event)) { + final mxCell cellAt = (mxCell) graphComponent.getCellAt(event.getX(), event.getY()); + if (cellAt != null && cellAt.isVertex()) { + final JPopupMenu jPopupMenu = new JPopupMenu(); + final AccountDeviceInstanceKey adiKey = (AccountDeviceInstanceKey) cellAt.getValue(); - if (lockedVertexModel.isVertexLocked(cellAt)) { - jPopupMenu.add(new JMenuItem(new AbstractAction("UnLock", unlockIcon) { - @Override - public void actionPerformed(final ActionEvent event) { - lockedVertexModel.unlockVertex(cellAt); - } - })); - } else { - jPopupMenu.add(new JMenuItem(new AbstractAction("Lock", lockIcon) { - @Override - public void actionPerformed(final ActionEvent event) { - lockedVertexModel.lockVertex(cellAt); - } - })); - } - if (pinnedAccountModel.isAccountPinned(adiKey)) { - jPopupMenu.add(UnpinAccountsAction.getInstance().getPopupPresenter()); - } else { - jPopupMenu.add(PinAccountsAction.getInstance().getPopupPresenter()); - jPopupMenu.add(ResetAndPinAccountsAction.getInstance().getPopupPresenter()); - } - jPopupMenu.show(graphComponent.getGraphControl(), event.getX(), event.getY()); + if (lockedVertexModel.isVertexLocked(cellAt)) { + jPopupMenu.add(new JMenuItem(new AbstractAction("UnLock", unlockIcon) { + @Override + public void actionPerformed(final ActionEvent event) { + lockedVertexModel.unlockVertex(cellAt); + } + })); + } else { + jPopupMenu.add(new JMenuItem(new AbstractAction("Lock", lockIcon) { + @Override + public void actionPerformed(final ActionEvent event) { + lockedVertexModel.lockVertex(cellAt); + } + })); } + if (pinnedAccountModel.isAccountPinned(adiKey)) { + jPopupMenu.add(UnpinAccountsAction.getInstance().getPopupPresenter()); + } else { + jPopupMenu.add(PinAccountsAction.getInstance().getPopupPresenter()); + jPopupMenu.add(ResetAndPinAccountsAction.getInstance().getPopupPresenter()); + } + jPopupMenu.show(graphComponent.getGraphControl(), event.getX(), event.getY()); } - }); + } } - }); + final MessageBrowser messageBrowser = new MessageBrowser(vizEM, gacEM); splitPane.setRightComponent(messageBrowser); proxyLookup = new ProxyLookup( - messageBrowser.getLookup(), - ExplorerUtils.createLookup(vizEM, getActionMap())); + ExplorerUtils.createLookup(vizEM, getActionMap()), + messageBrowser.getLookup() + ); //feed selection to explorermanager graph.getSelectionModel().addListener(mxEvent.CHANGE, new SelectionListener()); @@ -246,7 +245,6 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } @Override - public Lookup getLookup() { return proxyLookup; } @@ -275,7 +273,6 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider @Subscribe void handleFilterEvent(final CVTEvents.FilterChangeEvent filterChangeEvent) { - graph.getModel().beginUpdate(); graph.clear(); currentFilter = filterChangeEvent.getNewFilter(); @@ -733,7 +730,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider if (selectionCells.length > 0) { mxICell[] selectedCells = Arrays.asList(selectionCells).toArray(new mxCell[selectionCells.length]); HashSet relationshipSources = new HashSet<>(); - HashSet adis = new HashSet<>(); + HashSet adis = new HashSet<>(); for (mxICell cell : selectedCells) { if (cell.isEdge()) { mxICell source = (mxICell) graph.getModel().getTerminal(cell, true); @@ -750,7 +747,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider logger.log(Level.SEVERE, " Error getting relationsips....", tskCoreException); } } else if (cell.isVertex()) { - adis.add(((AccountDeviceInstanceKey) cell.getValue()).getAccountDeviceInstance()); + adis.add((AccountDeviceInstanceKey) cell.getValue()); } } @@ -872,7 +869,5 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider cancellable.cancel(true); progress.finish(); } - } - } From f3161c7af6607d9156be14cf783efa486b973cdc Mon Sep 17 00:00:00 2001 From: millmanorama Date: Sat, 7 Apr 2018 14:56:15 +0200 Subject: [PATCH 04/11] multiselect for locking. Not updating the icon properly... --- .../communications/CommunicationsGraph.java | 28 ++--- .../communications/LockedVertexModel.java | 46 ++++--- .../communications/PinnedAccountModel.java | 7 +- .../communications/VisualizationPanel.java | 116 ++++++++++++++---- 4 files changed, 124 insertions(+), 73 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java b/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java index f274ab00d7..98d9aa7d88 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java +++ b/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java @@ -38,6 +38,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; +import java.util.function.Consumer; import java.util.logging.Level; import javax.swing.SwingWorker; import org.sleuthkit.autopsy.coreutils.Logger; @@ -84,17 +85,19 @@ final class CommunicationsGraph extends mxGraph { mxStylesheet.getDefaultEdgeStyle().put(mxConstants.STYLE_STARTARROW, mxConstants.NONE); } - /* Map from type specific account identifier to mxCell(vertex). */ + /** Map from type specific account identifier to mxCell(vertex). */ private final Map nodeMap = new HashMap<>(); - /* Map from relationship source (Content) to mxCell (edge). */ + /** Map from relationship source (Content) to mxCell (edge). */ private final Multimap edgeMap = MultimapBuilder.hashKeys().hashSetValues().build(); private final LockedVertexModel lockedVertexModel; private final PinnedAccountModel pinnedAccountModel; - CommunicationsGraph() { + CommunicationsGraph(PinnedAccountModel pinnedAccountModel, LockedVertexModel lockedVertexModel) { super(mxStylesheet); + this.pinnedAccountModel =pinnedAccountModel; + this.lockedVertexModel = lockedVertexModel; //set fixed properties of graph. setAutoSizeCells(true); setCellsCloneable(false); @@ -113,21 +116,6 @@ final class CommunicationsGraph extends mxGraph { setKeepEdgesInBackground(true); setResetEdgesOnMove(true); setHtmlLabels(true); - - lockedVertexModel = new LockedVertexModel(); - lockedVertexModel.registerhandler((LockedVertexModel.VertexLockEvent event) -> { - if (event.isVertexLocked()) { - getView().clear(event.getVertex(), true, true); - getView().validate(); - } else { - final mxCellState state = getView().getState(event.getVertex(), true); - getView().updateLabel(state); - getView().updateLabelBounds(state); - getView().updateBoundingBox(state); - } - }); - - pinnedAccountModel = new PinnedAccountModel(this); } /** @@ -299,7 +287,7 @@ final class CommunicationsGraph extends mxGraph { int total = relationshipCounts.size(); int k = 0; - String progressText = ""; + String progressText = ""; progress.switchToDeterminate("", 0, total); for (Map.Entry entry : relationshipCounts.entrySet()) { Long count = entry.getValue(); @@ -308,7 +296,7 @@ final class CommunicationsGraph extends mxGraph { AccountDeviceInstanceKey account2 = relatedAccounts.get(relationshipKey.getSecond()); if (pinnedAccountModel.isAccountPinned(account1) - || pinnedAccountModel.isAccountPinned(account2)) { + || pinnedAccountModel.isAccountPinned(account2)) { mxCell addEdge = addOrUpdateEdge(count, account1, account2); progressText = addEdge.getId(); } diff --git a/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java b/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java index f26e9515b3..ad189a8bea 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java @@ -18,12 +18,22 @@ */ package org.sleuthkit.autopsy.communications; +import com.google.common.collect.ImmutableSet; import com.google.common.eventbus.EventBus; import com.mxgraph.model.mxCell; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Set; -class LockedVertexModel { +/** + * Model of which vertices in a graph are locked ( not moveable by layout + * algorithms). + * + */ +final class LockedVertexModel { void registerhandler(EventHandler handler) { eventBus.register(handler); @@ -42,30 +52,26 @@ class LockedVertexModel { */ private final Set lockedVertices = new HashSet<>(); - LockedVertexModel() { - } - /** - * Lock the given vertex so that applying a layout algorithm doesn't move - * it. The user can still manually position the vertex. + * Lock the given vertices so that applying a layout algorithm doesn't move + * them. The user can still manually position the vertices. * * @param vertex The vertex to lock. */ - void lockVertex(mxCell vertex) { - lockedVertices.add(vertex); - eventBus.post(new VertexLockEvent(vertex, true)); - + void lock(Collection vertices) { + lockedVertices.addAll(vertices); + eventBus.post(new VertexLockEvent(true, vertices)); } /** - * Lock the given vertex so that applying a layout algorithm can move it. + * Unlock the given vertices so that applying a layout algorithm can move + * them. * * @param vertex The vertex to unlock. */ - void unlockVertex(mxCell vertex) { - lockedVertices.remove(vertex); - eventBus.post(new VertexLockEvent(vertex, false)); - + void unlock(Collection vertices) { + lockedVertices.removeAll(vertices); + eventBus.post(new VertexLockEvent(false, vertices)); } boolean isVertexLocked(mxCell vertex) { @@ -79,10 +85,10 @@ class LockedVertexModel { static class VertexLockEvent { - private final mxCell vertex; + private final Set vertices; - public mxCell getVertex() { - return vertex; + public Set getVertices() { + return vertices; } public boolean isVertexLocked() { @@ -90,8 +96,8 @@ class LockedVertexModel { } private final boolean locked; - VertexLockEvent(mxCell vertex, boolean locked) { - this.vertex = vertex; + VertexLockEvent(boolean locked, Collection< mxCell> vertices) { + this.vertices = ImmutableSet.copyOf(vertices); this.locked = locked; } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/PinnedAccountModel.java b/Core/src/org/sleuthkit/autopsy/communications/PinnedAccountModel.java index d5f7a7cc03..beff35173d 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/PinnedAccountModel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/PinnedAccountModel.java @@ -25,17 +25,12 @@ import java.util.Set; class PinnedAccountModel { /** - * Set of AccountDeviceInstanceKeys that are 'Pinned' to this graph. Pinned + * Set of AccountDeviceInstanceKeys that are 'Pinned' to the graph. Pinned * accounts are shown regardless of filters, and accounts that are related * to pinned accounts and pass the filters are show. Pinning accounts is the * primary way to populate the graph. */ private final Set pinnedAccountDevices = new HashSet<>(); - private final CommunicationsGraph graph; - - PinnedAccountModel(CommunicationsGraph graph) { - this.graph = graph; - } boolean isAccountPinned(AccountDeviceInstanceKey account) { return pinnedAccountDevices.contains(account); diff --git a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java index 559bdf2bd5..d33ca867d7 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java @@ -36,7 +36,9 @@ import com.mxgraph.util.mxPoint; import com.mxgraph.util.mxRectangle; import com.mxgraph.util.mxUndoManager; import com.mxgraph.util.mxUndoableEdit; +import com.mxgraph.view.mxCellState; import com.mxgraph.view.mxGraph; +import com.mxgraph.view.mxGraphView; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Cursor; @@ -54,8 +56,11 @@ import java.util.Arrays; import java.util.EnumSet; import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.Future; import java.util.logging.Level; +import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.swing.AbstractAction; import javax.swing.ImageIcon; import javax.swing.JButton; @@ -83,7 +88,6 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.progress.ModalDialogProgressIndicator; -import org.sleuthkit.datamodel.AccountDeviceInstance; import org.sleuthkit.datamodel.CommunicationsFilter; import org.sleuthkit.datamodel.CommunicationsManager; import org.sleuthkit.datamodel.Content; @@ -99,7 +103,6 @@ import org.sleuthkit.datamodel.TskCoreException; * CVTTopComponent when this tab is active allowing for context sensitive * actions to work correctly. */ -@NbBundle.Messages("VisualizationPanel.cancelButton.text=Cancel") final public class VisualizationPanel extends JPanel implements Lookup.Provider { private static final long serialVersionUID = 1L; @@ -110,6 +113,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider static final private ImageIcon lockIcon = new ImageIcon(VisualizationPanel.class.getResource(BASE_IMAGE_PATH + "/lock_large_locked.png")); + @NbBundle.Messages("VisualizationPanel.cancelButton.text=Cancel") private static final String CANCEL = Bundle.VisualizationPanel_cancelButton_text(); private final ExplorerManager vizEM = new ExplorerManager(); @@ -124,7 +128,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider private final CommunicationsGraph graph; private final mxUndoManager undoManager = new mxUndoManager(); - private final mxRubberband rubberband; + private final mxRubberband rubberband; //NOPMD We keep a referenec as insurance to prevent garbage collection private final mxFastOrganicLayout fastOrganicLayout; private final mxCircleLayout circleLayout; @@ -133,14 +137,13 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider @ThreadConfined(type = ThreadConfined.ThreadType.AWT) private SwingWorker worker; - private final PinnedAccountModel pinnedAccountModel; - private final LockedVertexModel lockedVertexModel; + private final PinnedAccountModel pinnedAccountModel = new PinnedAccountModel(); + private final LockedVertexModel lockedVertexModel = new LockedVertexModel(); public VisualizationPanel() { initComponents(); - graph = new CommunicationsGraph(); - pinnedAccountModel = graph.getPinnedAccountModel(); - lockedVertexModel = graph.getLockedVertexModel(); + + graph = new CommunicationsGraph(pinnedAccountModel, lockedVertexModel); fastOrganicLayout = new mxFastOrganicLayoutImpl(graph); circleLayout = new mxCircleLayoutImpl(graph); @@ -159,9 +162,26 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider graphComponent.setBackground(Color.WHITE); borderLayoutPanel.add(graphComponent, BorderLayout.CENTER); - //install rubber band selection handler + //install rubber band other handlers rubberband = new mxRubberband(graphComponent); + lockedVertexModel.registerhandler((LockedVertexModel.VertexLockEvent event) -> { + final Set vertices = event.getVertices(); + mxGraphView view = graph.getView(); + if (event.isVertexLocked()) { + vertices.forEach(vertex -> view.clear(vertex, true, true)); + view.validate(); + } else { + vertices.forEach(vertex -> { + final mxCellState state = view.getState(vertex, true); + view.updateLabel(state); + view.updateLabelBounds(state); + view.updateBoundingBox(state); + }); + } + graphComponent.getGraphControl().repaint(); + }); + final mxEventSource.mxIEventListener scaleListener = (Object sender, mxEventObject evt) -> zoomLabel.setText(DecimalFormat.getPercentInstance().format(graph.getView().getScale())); graph.getView().addListener(mxEvent.SCALE, scaleListener); @@ -199,20 +219,16 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider final JPopupMenu jPopupMenu = new JPopupMenu(); final AccountDeviceInstanceKey adiKey = (AccountDeviceInstanceKey) cellAt.getValue(); + Set selectedVertices + = Stream.of(graph.getSelectionModel().getCells()) + .map(mxCell.class::cast) + .filter(mxCell::isVertex) + .collect(Collectors.toSet()); + if (lockedVertexModel.isVertexLocked(cellAt)) { - jPopupMenu.add(new JMenuItem(new AbstractAction("UnLock", unlockIcon) { - @Override - public void actionPerformed(final ActionEvent event) { - lockedVertexModel.unlockVertex(cellAt); - } - })); + jPopupMenu.add(new JMenuItem(new UnlockAction(selectedVertices))); } else { - jPopupMenu.add(new JMenuItem(new AbstractAction("Lock", lockIcon) { - @Override - public void actionPerformed(final ActionEvent event) { - lockedVertexModel.lockVertex(cellAt); - } - })); + jPopupMenu.add(new JMenuItem(new LockAction(selectedVertices))); } if (pinnedAccountModel.isAccountPinned(adiKey)) { jPopupMenu.add(UnpinAccountsAction.getInstance().getPopupPresenter()); @@ -224,6 +240,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } } } + }); final MessageBrowser messageBrowser = new MessageBrowser(vizEM, gacEM); @@ -650,16 +667,18 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } + @NbBundle.Messages({"Visualization.computingLayout=Computing Layout"}) private void morph(mxIGraphLayout layout) { // layout using morphing graph.getModel().beginUpdate(); CancelationListener cancelationListener = new CancelationListener(); - ModalDialogProgressIndicator progress = new ModalDialogProgressIndicator(windowAncestor, "Computing layout", new String[]{CANCEL}, CANCEL, cancelationListener); + ModalDialogProgressIndicator progress = new ModalDialogProgressIndicator(windowAncestor, + Bundle.Visualization_computingLayout(), new String[]{CANCEL}, CANCEL, cancelationListener); SwingWorker morphWorker = new SwingWorker() { @Override protected Void doInBackground() { - progress.start("Computing layout"); + progress.start(Bundle.Visualization_computingLayout()); layout.execute(graph.getDefaultParent()); if (isCancelled()) { progress.finish(); @@ -719,6 +738,10 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider private JButton zoomOutButton; // End of variables declaration//GEN-END:variables + /** + * Listens to graph selection model and updates ExplorerManager to reflect + * changes in selection. + */ final private class SelectionListener implements mxEventSource.mxIEventListener { @SuppressWarnings("unchecked") @@ -776,7 +799,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } @Override - public mxRectangle setVertexLocation(Object vertex, double x, double y) { + public mxRectangle setVertexLocation(Object vertex, double x, double y) { //NOPMD x,y variable names are standard if (isVertexIgnored(vertex)) { return getVertexBounds(vertex); } else { @@ -799,7 +822,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } @Override - public mxRectangle setVertexLocation(Object vertex, double x, double y) { + public mxRectangle setVertexLocation(Object vertex, double x, double y) { //NOPMD x,y variable names are standard if (isVertexIgnored(vertex)) { return getVertexBounds(vertex); } else { @@ -822,7 +845,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } @Override - public mxRectangle setVertexLocation(Object vertex, double x, double y) { + public mxRectangle setVertexLocation(Object vertex, double x, double y) { //NOPMD x,y variable names are standard if (isVertexIgnored(vertex)) { return getVertexBounds(vertex); } else { @@ -844,7 +867,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } @Override - public mxRectangle setVertexLocation(Object vertex, double x, double y) { + public mxRectangle setVertexLocation(Object vertex, double x, double y) { //NOPMD x,y variable names are standard if (isVertexIgnored(vertex)) { return getVertexBounds(vertex); } else { @@ -870,4 +893,43 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider progress.finish(); } } + + @NbBundle.Messages({ + "VisualizationPanel.unlockAction.singularText=Unlock Selected Account", + "VisualizationPanel.unlockAction.pluralText=Unlock Selected Accounts",}) + private final class UnlockAction extends AbstractAction { + + private final Set selectedVertices; + + UnlockAction(Set selectedVertices) { + super(selectedVertices.size() > 1 ? Bundle.VisualizationPanel_unlockAction_pluralText() : Bundle.VisualizationPanel_unlockAction_singularText(), + unlockIcon); + this.selectedVertices = selectedVertices; + } + + @Override + + public void actionPerformed(final ActionEvent event) { + lockedVertexModel.unlock(selectedVertices); + } + } + + @NbBundle.Messages({ + "VisualizationPanel.lockAction.singularText=Lock Selected Account", + "VisualizationPanel.lockAction.pluralText=Lock Selected Accounts"}) + private final class LockAction extends AbstractAction { + + private final Set selectedVertices; + + LockAction(Set selectedVertices) { + super(selectedVertices.size() > 1 ? Bundle.VisualizationPanel_lockAction_pluralText() : Bundle.VisualizationPanel_lockAction_singularText(), + lockIcon); + this.selectedVertices = selectedVertices; + } + + @Override + public void actionPerformed(final ActionEvent event) { + lockedVertexModel.lock(selectedVertices); + } + } } From b5a50fd62a0ad00291c6a0555a9843fce9aa0cf9 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Sat, 7 Apr 2018 15:49:25 +0200 Subject: [PATCH 05/11] fix repainting of lock icons --- .../autopsy/communications/EventHandler.java | 28 -------------- .../communications/LockedVertexModel.java | 24 ++++++++---- .../communications/VisualizationPanel.java | 37 +++++++++---------- 3 files changed, 33 insertions(+), 56 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/communications/EventHandler.java diff --git a/Core/src/org/sleuthkit/autopsy/communications/EventHandler.java b/Core/src/org/sleuthkit/autopsy/communications/EventHandler.java deleted file mode 100644 index f1acedf1cf..0000000000 --- a/Core/src/org/sleuthkit/autopsy/communications/EventHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2018 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sleuthkit.autopsy.communications; - -/** - * - */ -public interface EventHandler { - - void handle(T event); -} diff --git a/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java b/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java index ad189a8bea..873866f3f5 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java @@ -21,11 +21,8 @@ package org.sleuthkit.autopsy.communications; import com.google.common.collect.ImmutableSet; import com.google.common.eventbus.EventBus; import com.mxgraph.model.mxCell; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.HashSet; -import java.util.List; import java.util.Set; /** @@ -35,11 +32,11 @@ import java.util.Set; */ final class LockedVertexModel { - void registerhandler(EventHandler handler) { + void registerhandler(Object handler) { eventBus.register(handler); } - void unregisterhandler(EventHandler handler) { + void unregisterhandler(Object handler) { eventBus.unregister(handler); } @@ -83,18 +80,29 @@ final class LockedVertexModel { lockedVertices.clear(); } - static class VertexLockEvent { + /** + * Event that represents a change in the locked state of one or more + * vertices. + */ + final static class VertexLockEvent { + private final boolean locked; private final Set vertices; + /** + * @return The vertices whose locked state has changed. + */ public Set getVertices() { return vertices; } - public boolean isVertexLocked() { + /** + * @return True if the vertices are locked, False if the vertices are + * unlocked. + */ + public boolean isLocked() { return locked; } - private final boolean locked; VertexLockEvent(boolean locked, Collection< mxCell> vertices) { this.vertices = ImmutableSet.copyOf(vertices); diff --git a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java index d33ca867d7..e0fe563e81 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java @@ -165,22 +165,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider //install rubber band other handlers rubberband = new mxRubberband(graphComponent); - lockedVertexModel.registerhandler((LockedVertexModel.VertexLockEvent event) -> { - final Set vertices = event.getVertices(); - mxGraphView view = graph.getView(); - if (event.isVertexLocked()) { - vertices.forEach(vertex -> view.clear(vertex, true, true)); - view.validate(); - } else { - vertices.forEach(vertex -> { - final mxCellState state = view.getState(vertex, true); - view.updateLabel(state); - view.updateLabelBounds(state); - view.updateBoundingBox(state); - }); - } - graphComponent.getGraphControl().repaint(); - }); + lockedVertexModel.registerhandler(this); final mxEventSource.mxIEventListener scaleListener = (Object sender, mxEventObject evt) -> zoomLabel.setText(DecimalFormat.getPercentInstance().format(graph.getView().getScale())); @@ -267,7 +252,20 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } @Subscribe - void handleUnPinEvent(final CVTEvents.UnpinAccountsEvent pinEvent) { + void handle(LockedVertexModel.VertexLockEvent event) { + final Set vertices = event.getVertices(); + mxGraphView view = graph.getView(); + vertices.forEach(vertex -> { + final mxCellState state = view.getState(vertex, true); + view.updateLabel(state); + view.updateLabelBounds(state); + view.updateBoundingBox(state); + graphComponent.redraw(state); + }); + } + + @Subscribe + void handle(final CVTEvents.UnpinAccountsEvent pinEvent) { graph.getModel().beginUpdate(); pinnedAccountModel.unpinAccount(pinEvent.getAccountDeviceInstances()); graph.clear(); @@ -277,7 +275,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } @Subscribe - void handlePinEvent(final CVTEvents.PinAccountsEvent pinEvent) { + void handle(final CVTEvents.PinAccountsEvent pinEvent) { graph.getModel().beginUpdate(); if (pinEvent.isReplace()) { graph.resetGraph(); @@ -289,7 +287,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } @Subscribe - void handleFilterEvent(final CVTEvents.FilterChangeEvent filterChangeEvent) { + void handle(final CVTEvents.FilterChangeEvent filterChangeEvent) { graph.getModel().beginUpdate(); graph.clear(); currentFilter = filterChangeEvent.getNewFilter(); @@ -360,7 +358,6 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider logger.log(Level.SEVERE, "Error getting CommunicationsManager for the current case.", ex); } } - }); } From 1bec33604b401edffa5511c086ca0da6fe2ff77c Mon Sep 17 00:00:00 2001 From: millmanorama Date: Sat, 7 Apr 2018 16:19:14 +0200 Subject: [PATCH 06/11] fix codacy warnings --- .../communications/AbstractCVTAction.java | 5 +--- .../autopsy/communications/CVTEvents.java | 1 - .../communications/CommunicationsGraph.java | 23 ++++++++----------- .../communications/LockedVertexModel.java | 18 ++++++++------- .../communications/MessageBrowser.java | 1 - .../communications/PinAccountsAction.java | 8 +++++-- .../communications/PinnedAccountModel.java | 14 +++++++++++ .../ResetAndPinAccountsAction.java | 6 ++--- .../autopsy/communications/SelectionNode.java | 9 ++++---- .../communications/UnpinAccountsAction.java | 4 ++++ .../communications/VisualizationPanel.java | 11 ++++++++- 11 files changed, 62 insertions(+), 38 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java b/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java index 82cbe5e0f8..ef751d262c 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java +++ b/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java @@ -26,7 +26,6 @@ import org.openide.util.Utilities; import org.openide.util.actions.Presenter; /** - * * Base class for actions that act on the selected AccountDeviceInstanceKeys. * getPopupPresenter() provides a JMenuItem that works (i.e., has an icon) in * custom context menus and also in the Netbeans Explorer views. @@ -39,8 +38,7 @@ abstract class AbstractCVTAction extends AbstractAction implements Presenter.Pop * @return The selected accounts */ Collection getSelectedAccounts() { - final Collection lookupAll = Utilities.actionsGlobalContext().lookupAll(AccountDeviceInstanceKey.class); - return lookupAll; + return Utilities.actionsGlobalContext().lookupAll(AccountDeviceInstanceKey.class); } @Override @@ -64,5 +62,4 @@ abstract class AbstractCVTAction extends AbstractAction implements Presenter.Pop * @return An ImageIcon used to represent this action. */ abstract ImageIcon getIcon(); - } diff --git a/Core/src/org/sleuthkit/autopsy/communications/CVTEvents.java b/Core/src/org/sleuthkit/autopsy/communications/CVTEvents.java index 54e5b8a1ef..6a6a60d3da 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/CVTEvents.java +++ b/Core/src/org/sleuthkit/autopsy/communications/CVTEvents.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.communications; import com.google.common.collect.ImmutableSet; import com.google.common.eventbus.EventBus; import java.util.Collection; -import java.util.Set; import org.sleuthkit.datamodel.CommunicationsFilter; /** diff --git a/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java b/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java index 98d9aa7d88..2cf04eacea 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java +++ b/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java @@ -25,7 +25,6 @@ import com.google.common.collect.MultimapBuilder; import com.mxgraph.model.mxCell; import com.mxgraph.model.mxICell; import com.mxgraph.util.mxConstants; -import com.mxgraph.view.mxCellState; import com.mxgraph.view.mxGraph; import com.mxgraph.view.mxStylesheet; import java.io.InputStream; @@ -38,7 +37,6 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; -import java.util.function.Consumer; import java.util.logging.Level; import javax.swing.SwingWorker; import org.sleuthkit.autopsy.coreutils.Logger; @@ -96,7 +94,7 @@ final class CommunicationsGraph extends mxGraph { CommunicationsGraph(PinnedAccountModel pinnedAccountModel, LockedVertexModel lockedVertexModel) { super(mxStylesheet); - this.pinnedAccountModel =pinnedAccountModel; + this.pinnedAccountModel = pinnedAccountModel; this.lockedVertexModel = lockedVertexModel; //set fixed properties of graph. setAutoSizeCells(true); @@ -243,20 +241,20 @@ final class CommunicationsGraph extends mxGraph { */ private class RebuildWorker extends SwingWorker { - private final ProgressIndicator progress; + private final ProgressIndicator progressIndicator; private final CommunicationsManager commsManager; private final CommunicationsFilter currentFilter; RebuildWorker(ProgressIndicator progress, CommunicationsManager commsManager, CommunicationsFilter currentFilter) { - this.progress = progress; + this.progressIndicator = progress; this.currentFilter = currentFilter; this.commsManager = commsManager; } @Override - protected Void doInBackground() throws Exception { - progress.start("Loading accounts"); + protected Void doInBackground() { + progressIndicator.start("Loading accounts"); int progressCounter = 0; try { /** @@ -278,7 +276,7 @@ final class CommunicationsGraph extends mxGraph { final AccountDeviceInstanceKey relatedADIKey = new AccountDeviceInstanceKey(relatedADI, currentFilter, adiRelationshipsCount); relatedAccounts.put(relatedADI, relatedADIKey); //store related accounts } - progress.progress(++progressCounter); + progressIndicator.progress(++progressCounter); } Set accounts = relatedAccounts.keySet(); @@ -286,9 +284,9 @@ final class CommunicationsGraph extends mxGraph { Map relationshipCounts = commsManager.getRelationshipCountsPairwise(accounts, currentFilter); int total = relationshipCounts.size(); - int k = 0; + int progress = 0; String progressText = ""; - progress.switchToDeterminate("", 0, total); + progressIndicator.switchToDeterminate("", 0, total); for (Map.Entry entry : relationshipCounts.entrySet()) { Long count = entry.getValue(); AccountPair relationshipKey = entry.getKey(); @@ -300,11 +298,10 @@ final class CommunicationsGraph extends mxGraph { mxCell addEdge = addOrUpdateEdge(count, account1, account2); progressText = addEdge.getId(); } - progress.progress(progressText, k++); + progressIndicator.progress(progressText, progress++); } } catch (TskCoreException tskCoreException) { logger.log(Level.SEVERE, "Error", tskCoreException); - } finally { } return null; @@ -320,7 +317,7 @@ final class CommunicationsGraph extends mxGraph { } catch (CancellationException ex) { logger.log(Level.INFO, "Graph visualization cancelled"); } finally { - progress.finish(); + progressIndicator.finish(); } } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java b/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java index 873866f3f5..3ff5880b63 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java @@ -32,14 +32,6 @@ import java.util.Set; */ final class LockedVertexModel { - void registerhandler(Object handler) { - eventBus.register(handler); - } - - void unregisterhandler(Object handler) { - eventBus.unregister(handler); - } - private final EventBus eventBus = new EventBus(); /** @@ -49,6 +41,16 @@ final class LockedVertexModel { */ private final Set lockedVertices = new HashSet<>(); + + void registerhandler(Object handler) { + eventBus.register(handler); + } + + void unregisterhandler(Object handler) { + eventBus.unregister(handler); + } + + /** * Lock the given vertices so that applying a layout algorithm doesn't move * them. The user can still manually position the vertices. diff --git a/Core/src/org/sleuthkit/autopsy/communications/MessageBrowser.java b/Core/src/org/sleuthkit/autopsy/communications/MessageBrowser.java index 7c0bf99c62..7b90357993 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/MessageBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/communications/MessageBrowser.java @@ -35,7 +35,6 @@ import org.sleuthkit.autopsy.corecomponents.DataResultPanel; import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; import org.sleuthkit.autopsy.corecomponents.TableFilterNode; import org.sleuthkit.autopsy.directorytree.DataResultFilterNode; -import org.sleuthkit.datamodel.AccountDeviceInstance; /** * The right hand side of the CVT. Has a DataResultPanel to show a listing of diff --git a/Core/src/org/sleuthkit/autopsy/communications/PinAccountsAction.java b/Core/src/org/sleuthkit/autopsy/communications/PinAccountsAction.java index d820373284..52136d1b1a 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/PinAccountsAction.java +++ b/Core/src/org/sleuthkit/autopsy/communications/PinAccountsAction.java @@ -23,6 +23,10 @@ import javax.swing.ImageIcon; import org.openide.util.ImageUtilities; import org.openide.util.NbBundle; +/** + * Action that pins the AccountDevicesIntanceKeys in the ActionsGlobalContext to + * the visualizaion + */ @NbBundle.Messages({"PinAccountsAction.pluralText=Add Selected Accounts to Visualization", "PinAccountsAction.singularText=Add Selected Account to Visualization"}) final class PinAccountsAction extends AbstractCVTAction { @@ -31,7 +35,7 @@ final class PinAccountsAction extends AbstractCVTAction { "/org/sleuthkit/autopsy/communications/images/marker--plus.png", false); private static final String SINGULAR_TEXT = Bundle.PinAccountsAction_singularText(); private static final String PLURAL_TEXT = Bundle.PinAccountsAction_pluralText(); - + private static final PinAccountsAction instance = new PinAccountsAction(); static PinAccountsAction getInstance() { @@ -39,7 +43,7 @@ final class PinAccountsAction extends AbstractCVTAction { } @Override - public void actionPerformed(ActionEvent e) { + public void actionPerformed(ActionEvent event) { CVTEvents.getCVTEventBus().post(new CVTEvents.PinAccountsEvent(getSelectedAccounts(), false)); } diff --git a/Core/src/org/sleuthkit/autopsy/communications/PinnedAccountModel.java b/Core/src/org/sleuthkit/autopsy/communications/PinnedAccountModel.java index beff35173d..f7fb7d1232 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/PinnedAccountModel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/PinnedAccountModel.java @@ -19,9 +19,13 @@ package org.sleuthkit.autopsy.communications; import com.google.common.collect.ImmutableSet; +import com.google.common.eventbus.EventBus; import java.util.HashSet; import java.util.Set; +/** + * Model of what accounts are pinned to a visualization. + */ class PinnedAccountModel { /** @@ -32,6 +36,16 @@ class PinnedAccountModel { */ private final Set pinnedAccountDevices = new HashSet<>(); + private final EventBus eventBus = new EventBus(); + + void registerhandler(Object handler) { + eventBus.register(handler); + } + + void unregisterhandler(Object handler) { + eventBus.unregister(handler); + } + boolean isAccountPinned(AccountDeviceInstanceKey account) { return pinnedAccountDevices.contains(account); } diff --git a/Core/src/org/sleuthkit/autopsy/communications/ResetAndPinAccountsAction.java b/Core/src/org/sleuthkit/autopsy/communications/ResetAndPinAccountsAction.java index a42b2882ed..385ac3348b 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/ResetAndPinAccountsAction.java +++ b/Core/src/org/sleuthkit/autopsy/communications/ResetAndPinAccountsAction.java @@ -24,7 +24,8 @@ import org.openide.util.ImageUtilities; import org.openide.util.NbBundle; /** - * + * Action that clears any pinned accounts and pins the AcountDevicesInstanceKeys + * in the ActionsGlobalContext to the visualization. */ @NbBundle.Messages(value = {"ResetAndPinAccountsAction.singularText=Visualize Only Selected Account", "ResetAndPinAccountsAction.pluralText=Visualize Only Selected Accounts"}) @@ -42,7 +43,7 @@ final class ResetAndPinAccountsAction extends AbstractCVTAction { } @Override - public void actionPerformed(ActionEvent e) { + public void actionPerformed(ActionEvent event) { CVTEvents.getCVTEventBus().post(new CVTEvents.PinAccountsEvent(getSelectedAccounts(), true)); } @@ -55,5 +56,4 @@ final class ResetAndPinAccountsAction extends AbstractCVTAction { ImageIcon getIcon() { return ICON; } - } diff --git a/Core/src/org/sleuthkit/autopsy/communications/SelectionNode.java b/Core/src/org/sleuthkit/autopsy/communications/SelectionNode.java index be564c01cc..1618bb9ecc 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/SelectionNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/SelectionNode.java @@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.communications; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; @@ -48,7 +47,7 @@ import org.sleuthkit.datamodel.TskCoreException; */ final class SelectionNode extends AbstractNode { - SelectionNode(Children children, Lookup lookup) { + private SelectionNode(Children children, Lookup lookup) { super(children, lookup); } @@ -130,9 +129,9 @@ final class SelectionNode extends AbstractNode { } @Override - protected Node createNodeForKey(Content t) { - if (t instanceof BlackboardArtifact) { - return new RelationshipNode((BlackboardArtifact) t); + protected Node createNodeForKey(Content content) { + if (content instanceof BlackboardArtifact) { + return new RelationshipNode((BlackboardArtifact) content); } else { throw new UnsupportedOperationException("Cannot create a RelationshipNode for non BlackboardArtifact content."); } diff --git a/Core/src/org/sleuthkit/autopsy/communications/UnpinAccountsAction.java b/Core/src/org/sleuthkit/autopsy/communications/UnpinAccountsAction.java index 357f5a0451..ba0bbc545b 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/UnpinAccountsAction.java +++ b/Core/src/org/sleuthkit/autopsy/communications/UnpinAccountsAction.java @@ -23,6 +23,10 @@ import javax.swing.ImageIcon; import org.openide.util.ImageUtilities; import org.openide.util.NbBundle; +/** + * Action that unpins the AcccountDeviceInstanceKeys in the ActionsGlobalContext + * form the visualization. + */ @NbBundle.Messages({"UnpinAccountsAction.pluralText=Remove Selected Accounts", "UnpinAccountsAction.singularText=Remove Selected Account"}) final class UnpinAccountsAction extends AbstractCVTAction { diff --git a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java index e0fe563e81..9fca11992a 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java @@ -873,7 +873,10 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } } - private class CancelationListener implements ActionListener { + /** + * Listener that closes a ModalDialogProgreessIndicator when invoked. + */ + final private class CancelationListener implements ActionListener { private Future cancellable; private ModalDialogProgressIndicator progress; @@ -891,6 +894,9 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } } + /** + * Action that un-locks the selected vertices. + */ @NbBundle.Messages({ "VisualizationPanel.unlockAction.singularText=Unlock Selected Account", "VisualizationPanel.unlockAction.pluralText=Unlock Selected Accounts",}) @@ -911,6 +917,9 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } } + /** + * Action that locks the selected vertices. + */ @NbBundle.Messages({ "VisualizationPanel.lockAction.singularText=Lock Selected Account", "VisualizationPanel.lockAction.pluralText=Lock Selected Accounts"}) From f0e04d28f252238f88a270ca657e856151f40179 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Mon, 9 Apr 2018 11:32:14 +0200 Subject: [PATCH 07/11] log errors in layout SwingWorker --- .../communications/VisualizationPanel.java | 172 +++++++++--------- 1 file changed, 91 insertions(+), 81 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java index 9fca11992a..7d2c77dfce 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java @@ -57,6 +57,7 @@ import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.logging.Level; import java.util.stream.Collectors; @@ -104,7 +105,7 @@ import org.sleuthkit.datamodel.TskCoreException; * actions to work correctly. */ final public class VisualizationPanel extends JPanel implements Lookup.Provider { - + private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(VisualizationPanel.class.getName()); private static final String BASE_IMAGE_PATH = "/org/sleuthkit/autopsy/communications/images"; @@ -112,21 +113,21 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider = new ImageIcon(VisualizationPanel.class.getResource(BASE_IMAGE_PATH + "/lock_large_unlocked.png")); static final private ImageIcon lockIcon = new ImageIcon(VisualizationPanel.class.getResource(BASE_IMAGE_PATH + "/lock_large_locked.png")); - + @NbBundle.Messages("VisualizationPanel.cancelButton.text=Cancel") private static final String CANCEL = Bundle.VisualizationPanel_cancelButton_text(); - + private final ExplorerManager vizEM = new ExplorerManager(); private final ExplorerManager gacEM = new ExplorerManager(); private final ProxyLookup proxyLookup; private Frame windowAncestor; - + private CommunicationsManager commsManager; private CommunicationsFilter currentFilter; - + private final mxGraphComponent graphComponent; private final CommunicationsGraph graph; - + private final mxUndoManager undoManager = new mxUndoManager(); private final mxRubberband rubberband; //NOPMD We keep a referenec as insurance to prevent garbage collection @@ -134,22 +135,22 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider private final mxCircleLayout circleLayout; private final mxOrganicLayout organicLayout; private final mxHierarchicalLayout hierarchicalLayout; - + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) private SwingWorker worker; private final PinnedAccountModel pinnedAccountModel = new PinnedAccountModel(); private final LockedVertexModel lockedVertexModel = new LockedVertexModel(); - + public VisualizationPanel() { initComponents(); - + graph = new CommunicationsGraph(pinnedAccountModel, lockedVertexModel); - + fastOrganicLayout = new mxFastOrganicLayoutImpl(graph); circleLayout = new mxCircleLayoutImpl(graph); organicLayout = new mxOrganicLayoutImpl(graph); hierarchicalLayout = new mxHierarchicalLayoutImpl(graph); - + graphComponent = new mxGraphComponent(graph); graphComponent.setAutoExtend(true); graphComponent.setAutoScroll(true); @@ -164,14 +165,14 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider //install rubber band other handlers rubberband = new mxRubberband(graphComponent); - + lockedVertexModel.registerhandler(this); - + final mxEventSource.mxIEventListener scaleListener = (Object sender, mxEventObject evt) -> zoomLabel.setText(DecimalFormat.getPercentInstance().format(graph.getView().getScale())); graph.getView().addListener(mxEvent.SCALE, scaleListener); graph.getView().addListener(mxEvent.SCALE_AND_TRANSLATE, scaleListener); - + graphComponent.getGraphControl().addMouseWheelListener(new MouseAdapter() { /** * Translate mouse wheel events into zooming. @@ -188,7 +189,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } } }); - + graphComponent.getGraphControl().addMouseListener(new MouseAdapter() { /** * Right click handler: show context menu. @@ -203,13 +204,13 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider if (cellAt != null && cellAt.isVertex()) { final JPopupMenu jPopupMenu = new JPopupMenu(); final AccountDeviceInstanceKey adiKey = (AccountDeviceInstanceKey) cellAt.getValue(); - + Set selectedVertices = Stream.of(graph.getSelectionModel().getCells()) .map(mxCell.class::cast) .filter(mxCell::isVertex) .collect(Collectors.toSet()); - + if (lockedVertexModel.isVertexLocked(cellAt)) { jPopupMenu.add(new JMenuItem(new UnlockAction(selectedVertices))); } else { @@ -225,13 +226,13 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } } } - + }); - + final MessageBrowser messageBrowser = new MessageBrowser(vizEM, gacEM); - + splitPane.setRightComponent(messageBrowser); - + proxyLookup = new ProxyLookup( ExplorerUtils.createLookup(vizEM, getActionMap()), messageBrowser.getLookup() @@ -241,16 +242,16 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider graph.getSelectionModel().addListener(mxEvent.CHANGE, new SelectionListener()); final mxEventSource.mxIEventListener undoListener = (Object sender, mxEventObject evt) -> undoManager.undoableEditHappened((mxUndoableEdit) evt.getProperty("edit")); - + graph.getModel().addListener(mxEvent.UNDO, undoListener); graph.getView().addListener(mxEvent.UNDO, undoListener); } - + @Override public Lookup getLookup() { return proxyLookup; } - + @Subscribe void handle(LockedVertexModel.VertexLockEvent event) { final Set vertices = event.getVertices(); @@ -263,7 +264,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider graphComponent.redraw(state); }); } - + @Subscribe void handle(final CVTEvents.UnpinAccountsEvent pinEvent) { graph.getModel().beginUpdate(); @@ -273,7 +274,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider // Updates the display graph.getModel().endUpdate(); } - + @Subscribe void handle(final CVTEvents.PinAccountsEvent pinEvent) { graph.getModel().beginUpdate(); @@ -285,7 +286,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider // Updates the display graph.getModel().endUpdate(); } - + @Subscribe void handle(final CVTEvents.FilterChangeEvent filterChangeEvent) { graph.getModel().beginUpdate(); @@ -295,7 +296,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider // Updates the display graph.getModel().endUpdate(); } - + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) private void rebuildGraph() { if (pinnedAccountModel.isEmpty()) { @@ -308,7 +309,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider if (worker != null) { worker.cancel(true); } - + final CancelationListener cancelationListener = new CancelationListener(); final ModalDialogProgressIndicator progress = new ModalDialogProgressIndicator(windowAncestor, "Loading Visualization", new String[]{CANCEL}, CANCEL, cancelationListener); worker = graph.rebuild(progress, commsManager, currentFilter); @@ -319,20 +320,20 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider graph.resetGraph(); rebuildGraph(); } else { - morph(fastOrganicLayout); + animateLayout(fastOrganicLayout); } } }); - + worker.execute(); } } - + @Override public void addNotify() { super.addNotify(); windowAncestor = (Frame) SwingUtilities.getAncestorOfClass(Frame.class, this); - + try { commsManager = Case.getOpenCase().getSleuthkitCase().getCommunicationsManager(); } catch (TskCoreException ex) { @@ -340,7 +341,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } catch (NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Can't get CommunicationsManager when there is no case open.", ex); } - + Case.addEventTypeSubscriber(EnumSet.of(CURRENT_CASE), evt -> { graph.getModel().beginUpdate(); try { @@ -605,7 +606,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider }//GEN-LAST:event_zoomOutButtonActionPerformed private void circleLayoutButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_circleLayoutButtonActionPerformed - morph(circleLayout); + animateLayout(circleLayout); }//GEN-LAST:event_circleLayoutButtonActionPerformed private void organicLayoutButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_organicLayoutButtonActionPerformed @@ -613,11 +614,11 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider }//GEN-LAST:event_organicLayoutButtonActionPerformed private void fastOrganicLayoutButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_fastOrganicLayoutButtonActionPerformed - morph(fastOrganicLayout); + animateLayout(fastOrganicLayout); }//GEN-LAST:event_fastOrganicLayoutButtonActionPerformed private void hierarchyLayoutButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_hierarchyLayoutButtonActionPerformed - morph(hierarchicalLayout); + animateLayout(hierarchicalLayout); }//GEN-LAST:event_hierarchyLayoutButtonActionPerformed private void clearVizButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_clearVizButtonActionPerformed @@ -631,44 +632,44 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider setCursor(Cursor.getDefaultCursor()); }//GEN-LAST:event_clearVizButtonActionPerformed - + private void applyOrganicLayout(int iterations) { organicLayout.setMaxIterations(iterations); - morph(organicLayout); + animateLayout(organicLayout); } - + private void fitGraph() { graphComponent.zoomTo(1, true); mxPoint translate = graph.getView().getTranslate(); if (translate == null || Double.isNaN(translate.getX()) || Double.isNaN(translate.getY())) { translate = new mxPoint(); } - + mxRectangle boundsForCells = graph.getCellBounds(graph.getDefaultParent(), true, true, true); if (boundsForCells == null || Double.isNaN(boundsForCells.getWidth()) || Double.isNaN(boundsForCells.getHeight())) { boundsForCells = new mxRectangle(0, 0, 1, 1); } final mxPoint mxPoint = new mxPoint(translate.getX() - boundsForCells.getX(), translate.getY() - boundsForCells.getY()); - + graph.cellsMoved(graph.getChildCells(graph.getDefaultParent()), mxPoint.getX(), mxPoint.getY(), false, false); - + boundsForCells = graph.getCellBounds(graph.getDefaultParent(), true, true, true); if (boundsForCells == null || Double.isNaN(boundsForCells.getWidth()) || Double.isNaN(boundsForCells.getHeight())) { boundsForCells = new mxRectangle(0, 0, 1, 1); } - + final Dimension size = graphComponent.getSize(); final double widthFactor = size.getWidth() / boundsForCells.getWidth(); - + graphComponent.zoom(widthFactor); - + } - + @NbBundle.Messages({"Visualization.computingLayout=Computing Layout"}) - private void morph(mxIGraphLayout layout) { + private void animateLayout(mxIGraphLayout layout) { // layout using morphing graph.getModel().beginUpdate(); - + CancelationListener cancelationListener = new CancelationListener(); ModalDialogProgressIndicator progress = new ModalDialogProgressIndicator(windowAncestor, Bundle.Visualization_computingLayout(), new String[]{CANCEL}, CANCEL, cancelationListener); @@ -685,10 +686,10 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider @Override public void updateAnimation() { fireEvent(new mxEventObject(mxEvent.EXECUTE)); - super.updateAnimation(); //To change body of generated methods, choose Tools | Templates. + super.updateAnimation(); } - }; + morph.addListener(mxEvent.EXECUTE, (Object sender, mxEventObject evt) -> { if (isCancelled()) { morph.stopAnimation(); @@ -703,10 +704,19 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } progress.finish(); }); - + morph.startAnimation(); return null; - + } + + @Override + protected void done() { + super.done(); + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + logger.log(Level.SEVERE, "Layout interupted", ex); + } } }; cancelationListener.configure(morphWorker, progress); @@ -740,7 +750,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider * changes in selection. */ final private class SelectionListener implements mxEventSource.mxIEventListener { - + @SuppressWarnings("unchecked") @Override public void invoke(Object sender, mxEventObject evt) { @@ -770,7 +780,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider adis.add((AccountDeviceInstanceKey) cell.getValue()); } } - + rootNode = SelectionNode.createFromAccountsAndRelationships(relationshipSources, adis, currentFilter, commsManager); selectedNodes = new Node[]{rootNode}; } @@ -782,19 +792,19 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } } } - + final private class mxFastOrganicLayoutImpl extends mxFastOrganicLayout { - + mxFastOrganicLayoutImpl(mxGraph graph) { super(graph); } - + @Override public boolean isVertexIgnored(Object vertex) { return super.isVertexIgnored(vertex) || lockedVertexModel.isVertexLocked((mxCell) vertex); } - + @Override public mxRectangle setVertexLocation(Object vertex, double x, double y) { //NOPMD x,y variable names are standard if (isVertexIgnored(vertex)) { @@ -804,20 +814,20 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } } } - + final private class mxCircleLayoutImpl extends mxCircleLayout { - + mxCircleLayoutImpl(mxGraph graph) { super(graph); setResetEdges(true); } - + @Override public boolean isVertexIgnored(Object vertex) { return super.isVertexIgnored(vertex) || lockedVertexModel.isVertexLocked((mxCell) vertex); } - + @Override public mxRectangle setVertexLocation(Object vertex, double x, double y) { //NOPMD x,y variable names are standard if (isVertexIgnored(vertex)) { @@ -827,20 +837,20 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } } } - + final private class mxOrganicLayoutImpl extends mxOrganicLayout { - + mxOrganicLayoutImpl(mxGraph graph) { super(graph); setResetEdges(true); } - + @Override public boolean isVertexIgnored(Object vertex) { return super.isVertexIgnored(vertex) || lockedVertexModel.isVertexLocked((mxCell) vertex); } - + @Override public mxRectangle setVertexLocation(Object vertex, double x, double y) { //NOPMD x,y variable names are standard if (isVertexIgnored(vertex)) { @@ -850,19 +860,19 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } } } - + final private class mxHierarchicalLayoutImpl extends mxHierarchicalLayout { - + mxHierarchicalLayoutImpl(mxGraph graph) { super(graph); } - + @Override public boolean isVertexIgnored(Object vertex) { return super.isVertexIgnored(vertex) || lockedVertexModel.isVertexLocked((mxCell) vertex); } - + @Override public mxRectangle setVertexLocation(Object vertex, double x, double y) { //NOPMD x,y variable names are standard if (isVertexIgnored(vertex)) { @@ -877,15 +887,15 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider * Listener that closes a ModalDialogProgreessIndicator when invoked. */ final private class CancelationListener implements ActionListener { - + private Future cancellable; private ModalDialogProgressIndicator progress; - + void configure(Future cancellable, ModalDialogProgressIndicator progress) { this.cancellable = cancellable; this.progress = progress; } - + @Override public void actionPerformed(ActionEvent event) { progress.setCancelling("Cancelling..."); @@ -901,17 +911,17 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider "VisualizationPanel.unlockAction.singularText=Unlock Selected Account", "VisualizationPanel.unlockAction.pluralText=Unlock Selected Accounts",}) private final class UnlockAction extends AbstractAction { - + private final Set selectedVertices; - + UnlockAction(Set selectedVertices) { super(selectedVertices.size() > 1 ? Bundle.VisualizationPanel_unlockAction_pluralText() : Bundle.VisualizationPanel_unlockAction_singularText(), unlockIcon); this.selectedVertices = selectedVertices; } - + @Override - + public void actionPerformed(final ActionEvent event) { lockedVertexModel.unlock(selectedVertices); } @@ -924,15 +934,15 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider "VisualizationPanel.lockAction.singularText=Lock Selected Account", "VisualizationPanel.lockAction.pluralText=Lock Selected Accounts"}) private final class LockAction extends AbstractAction { - + private final Set selectedVertices; - + LockAction(Set selectedVertices) { super(selectedVertices.size() > 1 ? Bundle.VisualizationPanel_lockAction_pluralText() : Bundle.VisualizationPanel_lockAction_singularText(), lockIcon); this.selectedVertices = selectedVertices; } - + @Override public void actionPerformed(final ActionEvent event) { lockedVertexModel.lock(selectedVertices); From 662babede1bd431757f7979108d44cd4c395145b Mon Sep 17 00:00:00 2001 From: millmanorama Date: Mon, 9 Apr 2018 13:52:10 +0200 Subject: [PATCH 08/11] Revert "refactor to use LockedVertexLayoutWrapper" This reverts commit 08cc853fa8e8e447268ecde3c18f4f980508c11f. # Conflicts: # Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java # Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java --- .../communications/LockedVertexModel.java | 118 -------------- .../communications/VisualizationPanel.form | 6 +- .../communications/VisualizationPanel.java | 144 ++++++++++++++---- 3 files changed, 116 insertions(+), 152 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java b/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java index 4a2b82dc43..251f6382f7 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java @@ -20,14 +20,12 @@ package org.sleuthkit.autopsy.communications; import com.google.common.collect.ImmutableSet; import com.google.common.eventbus.EventBus; -import com.mxgraph.layout.mxGraphLayout; import com.mxgraph.model.mxCell; import com.mxgraph.util.mxPoint; import com.mxgraph.util.mxRectangle; import com.mxgraph.view.mxGraph; import java.util.Collection; import java.util.HashSet; -import java.util.List; import java.util.Set; /** @@ -114,120 +112,4 @@ final class LockedVertexModel { this.locked = locked; } } - - mxGraphLayout createLockedVertexWrapper(mxGraphLayout layout) { - return new LockedVertexLayoutWrapper(layout, this); - } - - /** An mxGraphLayout that wrapps an other layout and ignores locked vertes. - * - * @param - */ - private static final class LockedVertexLayoutWrapper extends mxGraphLayout { - - private final mxGraphLayout wrappedLayout; - private final LockedVertexModel lockedVertexModel; - - /** - * - * - * @param layout The layout to wrap - * @param lockedVertexModel the value of lockedVertexModel2 - */ - private LockedVertexLayoutWrapper(mxGraphLayout layout, LockedVertexModel lockedVertexModel) { - super(layout.getGraph()); - this.lockedVertexModel = lockedVertexModel; - wrappedLayout = layout; - } - - @Override - public boolean isVertexIgnored(Object vertex) { - return wrappedLayout.isVertexIgnored(vertex) - || lockedVertexModel.isVertexLocked((mxCell) vertex); - } - - @Override - public mxRectangle setVertexLocation(Object vertex, double xCoord, double yCoord) { - if (isVertexIgnored(vertex)) { - return getVertexBounds(vertex); - } else { - return wrappedLayout.setVertexLocation(vertex, xCoord, yCoord); - } - } - - @Override - public void execute(Object parent) { - wrappedLayout.execute(parent); - } - - @Override - public void moveCell(Object cell, double xCoord, double yCoord) { - wrappedLayout.moveCell(cell, xCoord, yCoord); - } - - @Override - public mxGraph getGraph() { - return wrappedLayout.getGraph(); - } - - @Override - public Object getConstraint(Object key, Object cell) { - return wrappedLayout.getConstraint(key, cell); - } - - @Override - public Object getConstraint(Object key, Object cell, Object edge, boolean source) { - return wrappedLayout.getConstraint(key, cell, edge, source); - } - - @Override - public boolean isUseBoundingBox() { - return wrappedLayout.isUseBoundingBox(); - } - - @Override - public void setUseBoundingBox(boolean useBoundingBox) { - wrappedLayout.setUseBoundingBox(useBoundingBox); - } - - @Override - public boolean isVertexMovable(Object vertex) { - return wrappedLayout.isVertexMovable(vertex); - } - - @Override - public boolean isEdgeIgnored(Object edge) { - return wrappedLayout.isEdgeIgnored(edge); - } - - @Override - public void setEdgeStyleEnabled(Object edge, boolean value) { - wrappedLayout.setEdgeStyleEnabled(edge, value); - } - - @Override - public void setOrthogonalEdge(Object edge, boolean value) { - wrappedLayout.setOrthogonalEdge(edge, value); - } - - @Override - public mxPoint getParentOffset(Object parent) { - return wrappedLayout.getParentOffset(parent); - } - - @Override - public void setEdgePoints(Object edge, List points) { - wrappedLayout.setEdgePoints(edge, points); - } - - @Override - public mxRectangle getVertexBounds(Object vertex) { - return wrappedLayout.getVertexBounds(vertex); - } - - @Override - public void arrangeGroups(Object[] groups, int border) { - wrappedLayout.arrangeGroups(groups, border); - } - } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.form b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.form index deae56fd17..a847f700c7 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.form +++ b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.form @@ -11,7 +11,7 @@ - + @@ -106,7 +106,7 @@ - + @@ -120,7 +120,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java index adcdecf7ba..25eea8cc98 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java @@ -23,7 +23,6 @@ import com.mxgraph.layout.hierarchical.mxHierarchicalLayout; import com.mxgraph.layout.mxCircleLayout; import com.mxgraph.layout.mxFastOrganicLayout; import com.mxgraph.layout.mxGraphLayout; -import com.mxgraph.layout.mxIGraphLayout; import com.mxgraph.layout.mxOrganicLayout; import com.mxgraph.model.mxCell; import com.mxgraph.model.mxICell; @@ -38,6 +37,7 @@ import com.mxgraph.util.mxRectangle; import com.mxgraph.util.mxUndoManager; import com.mxgraph.util.mxUndoableEdit; import com.mxgraph.view.mxCellState; +import com.mxgraph.view.mxGraph; import com.mxgraph.view.mxGraphView; import java.awt.BorderLayout; import java.awt.Color; @@ -133,11 +133,10 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider private final mxUndoManager undoManager = new mxUndoManager(); private final mxRubberband rubberband; //NOPMD We keep a referenec as insurance to prevent garbage collection - - private final mxGraphLayout fastOrganicLayout; - private final mxGraphLayout circleLayout; - private final mxGraphLayout organicLayout; - private final mxGraphLayout hierarchyLayout; + private final mxFastOrganicLayout fastOrganicLayout; + private final mxCircleLayout circleLayout; + private final mxOrganicLayout organicLayout; + private final mxHierarchicalLayout hierarchyLayout; @ThreadConfined(type = ThreadConfined.ThreadType.AWT) private SwingWorker worker; @@ -193,19 +192,12 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider graph.getModel().addListener(mxEvent.UNDO, undoListener); graph.getView().addListener(mxEvent.UNDO, undoListener); - fastOrganicLayout = lockedVertexModel.createLockedVertexWrapper(new mxFastOrganicLayout(graph)); - hierarchyLayout = lockedVertexModel.createLockedVertexWrapper(new mxHierarchicalLayout(graph)); - circleLayout = lockedVertexModel.createLockedVertexWrapper(new mxCircleLayout(graph) { - { - setResetEdges(true); - } - }); - organicLayout = lockedVertexModel.createLockedVertexWrapper(new mxOrganicLayout(graph) { - { - setResetEdges(true); - setMaxIterations(10); - } - }); + fastOrganicLayout = new mxFastOrganicLayoutImpl(graph); + circleLayout = new mxCircleLayoutImpl(graph); + organicLayout = new mxOrganicLayoutImpl(graph); + organicLayout.setMaxIterations(10); + hierarchyLayout = new mxHierarchicalLayoutImpl(graph); + //local method to configure layout buttons BiConsumer configure = (layoutButton, layout) -> { layoutButtons.put(layout, layoutButton); @@ -502,7 +494,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider .add(hierarchyLayoutButton) .addPreferredGap(LayoutStyle.RELATED) .add(circleLayoutButton) - .addPreferredGap(LayoutStyle.UNRELATED) + .addPreferredGap(LayoutStyle.RELATED) .add(jSeparator2, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE) .addPreferredGap(LayoutStyle.RELATED) .add(jLabel2) @@ -516,7 +508,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider .add(zoomActualButton, GroupLayout.PREFERRED_SIZE, 33, GroupLayout.PREFERRED_SIZE) .addPreferredGap(LayoutStyle.RELATED) .add(fitZoomButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE) - .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap(12, Short.MAX_VALUE)) ); toolbarLayout.setVerticalGroup(toolbarLayout.createParallelGroup(GroupLayout.LEADING) .add(toolbarLayout.createSequentialGroup() @@ -577,18 +569,18 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider graph.getModel().beginUpdate(); CancelationListener cancelationListener = new CancelationListener(); - ModalDialogProgressIndicator progress = new ModalDialogProgressIndicator(windowAncestor, + ModalDialogProgressIndicator progressIndicator = new ModalDialogProgressIndicator(windowAncestor, Bundle.Visualization_computingLayout(), new String[]{CANCEL}, CANCEL, cancelationListener); SwingWorker morphWorker = new SwingWorker() { - int i = 0; + int progress = 0; int max = 100; @Override protected Void doInBackground() { - progress.start(Bundle.Visualization_computingLayout()); + progressIndicator.start(Bundle.Visualization_computingLayout()); layout.execute(graph.getDefaultParent()); if (isCancelled()) { - progress.finish(); + progressIndicator.finish(); return null; } @@ -600,10 +592,10 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider if (isCancelled()) { stopAnimation(); } else { - i++; - progress.switchToDeterminate(Bundle.Visualization_computingLayout(), i, max); - if ( i >= max *3.0/4.0){ - max *=2; + progress++; + progressIndicator.switchToDeterminate(Bundle.Visualization_computingLayout(), progress, max); + if (progress >= max * 3.0 / 4.0) { + max *= 2; } } } @@ -616,7 +608,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } else { fitGraph(); } - progress.finish(); + progressIndicator.finish(); }); morph.startAnimation(); @@ -633,7 +625,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } } }; - cancelationListener.configure(morphWorker, progress); + cancelationListener.configure(morphWorker, progressIndicator); morphWorker.execute(); } @@ -746,6 +738,96 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } } + final private class mxFastOrganicLayoutImpl extends mxFastOrganicLayout { + + mxFastOrganicLayoutImpl(mxGraph graph) { + super(graph); + } + + @Override + public boolean isVertexIgnored(Object vertex) { + return super.isVertexIgnored(vertex) + || lockedVertexModel.isVertexLocked((mxCell) vertex); + } + + @Override + public mxRectangle setVertexLocation(Object vertex, double x, double y) { //NOPMD x, y are standard coordinate names + if (isVertexIgnored(vertex)) { + return getVertexBounds(vertex); + } else { + return super.setVertexLocation(vertex, x, y); + } + } + } + + final private class mxCircleLayoutImpl extends mxCircleLayout { + + mxCircleLayoutImpl(mxGraph graph) { + super(graph); + setResetEdges(true); + } + + @Override + public boolean isVertexIgnored(Object vertex) { + return super.isVertexIgnored(vertex) + || lockedVertexModel.isVertexLocked((mxCell) vertex); + } + + @Override + public mxRectangle setVertexLocation(Object vertex, double x, double y) { //NOPMD x, y are standard coordinate names + if (isVertexIgnored(vertex)) { + return getVertexBounds(vertex); + } else { + return super.setVertexLocation(vertex, x, y); + } + } + } + + final private class mxOrganicLayoutImpl extends mxOrganicLayout { + + mxOrganicLayoutImpl(mxGraph graph) { + super(graph); + setResetEdges(true); + } + + @Override + public boolean isVertexIgnored(Object vertex) { + return super.isVertexIgnored(vertex) + || lockedVertexModel.isVertexLocked((mxCell) vertex); + } + + @Override + public mxRectangle setVertexLocation(Object vertex, double x, double y) { //NOPMD x, y are standard coordinate names + if (isVertexIgnored(vertex)) { + return getVertexBounds(vertex); + } else { + return super.setVertexLocation(vertex, x, y); + } + } + } + + final private class mxHierarchicalLayoutImpl extends mxHierarchicalLayout { + + mxHierarchicalLayoutImpl(mxGraph graph) { + super(graph); + } + + @Override + public boolean isVertexIgnored(Object vertex) { + return super.isVertexIgnored(vertex) + || lockedVertexModel.isVertexLocked((mxCell) vertex); + } + + @Override + public mxRectangle setVertexLocation(Object vertex, double x, double y) { //NOPMD x, y are standard coordinate names + if (isVertexIgnored(vertex)) { + return getVertexBounds(vertex); + } else { + return super.setVertexLocation(vertex, x, y); + } + } + } + /** * Listener that closses the given ModalDialogProgressIndicator and cancels * the future. From f3f650c2f364c8abb45faf28e93f83f15c4d4f65 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Mon, 9 Apr 2018 13:54:40 +0200 Subject: [PATCH 09/11] fix codacy issues --- .../autopsy/communications/VisualizationPanel.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java index 25eea8cc98..c76427aa62 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java @@ -738,6 +738,9 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } } + /** + * Extension of mxFastOrganicLayout that ignores locked vertices. + */ final private class mxFastOrganicLayoutImpl extends mxFastOrganicLayout { mxFastOrganicLayoutImpl(mxGraph graph) { @@ -760,6 +763,9 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } } + /** + * Extension of mxCircleLayout that ignores locked vertices. + */ final private class mxCircleLayoutImpl extends mxCircleLayout { mxCircleLayoutImpl(mxGraph graph) { @@ -783,6 +789,9 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } } + /** + * Extension of mxOrganicLayout that ignores locked vertices. + */ final private class mxOrganicLayoutImpl extends mxOrganicLayout { mxOrganicLayoutImpl(mxGraph graph) { @@ -806,6 +815,9 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } } + /** + * Extension of mxHierarchicalLayout that ignores locked vertices. + */ final private class mxHierarchicalLayoutImpl extends mxHierarchicalLayout { mxHierarchicalLayoutImpl(mxGraph graph) { From 206e599037ba390ad28c9ffc76685a380aaa2909 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Mon, 9 Apr 2018 16:43:26 +0200 Subject: [PATCH 10/11] remove animation of layout and handle errors. --- .../autopsy/communications/Bundle.properties | 5 +- .../communications/CommunicationsGraph.java | 2 +- .../communications/LockedVertexModel.java | 4 + .../communications/VisualizationPanel.java | 143 +++++++++--------- 4 files changed, 77 insertions(+), 77 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties index ea3049f895..358971eaa8 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties @@ -20,9 +20,6 @@ CVTTopComponent.vizPanel.TabConstraints.tabTitle=Visualize CVTTopComponent.accountsBrowser.TabConstraints.tabTitle_1=Browse CVTTopComponent.browseVisualizeTabPane.AccessibleContext.accessibleName=Visualize CVTTopComponent.vizPanel.TabConstraints.tabTitle_1=Visualize -VisualizationPanel.jButton6.text=Hierarchy -VisualizationPanel.jButton7.text=Circle -VisualizationPanel.jButton8.text=Organic VisualizationPanel.fitGraphButton.text= VisualizationPanel.jTextArea1.text=Right-click an account in the Browse Accounts table, and select 'Visualize' to begin. VisualizationPanel.jLabel1.text=Layouts: @@ -39,5 +36,5 @@ VisualizationPanel.zoomOutButton.text= VisualizationPanel.circleLayoutButton.text=Circle VisualizationPanel.organicLayoutButton.text=Organic VisualizationPanel.fastOrganicLayoutButton.text=Fast Organic -VisualizationPanel.hierarchyLayoutButton.text=Hierarchy +VisualizationPanel.hierarchyLayoutButton.text=Hierarchical VisualizationPanel.clearVizButton.text_1=Clear Viz. diff --git a/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java b/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java index 2dadb888b9..716d00656c 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java +++ b/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java @@ -264,7 +264,7 @@ final class CommunicationsGraph extends mxGraph { for (final AccountDeviceInstanceKey adiKey : pinnedAccountModel.getPinnedAccounts()) { if (isCancelled()) { break; - } + } //get accounts related to pinned account final List relatedAccountDeviceInstances = commsManager.getRelatedAccountDeviceInstances(adiKey.getAccountDeviceInstance(), currentFilter); diff --git a/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java b/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java index 251f6382f7..d8c2a28091 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java @@ -83,6 +83,10 @@ final class LockedVertexModel { lockedVertices.clear(); } + boolean isEmpty() { + return lockedVertices.isEmpty(); + } + /** * Event that represents a change in the locked state of one or more * vertices. diff --git a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java index c76427aa62..325fbd51b9 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java @@ -22,13 +22,12 @@ import com.google.common.eventbus.Subscribe; import com.mxgraph.layout.hierarchical.mxHierarchicalLayout; import com.mxgraph.layout.mxCircleLayout; import com.mxgraph.layout.mxFastOrganicLayout; -import com.mxgraph.layout.mxGraphLayout; +import com.mxgraph.layout.mxIGraphLayout; import com.mxgraph.layout.mxOrganicLayout; import com.mxgraph.model.mxCell; import com.mxgraph.model.mxICell; import com.mxgraph.swing.handler.mxRubberband; import com.mxgraph.swing.mxGraphComponent; -import com.mxgraph.swing.util.mxMorphing; import com.mxgraph.util.mxEvent; import com.mxgraph.util.mxEventObject; import com.mxgraph.util.mxEventSource; @@ -90,6 +89,7 @@ import org.openide.util.lookup.ProxyLookup; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.progress.ModalDialogProgressIndicator; import org.sleuthkit.datamodel.CommunicationsFilter; @@ -133,18 +133,14 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider private final mxUndoManager undoManager = new mxUndoManager(); private final mxRubberband rubberband; //NOPMD We keep a referenec as insurance to prevent garbage collection - private final mxFastOrganicLayout fastOrganicLayout; - private final mxCircleLayout circleLayout; - private final mxOrganicLayout organicLayout; - private final mxHierarchicalLayout hierarchyLayout; @ThreadConfined(type = ThreadConfined.ThreadType.AWT) private SwingWorker worker; private final PinnedAccountModel pinnedAccountModel = new PinnedAccountModel(); private final LockedVertexModel lockedVertexModel = new LockedVertexModel(); - private final Map layoutButtons = new HashMap<>(); - private mxGraphLayout currentLayout; + private final Map layoutButtons = new HashMap<>(); + private NamedGraphLayout currentLayout; public VisualizationPanel() { initComponents(); @@ -192,14 +188,14 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider graph.getModel().addListener(mxEvent.UNDO, undoListener); graph.getView().addListener(mxEvent.UNDO, undoListener); - fastOrganicLayout = new mxFastOrganicLayoutImpl(graph); - circleLayout = new mxCircleLayoutImpl(graph); - organicLayout = new mxOrganicLayoutImpl(graph); + FastOrganicLayoutImpl fastOrganicLayout = new FastOrganicLayoutImpl(graph); + CircleLayoutImpl circleLayout = new CircleLayoutImpl(graph); + OrganicLayoutImpl organicLayout = new OrganicLayoutImpl(graph); organicLayout.setMaxIterations(10); - hierarchyLayout = new mxHierarchicalLayoutImpl(graph); + HierarchicalLayoutImpl hierarchyLayout = new HierarchicalLayoutImpl(graph); //local method to configure layout buttons - BiConsumer configure = (layoutButton, layout) -> { + BiConsumer configure = (layoutButton, layout) -> { layoutButtons.put(layout, layoutButton); layoutButton.addActionListener(event -> applyLayout(layout)); }; @@ -556,77 +552,52 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider /** * Apply the given layout. The given layout becomes the current layout. The - * layout is computed in the background and applied via mxMorphing. + * layout is computed in the background. * * @param layout The layout to apply. */ - @NbBundle.Messages({"Visualization.computingLayout=Computing Layout"}) - private void applyLayout(mxGraphLayout layout) { + @NbBundle.Messages({"VisualizationPanel.computingLayout=Computing Layout", + "# {0} - layout name", + "VisualizationPanel.layoutFailWithLockedVertices.text={0} layout failed with locked vertices. Unlock some vertices or try a different layout.", + "# {0} - layout name", + "VisualizationPanel.layoutFail.text={0} layout failed. Try a different layout."}) + private void applyLayout(NamedGraphLayout layout) { currentLayout = layout; layoutButtons.forEach((layoutKey, button) -> button.setFont(button.getFont().deriveFont(layoutKey == layout ? Font.BOLD : Font.PLAIN))); - // layout using morphing - graph.getModel().beginUpdate(); - CancelationListener cancelationListener = new CancelationListener(); - ModalDialogProgressIndicator progressIndicator = new ModalDialogProgressIndicator(windowAncestor, - Bundle.Visualization_computingLayout(), new String[]{CANCEL}, CANCEL, cancelationListener); - SwingWorker morphWorker = new SwingWorker() { - int progress = 0; - int max = 100; + ModalDialogProgressIndicator progressIndicator = new ModalDialogProgressIndicator(windowAncestor, Bundle.VisualizationPanel_computingLayout()); + progressIndicator.start(Bundle.VisualizationPanel_computingLayout()); + new SwingWorker() { @Override protected Void doInBackground() { - progressIndicator.start(Bundle.Visualization_computingLayout()); - layout.execute(graph.getDefaultParent()); - if (isCancelled()) { - progressIndicator.finish(); - return null; - } - - mxMorphing morph = new mxMorphing(graphComponent, 20, 1.2, 20) { - @Override - public void updateAnimation() { - fireEvent(new mxEventObject(mxEvent.EXECUTE)); - super.updateAnimation(); - if (isCancelled()) { - stopAnimation(); - } else { - progress++; - progressIndicator.switchToDeterminate(Bundle.Visualization_computingLayout(), progress, max); - if (progress >= max * 3.0 / 4.0) { - max *= 2; - } - } - } - }; - - morph.addListener(mxEvent.DONE, (Object sender, mxEventObject event) -> { + graph.getModel().beginUpdate(); + try { + layout.execute(graph.getDefaultParent()); + } finally { graph.getModel().endUpdate(); - if (isCancelled()) { - undoManager.undo(); - } else { - fitGraph(); - } progressIndicator.finish(); - }); - - morph.startAnimation(); + } return null; } @Override protected void done() { - super.done(); try { get(); + fitGraph(); } catch (InterruptedException | ExecutionException ex) { - logger.log(Level.SEVERE, "Layout interupted", ex); + logger.log(Level.WARNING, "CVT graph layout failed.", ex); + if (lockedVertexModel.isEmpty()) { + MessageNotifyUtil.Message.error(Bundle.VisualizationPanel_layoutFail_text(layout.getDisplayName())); + } else { + MessageNotifyUtil.Message.error(Bundle.VisualizationPanel_layoutFailWithLockedVertices_text(layout.getDisplayName())); + } + undoManager.undo(); } } - }; - cancelationListener.configure(morphWorker, progressIndicator); - morphWorker.execute(); + }.execute(); } private void clearVizButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_clearVizButtonActionPerformed @@ -662,9 +633,9 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider final Dimension size = graphComponent.getSize(); final double widthFactor = size.getWidth() / boundsForCells.getWidth(); + final double heightFactor = size.getHeight() / boundsForCells.getHeight(); - graphComponent.zoom(widthFactor); - + graphComponent.zoom((heightFactor + widthFactor) / 2.0); } @@ -738,12 +709,20 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider } } + /** + * Extend mxIGraphLayout with a getDisplayName method, + */ + private interface NamedGraphLayout extends mxIGraphLayout { + + String getDisplayName(); + } + /** * Extension of mxFastOrganicLayout that ignores locked vertices. */ - final private class mxFastOrganicLayoutImpl extends mxFastOrganicLayout { + final private class FastOrganicLayoutImpl extends mxFastOrganicLayout implements NamedGraphLayout { - mxFastOrganicLayoutImpl(mxGraph graph) { + FastOrganicLayoutImpl(mxGraph graph) { super(graph); } @@ -761,14 +740,19 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider return super.setVertexLocation(vertex, x, y); } } + + @Override + public String getDisplayName() { + return "Fast Organic"; + } } /** * Extension of mxCircleLayout that ignores locked vertices. */ - final private class mxCircleLayoutImpl extends mxCircleLayout { + final private class CircleLayoutImpl extends mxCircleLayout implements NamedGraphLayout { - mxCircleLayoutImpl(mxGraph graph) { + CircleLayoutImpl(mxGraph graph) { super(graph); setResetEdges(true); } @@ -787,14 +771,19 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider return super.setVertexLocation(vertex, x, y); } } + + @Override + public String getDisplayName() { + return "Circle"; + } } /** * Extension of mxOrganicLayout that ignores locked vertices. */ - final private class mxOrganicLayoutImpl extends mxOrganicLayout { + final private class OrganicLayoutImpl extends mxOrganicLayout implements NamedGraphLayout { - mxOrganicLayoutImpl(mxGraph graph) { + OrganicLayoutImpl(mxGraph graph) { super(graph); setResetEdges(true); } @@ -813,14 +802,19 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider return super.setVertexLocation(vertex, x, y); } } + + @Override + public String getDisplayName() { + return "Organic"; + } } /** * Extension of mxHierarchicalLayout that ignores locked vertices. */ - final private class mxHierarchicalLayoutImpl extends mxHierarchicalLayout { + final private class HierarchicalLayoutImpl extends mxHierarchicalLayout implements NamedGraphLayout { - mxHierarchicalLayoutImpl(mxGraph graph) { + HierarchicalLayoutImpl(mxGraph graph) { super(graph); } @@ -838,6 +832,11 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider return super.setVertexLocation(vertex, x, y); } } + + @Override + public String getDisplayName() { + return "Hierarchical"; + } } /** From 4379f81e176d3098b59411035d38405fdc052013 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Mon, 9 Apr 2018 16:51:59 +0200 Subject: [PATCH 11/11] call fitGraph() within transaction to avoid 'blip' --- .../sleuthkit/autopsy/communications/LockedVertexModel.java | 3 --- .../sleuthkit/autopsy/communications/VisualizationPanel.java | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java b/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java index d8c2a28091..7d8b8c083d 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java @@ -21,9 +21,6 @@ package org.sleuthkit.autopsy.communications; import com.google.common.collect.ImmutableSet; import com.google.common.eventbus.EventBus; import com.mxgraph.model.mxCell; -import com.mxgraph.util.mxPoint; -import com.mxgraph.util.mxRectangle; -import com.mxgraph.view.mxGraph; import java.util.Collection; import java.util.HashSet; import java.util.Set; diff --git a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java index 325fbd51b9..4f6b53ae39 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java @@ -575,6 +575,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider graph.getModel().beginUpdate(); try { layout.execute(graph.getDefaultParent()); + fitGraph(); } finally { graph.getModel().endUpdate(); progressIndicator.finish(); @@ -586,7 +587,6 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider protected void done() { try { get(); - fitGraph(); } catch (InterruptedException | ExecutionException ex) { logger.log(Level.WARNING, "CVT graph layout failed.", ex); if (lockedVertexModel.isEmpty()) {