mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-13 08:26:15 +00:00
multiselect for locking. Not updating the icon properly...
This commit is contained in:
parent
1882690b72
commit
f3161c7af6
@ -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<String, mxCell> nodeMap = new HashMap<>();
|
||||
|
||||
/* Map from relationship source (Content) to mxCell (edge). */
|
||||
/** Map from relationship source (Content) to mxCell (edge). */
|
||||
private final Multimap<Content, mxCell> 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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<VertexLockEvent> handler) {
|
||||
eventBus.register(handler);
|
||||
@ -42,30 +52,26 @@ class LockedVertexModel {
|
||||
*/
|
||||
private final Set<mxCell> 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<mxCell> 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<mxCell> 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<mxCell> vertices;
|
||||
|
||||
public mxCell getVertex() {
|
||||
return vertex;
|
||||
public Set<mxCell> 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;
|
||||
}
|
||||
}
|
||||
|
@ -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<AccountDeviceInstanceKey> pinnedAccountDevices = new HashSet<>();
|
||||
private final CommunicationsGraph graph;
|
||||
|
||||
PinnedAccountModel(CommunicationsGraph graph) {
|
||||
this.graph = graph;
|
||||
}
|
||||
|
||||
boolean isAccountPinned(AccountDeviceInstanceKey account) {
|
||||
return pinnedAccountDevices.contains(account);
|
||||
|
@ -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<mxCell> 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<mxCell> 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<Void, Void> morphWorker = new SwingWorker<Void, Void>() {
|
||||
@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<mxCell> selectedVertices;
|
||||
|
||||
UnlockAction(Set<mxCell> 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<mxCell> selectedVertices;
|
||||
|
||||
LockAction(Set<mxCell> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user