mirror of
https://github.com/elisspace/autopsy.git
synced 2026-09-29 13:59:52 +00:00
Added the new MessageBrowser to the VisualizationPanel
This commit is contained in:
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2017 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> 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.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.python.google.common.collect.Iterables;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.AccountDeviceInstance;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.CommunicationsFilter;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* 'Root' Node for the Account/Messages area. Has children which are all the
|
||||
* relationships of all the accounts in this node.
|
||||
*
|
||||
*/
|
||||
final class AccountDetailsNode extends AbstractNode {
|
||||
|
||||
private final static Logger logger = Logger.getLogger(AccountDetailsNode.class.getName());
|
||||
|
||||
AccountDetailsNode(Set<AccountDeviceInstance> accountDeviceInstances, CommunicationsFilter filter, CommunicationsManager commsManager) {
|
||||
super(Children.create(new AccountRelationshipChildren(accountDeviceInstances, commsManager, filter), true));
|
||||
String displayName = (accountDeviceInstances.size() == 1)
|
||||
? Iterables.getOnlyElement(accountDeviceInstances).getAccount().getTypeSpecificID()
|
||||
: accountDeviceInstances.size() + " accounts";
|
||||
setDisplayName(displayName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Children object for the relationships that the accounts are part of.
|
||||
*/
|
||||
private static class AccountRelationshipChildren extends ChildFactory<Content> {
|
||||
|
||||
private final Set<AccountDeviceInstance> accountDeviceInstances;
|
||||
private final CommunicationsManager commsManager;
|
||||
private final CommunicationsFilter filter;
|
||||
|
||||
private AccountRelationshipChildren(Set<AccountDeviceInstance> accountDeviceInstances, CommunicationsManager commsManager, CommunicationsFilter filter) {
|
||||
this.accountDeviceInstances = accountDeviceInstances;
|
||||
this.commsManager = commsManager;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<Content> list) {
|
||||
try {
|
||||
list.addAll(commsManager.getRelationshipSources(accountDeviceInstances, filter));
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error getting communications", ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(Content t) {
|
||||
if (t instanceof BlackboardArtifact) {
|
||||
return new RelationshipNode((BlackboardArtifact) t);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Cannot create a RelationshipNode for non BlackboardArtifact content.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
package org.sleuthkit.autopsy.communications;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.util.List;
|
||||
@@ -61,8 +62,11 @@ public final class CVTTopComponent extends TopComponent {
|
||||
associateLookup(proxyLookup);
|
||||
// Make sure the Global Actions Context is proxying the selection of the active tab.
|
||||
browseVisualizeTabPane.addChangeListener(changeEvent -> {
|
||||
Lookup.Provider selectedComponent = (Lookup.Provider) browseVisualizeTabPane.getSelectedComponent();
|
||||
proxyLookup.setNewLookups(selectedComponent.getLookup());
|
||||
Component selectedComponent = browseVisualizeTabPane.getSelectedComponent();
|
||||
if(selectedComponent instanceof Lookup.Provider) {
|
||||
Lookup lookup = ((Lookup.Provider)selectedComponent).getLookup();
|
||||
proxyLookup.setNewLookups(lookup);
|
||||
}
|
||||
filtersPane.setDeviceAccountTypeEnabled(browseVisualizeTabPane.getSelectedIndex() != 0);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.4" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
|
||||
<Component id="splitPane" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
|
||||
<Component id="splitPane" pref="1083" max="32767" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JSplitPane" name="splitPane">
|
||||
<Properties>
|
||||
<Property name="dividerLocation" type="int" value="400"/>
|
||||
<Property name="dividerSize" type="int" value="10"/>
|
||||
<Property name="orientation" type="int" value="0"/>
|
||||
<Property name="resizeWeight" type="double" value="0.5"/>
|
||||
</Properties>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="org.sleuthkit.autopsy.communications.MessageDataContent" name="messageDataContent">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
|
||||
<JSplitPaneConstraints position="bottom"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
@@ -1,231 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2017-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> 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 obt ain 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.Component;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.swing.JPanel;
|
||||
import static javax.swing.SwingUtilities.isDescendingFrom;
|
||||
import org.openide.explorer.ExplorerManager;
|
||||
import static org.openide.explorer.ExplorerUtils.createLookup;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.corecomponents.DataResultPanel;
|
||||
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
|
||||
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
|
||||
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
|
||||
|
||||
/**
|
||||
* The right hand side of the CVT. Has a DataResultPanel to show a listing of
|
||||
* messages and other account details, and a ContentViewer to show individual
|
||||
* messages.
|
||||
*/
|
||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||
public final class MessageBrowser extends JPanel implements ExplorerManager.Provider, Lookup.Provider {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final ExplorerManager tableEM;
|
||||
private final ExplorerManager gacExplorerManager;
|
||||
private final DataResultPanel messagesResultPanel;
|
||||
/* lookup that will be exposed through the (Global Actions Context) */
|
||||
private final ModifiableProxyLookup proxyLookup = new ModifiableProxyLookup();
|
||||
|
||||
private final PropertyChangeListener focusPropertyListener = new PropertyChangeListener() {
|
||||
/**
|
||||
* Listener that keeps the proxyLookup in sync with the focused area of
|
||||
* the UI.
|
||||
*
|
||||
* Since the embedded MessageContentViewer (attachments panel) is not in
|
||||
* its own TopComponenet, its selection does not get proxied into the
|
||||
* Global Actions Context (GAC), and many of the available actions don't
|
||||
* work on it. Further, we can't put the selection from both the
|
||||
* Messages table and the Attachments table in the GAC because they
|
||||
* could both include AbstractFiles, muddling the selection seen by the
|
||||
* actions. Instead, depending on where the focus is in the window, we
|
||||
* want to put different Content in the Global Actions Context to be
|
||||
* picked up by, e.g., the tagging actions. The best way I could figure
|
||||
* to do this was to listen to all focus events and swap out what is in
|
||||
* the lookup appropriately. An alternative to this would be to
|
||||
* investigate using the ContextAwareAction interface.
|
||||
*
|
||||
* @see org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a
|
||||
* similar situation and a similar solution.
|
||||
*
|
||||
* @param focusEvent The focus change event.
|
||||
*/
|
||||
@Override
|
||||
public void propertyChange(final PropertyChangeEvent focusEvent) {
|
||||
if (focusEvent.getPropertyName().equalsIgnoreCase("focusOwner")) {
|
||||
final Component newFocusOwner = (Component) focusEvent.getNewValue();
|
||||
|
||||
if (newFocusOwner == null) {
|
||||
return;
|
||||
}
|
||||
if (isDescendingFrom(newFocusOwner, messageDataContent)) {
|
||||
//if the focus owner is within the MessageContentViewer ( the attachments table)
|
||||
proxyLookup.setNewLookups(createLookup(messageDataContent.getExplorerManager(), getActionMap()));
|
||||
} else if (isDescendingFrom(newFocusOwner, messagesResultPanel)) {
|
||||
//... or if it is within the Messages table.
|
||||
proxyLookup.setNewLookups(createLookup(gacExplorerManager, getActionMap()));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs the right hand side of the Communications Visualization Tool
|
||||
* (CVT).
|
||||
*
|
||||
* @param tableEM An explorer manager to listen to as the driver
|
||||
* of the Message Table.
|
||||
* @param gacExplorerManager An explorer manager associated with the
|
||||
* GlobalActionsContext (GAC) so that selections
|
||||
* in the messages browser can be exposed to
|
||||
* context-sensitive actions.
|
||||
*/
|
||||
@NbBundle.Messages({"MessageBrowser.DataResultViewerTable.title=Messages"})
|
||||
MessageBrowser(final ExplorerManager tableEM, final ExplorerManager gacExplorerManager) {
|
||||
this.tableEM = tableEM;
|
||||
this.gacExplorerManager = gacExplorerManager;
|
||||
initComponents();
|
||||
//create an uninitialized DataResultPanel so we can control the ResultViewers that get added.
|
||||
messagesResultPanel = DataResultPanel.createInstanceUninitialized("Account", "", Node.EMPTY, 0, messageDataContent);
|
||||
splitPane.setTopComponent(messagesResultPanel);
|
||||
splitPane.setBottomComponent(messageDataContent);
|
||||
messagesResultPanel.addResultViewer(new DataResultViewerTable(gacExplorerManager,
|
||||
Bundle.MessageBrowser_DataResultViewerTable_title()));
|
||||
messagesResultPanel.open();
|
||||
|
||||
this.tableEM.addPropertyChangeListener(new PropertyChangeListener() {
|
||||
/**
|
||||
* Listener that pushes selections in the tableEM (the Accounts
|
||||
* table) into the Messages table.
|
||||
*
|
||||
* @param pce The ExplorerManager event.
|
||||
*/
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent pce) {
|
||||
if (pce.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
|
||||
final Node[] selectedNodes = MessageBrowser.this.tableEM.getSelectedNodes();
|
||||
messagesResultPanel.setNumberOfChildNodes(0);
|
||||
messagesResultPanel.setNode(null);
|
||||
messagesResultPanel.setPath("");
|
||||
if (selectedNodes.length > 0) {
|
||||
Node rootNode;
|
||||
final Node selectedNode = selectedNodes[0];
|
||||
|
||||
if (selectedNode instanceof AccountDeviceInstanceNode) {
|
||||
rootNode = makeRootNodeFromAccountDeviceInstanceNodes(selectedNodes);
|
||||
} else {
|
||||
rootNode = selectedNode;
|
||||
}
|
||||
messagesResultPanel.setPath(rootNode.getDisplayName());
|
||||
messagesResultPanel.setNode(new TableFilterNode(new DataResultFilterNode(rootNode, gacExplorerManager), true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Node makeRootNodeFromAccountDeviceInstanceNodes(final Node[] selectedNodes) {
|
||||
//Use lookup here?
|
||||
final AccountDeviceInstanceNode adiNode = (AccountDeviceInstanceNode) selectedNodes[0];
|
||||
|
||||
final Set<AccountDeviceInstanceKey> accountDeviceInstances = new HashSet<>();
|
||||
for (final Node n : selectedNodes) {
|
||||
//Use lookup here?
|
||||
accountDeviceInstances.add(((AccountDeviceInstanceNode) n).getAccountDeviceInstanceKey());
|
||||
}
|
||||
return SelectionNode.createFromAccounts(accountDeviceInstances, adiNode.getFilter(), adiNode.getCommsManager());
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExplorerManager getExplorerManager() {
|
||||
return gacExplorerManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lookup getLookup() {
|
||||
return proxyLookup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotify() {
|
||||
super.addNotify();
|
||||
//add listener that maintains correct selection in the Global Actions Context
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager()
|
||||
.addPropertyChangeListener("focusOwner", focusPropertyListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotify() {
|
||||
super.removeNotify();
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager()
|
||||
.removePropertyChangeListener("focusOwner", focusPropertyListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
splitPane = new javax.swing.JSplitPane();
|
||||
messageDataContent = new org.sleuthkit.autopsy.communications.MessageDataContent();
|
||||
|
||||
splitPane.setDividerLocation(400);
|
||||
splitPane.setDividerSize(10);
|
||||
splitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
|
||||
splitPane.setResizeWeight(0.5);
|
||||
splitPane.setBottomComponent(messageDataContent);
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(splitPane))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(splitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 1083, Short.MAX_VALUE)
|
||||
.addGap(0, 0, 0))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private org.sleuthkit.autopsy.communications.MessageDataContent messageDataContent;
|
||||
private javax.swing.JSplitPane splitPane;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
}
|
||||
@@ -48,7 +48,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
*/
|
||||
final class MessageNode extends BlackboardArtifactNode {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(RelationshipNode.class.getName());
|
||||
private static final Logger logger = Logger.getLogger(MessageNode.class.getName());
|
||||
|
||||
MessageNode(BlackboardArtifact artifact) {
|
||||
super(artifact);
|
||||
|
||||
@@ -109,6 +109,9 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer,
|
||||
if (nodes != null && nodes.length > 0) {
|
||||
contentViewer.setNode(nodes[0]);
|
||||
}
|
||||
else {
|
||||
contentViewer.setNode(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -127,7 +130,6 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer,
|
||||
|
||||
@Override
|
||||
public void setSelectionInfo(SelectionInfo info) {
|
||||
// tableEM.setRootContext(new TableFilterNode(new DataResultFilterNode(new AbstractNode(Children.create(new MessagesChildNodeFactory(info), true)), getExplorerManager()), true));
|
||||
nodeFactory.refresh(info);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
package org.sleuthkit.autopsy.communications;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import org.openide.util.Lookup;
|
||||
|
||||
/**
|
||||
* Displays the Relationship information for the currently selected accounts.
|
||||
@@ -28,16 +27,21 @@ import org.openide.util.Lookup;
|
||||
final class RelationshipBrowser extends JPanel {
|
||||
|
||||
private SelectionInfo currentSelection;
|
||||
|
||||
private final MessagesViewer messagesViewer;
|
||||
private final ContactsViewer contactsViewer;
|
||||
|
||||
/**
|
||||
* Creates new form RelationshipBrowser
|
||||
*/
|
||||
public RelationshipBrowser() {
|
||||
initComponents();
|
||||
|
||||
Lookup.getDefault().lookupAll(RelationshipsViewer.class).forEach((viewer) -> {
|
||||
tabPane.add(viewer.getDisplayName(), viewer.getPanel());
|
||||
});
|
||||
|
||||
messagesViewer = new MessagesViewer();
|
||||
contactsViewer = new ContactsViewer();
|
||||
|
||||
tabPane.add(messagesViewer.getDisplayName(), messagesViewer);
|
||||
tabPane.add(contactsViewer.getDisplayName(), contactsViewer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,7 +85,9 @@ final class RelationshipBrowser extends JPanel {
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void tabPaneStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_tabPaneStateChanged
|
||||
((RelationshipsViewer) tabPane.getSelectedComponent()).setSelectionInfo(currentSelection);
|
||||
if(currentSelection != null) {
|
||||
((RelationshipsViewer) tabPane.getSelectedComponent()).setSelectionInfo(currentSelection);
|
||||
}
|
||||
}//GEN-LAST:event_tabPaneStateChanged
|
||||
|
||||
|
||||
|
||||
@@ -1,174 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2017-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> 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.util.List;
|
||||
import java.util.TimeZone;
|
||||
import java.util.logging.Level;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_FROM;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_TO;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME;
|
||||
import org.sleuthkit.datamodel.Tag;
|
||||
import org.sleuthkit.datamodel.TimeUtilities;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Node for a relationship, as represented by a BlackboardArtifact.
|
||||
*/
|
||||
final class RelationshipNode extends BlackboardArtifactNode {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(RelationshipNode.class.getName());
|
||||
|
||||
RelationshipNode(BlackboardArtifact artifact) {
|
||||
super(artifact);
|
||||
final String stripEnd = StringUtils.stripEnd(artifact.getDisplayName(), "s");
|
||||
String removeEndIgnoreCase = StringUtils.removeEndIgnoreCase(stripEnd, "message");
|
||||
setDisplayName(removeEndIgnoreCase.isEmpty() ? stripEnd : removeEndIgnoreCase);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet sheet = new Sheet();
|
||||
List<Tag> tags = getAllTagsFromDatabase();
|
||||
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
|
||||
if (sheetSet == null) {
|
||||
sheetSet = Sheet.createPropertiesSet();
|
||||
sheet.put(sheetSet);
|
||||
}
|
||||
|
||||
sheetSet.put(new NodeProperty<>("Type", "Type", "Type", getDisplayName()));
|
||||
|
||||
addScoreProperty(sheetSet, tags);
|
||||
|
||||
CorrelationAttributeInstance correlationAttribute = null;
|
||||
if (UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
|
||||
correlationAttribute = getCorrelationAttributeInstance();
|
||||
}
|
||||
addCommentProperty(sheetSet, tags, correlationAttribute);
|
||||
|
||||
if (UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
|
||||
addCountProperty(sheetSet, correlationAttribute);
|
||||
}
|
||||
final BlackboardArtifact artifact = getArtifact();
|
||||
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(getArtifact().getArtifactTypeID());
|
||||
if (null != fromID) {
|
||||
//Consider refactoring this to reduce boilerplate
|
||||
switch (fromID) {
|
||||
case TSK_EMAIL_MSG:
|
||||
sheetSet.put(new NodeProperty<>("From", "From", "From",
|
||||
StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_FROM), " \t\n;")));
|
||||
sheetSet.put(new NodeProperty<>("To", "To", "To",
|
||||
StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_TO), " \t\n;")));
|
||||
sheetSet.put(new NodeProperty<>("Date", "Date", "Date",
|
||||
getAttributeDisplayString(artifact, TSK_DATETIME_SENT)));
|
||||
sheetSet.put(new NodeProperty<>("Subject", "Subject", "Subject",
|
||||
getAttributeDisplayString(artifact, TSK_SUBJECT)));
|
||||
try {
|
||||
sheetSet.put(new NodeProperty<>("Attms", "Attms", "Attms", artifact.getChildrenCount()));
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex);
|
||||
}
|
||||
|
||||
break;
|
||||
case TSK_MESSAGE:
|
||||
sheetSet.put(new NodeProperty<>("From", "From", "From",
|
||||
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM)));
|
||||
sheetSet.put(new NodeProperty<>("To", "To", "To",
|
||||
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO)));
|
||||
sheetSet.put(new NodeProperty<>("Date", "Date", "Date",
|
||||
getAttributeDisplayString(artifact, TSK_DATETIME)));
|
||||
sheetSet.put(new NodeProperty<>("Subject", "Subject", "Subject",
|
||||
getAttributeDisplayString(artifact, TSK_SUBJECT)));
|
||||
try {
|
||||
sheetSet.put(new NodeProperty<>("Attms", "Attms", "Attms", artifact.getChildrenCount()));
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex);
|
||||
}
|
||||
break;
|
||||
case TSK_CALLLOG:
|
||||
sheetSet.put(new NodeProperty<>("From", "From", "From",
|
||||
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM)));
|
||||
sheetSet.put(new NodeProperty<>("To", "To", "To",
|
||||
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO)));
|
||||
sheetSet.put(new NodeProperty<>("Date", "Date", "Date",
|
||||
getAttributeDisplayString(artifact, TSK_DATETIME_START)));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return sheet;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Get the display string for the attribute of the given type from the given
|
||||
* artifact.
|
||||
*
|
||||
* @param artifact the value of artifact
|
||||
* @param attributeType the value of TSK_SUBJECT1
|
||||
*
|
||||
* @return The display string, or an empty string if there is no such
|
||||
* attribute or an an error.
|
||||
*/
|
||||
private static String getAttributeDisplayString(final BlackboardArtifact artifact, final ATTRIBUTE_TYPE attributeType) {
|
||||
try {
|
||||
BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(attributeType.getTypeID())));
|
||||
if (attribute == null) {
|
||||
return "";
|
||||
} else if (attributeType.getValueType() == DATETIME) {
|
||||
return TimeUtilities.epochToTime(attribute.getValueLong(),
|
||||
TimeZone.getTimeZone(Utils.getUserPreferredZoneId()));
|
||||
} else {
|
||||
return attribute.getDisplayString();
|
||||
}
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
logger.log(Level.WARNING, "Error getting attribute value.", tskCoreException);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Circumvent DataResultFilterNode's slightly odd delegation to
|
||||
* BlackboardArtifactNode.getSourceName().
|
||||
*
|
||||
* @return the displayName of this Node, which is the type.
|
||||
*/
|
||||
@Override
|
||||
public String getSourceName() {
|
||||
return getDisplayName();
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> 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 com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Sets;
|
||||
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;
|
||||
import org.sleuthkit.datamodel.CommunicationsFilter;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* 'Root' Node for the Account/Messages area. Represents all the relationships
|
||||
* that are selected in the AccountsBrowser or the VisualizationPanel. Can be
|
||||
* populated with AccountDeviceInstance and/or directly with relationships
|
||||
* (Content).
|
||||
*/
|
||||
final class SelectionNode extends AbstractNode {
|
||||
|
||||
private SelectionNode(Children children, Lookup lookup) {
|
||||
super(children, lookup);
|
||||
}
|
||||
|
||||
static SelectionNode createFromAccountsAndRelationships(
|
||||
Set<Content> edgeRelationshipArtifacts,
|
||||
Set<AccountDeviceInstanceKey> accountDeviceInstanceKeys,
|
||||
CommunicationsFilter filter,
|
||||
CommunicationsManager commsManager) {
|
||||
|
||||
Set<AccountDeviceInstance> accountDeviceInstances = accountDeviceInstanceKeys.stream()
|
||||
.map(AccountDeviceInstanceKey::getAccountDeviceInstance)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
SelectionNode node = new SelectionNode(Children.create(
|
||||
new RelationshipChildren(
|
||||
edgeRelationshipArtifacts,
|
||||
accountDeviceInstances,
|
||||
commsManager,
|
||||
filter),
|
||||
true), Lookups.fixed(accountDeviceInstanceKeys.toArray()));
|
||||
|
||||
//This is not good for internationalization!!!
|
||||
String name = "";
|
||||
final int accounts = accountDeviceInstances.size();
|
||||
if (accounts > 1) {
|
||||
name = accounts + " accounts";
|
||||
} else if (accounts == 1) {
|
||||
name = Iterables.getOnlyElement(accountDeviceInstances).getAccount().getTypeSpecificID();
|
||||
}
|
||||
|
||||
final int edges = edgeRelationshipArtifacts.size();
|
||||
|
||||
if (edges > 0) {
|
||||
name = name + (name.isEmpty() ? "" : " and ") + edges + " relationship" + (edges > 1 ? "s" : "");
|
||||
}
|
||||
|
||||
node.setDisplayName(name);
|
||||
return node;
|
||||
}
|
||||
|
||||
static SelectionNode createFromAccounts(
|
||||
Set<AccountDeviceInstanceKey> accountDeviceInstances,
|
||||
CommunicationsFilter filter,
|
||||
CommunicationsManager commsManager) {
|
||||
|
||||
return createFromAccountsAndRelationships(Collections.emptySet(), accountDeviceInstances, filter, commsManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Children object for the relationships that the accounts are part of.
|
||||
*/
|
||||
private static class RelationshipChildren extends ChildFactory<Content> {
|
||||
|
||||
static final private Logger logger = Logger.getLogger(RelationshipChildren.class.getName());
|
||||
|
||||
private final Set<Content> edgeRelationshipArtifacts;
|
||||
|
||||
private final Set<AccountDeviceInstance> accountDeviceInstances;
|
||||
|
||||
private final CommunicationsManager commsManager;
|
||||
private final CommunicationsFilter filter;
|
||||
|
||||
private RelationshipChildren(Set<Content> selectedEdgeRelationshipSources, Set<AccountDeviceInstance> selecedAccountDeviceInstances, CommunicationsManager commsManager, CommunicationsFilter filter) {
|
||||
this.edgeRelationshipArtifacts = selectedEdgeRelationshipSources;
|
||||
this.accountDeviceInstances = selecedAccountDeviceInstances;
|
||||
this.commsManager = commsManager;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<Content> list) {
|
||||
try {
|
||||
final Set<Content> relationshipSources = commsManager.getRelationshipSources(accountDeviceInstances, filter);
|
||||
list.addAll(Sets.union(relationshipSources, edgeRelationshipArtifacts));
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error getting communications", ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,6 @@ import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyVetoException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@@ -63,11 +62,11 @@ import java.nio.file.Paths;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
@@ -99,12 +98,8 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.controlsfx.control.Notifications;
|
||||
import org.jdesktop.layout.GroupLayout;
|
||||
import org.jdesktop.layout.LayoutStyle;
|
||||
import org.openide.explorer.ExplorerManager;
|
||||
import org.openide.explorer.ExplorerUtils;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.ProxyLookup;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
@@ -113,9 +108,9 @@ import org.sleuthkit.autopsy.coreutils.FileUtil;
|
||||
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;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
/**
|
||||
* A panel that goes in the Visualize tab of the Communications Visualization
|
||||
@@ -128,7 +123,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
* actions to work correctly.
|
||||
*/
|
||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||
final public class VisualizationPanel extends JPanel implements Lookup.Provider {
|
||||
final public class VisualizationPanel extends JPanel {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger logger = Logger.getLogger(VisualizationPanel.class.getName());
|
||||
@@ -141,9 +136,6 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
|
||||
@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;
|
||||
@@ -162,6 +154,8 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
|
||||
|
||||
private final Map<NamedGraphLayout, JButton> layoutButtons = new HashMap<>();
|
||||
private NamedGraphLayout currentLayout;
|
||||
|
||||
private final RelationshipBrowser relationshipBrowser;
|
||||
|
||||
@NbBundle.Messages("VisalizationPanel.paintingError=Problem painting visualization.")
|
||||
public VisualizationPanel() {
|
||||
@@ -224,13 +218,9 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
|
||||
final GraphMouseListener graphMouseListener = new GraphMouseListener();
|
||||
graphComponent.getGraphControl().addMouseWheelListener(graphMouseListener);
|
||||
graphComponent.getGraphControl().addMouseListener(graphMouseListener);
|
||||
|
||||
final MessageBrowser messageBrowser = new MessageBrowser(vizEM, gacEM);
|
||||
splitPane.setRightComponent(messageBrowser);
|
||||
proxyLookup = new ProxyLookup(
|
||||
ExplorerUtils.createLookup(vizEM, getActionMap()),
|
||||
messageBrowser.getLookup()
|
||||
);
|
||||
|
||||
relationshipBrowser = new RelationshipBrowser();
|
||||
splitPane.setRightComponent(relationshipBrowser);
|
||||
|
||||
//feed selection to explorermanager
|
||||
graph.getSelectionModel().addListener(mxEvent.CHANGE, new SelectionListener());
|
||||
@@ -259,12 +249,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
|
||||
|
||||
applyLayout(fastOrganicLayout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lookup getLookup() {
|
||||
return proxyLookup;
|
||||
}
|
||||
|
||||
|
||||
@Subscribe
|
||||
void handle(LockedVertexModel.VertexLockEvent event) {
|
||||
final Set<mxCell> vertices = event.getVertices();
|
||||
@@ -884,40 +869,25 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
|
||||
@Override
|
||||
public void invoke(Object sender, mxEventObject evt) {
|
||||
Object[] selectionCells = graph.getSelectionCells();
|
||||
Node rootNode = Node.EMPTY;
|
||||
Node[] selectedNodes = new Node[0];
|
||||
if (selectionCells.length > 0) {
|
||||
mxICell[] selectedCells = Arrays.asList(selectionCells).toArray(new mxCell[selectionCells.length]);
|
||||
HashSet<Content> relationshipSources = new HashSet<>();
|
||||
HashSet<AccountDeviceInstanceKey> adis = new HashSet<>();
|
||||
HashSet<AccountDeviceInstance> deviceInstances = new HashSet<>();
|
||||
for (mxICell cell : selectedCells) {
|
||||
if (cell.isEdge()) {
|
||||
mxICell source = (mxICell) graph.getModel().getTerminal(cell, true);
|
||||
AccountDeviceInstanceKey account1 = (AccountDeviceInstanceKey) source.getValue();
|
||||
mxICell target = (mxICell) graph.getModel().getTerminal(cell, false);
|
||||
AccountDeviceInstanceKey account2 = (AccountDeviceInstanceKey) target.getValue();
|
||||
try {
|
||||
final List<Content> relationshipSources1 = commsManager.getRelationshipSources(
|
||||
account1.getAccountDeviceInstance(),
|
||||
account2.getAccountDeviceInstance(),
|
||||
currentFilter);
|
||||
relationshipSources.addAll(relationshipSources1);
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
logger.log(Level.SEVERE, " Error getting relationsips....", tskCoreException);
|
||||
}
|
||||
|
||||
deviceInstances.add(((AccountDeviceInstanceKey) source.getValue()).getAccountDeviceInstance());
|
||||
deviceInstances.add(((AccountDeviceInstanceKey) target.getValue()).getAccountDeviceInstance());
|
||||
|
||||
} else if (cell.isVertex()) {
|
||||
adis.add((AccountDeviceInstanceKey) cell.getValue());
|
||||
deviceInstances.add(((AccountDeviceInstanceKey) cell.getValue()).getAccountDeviceInstance());
|
||||
}
|
||||
}
|
||||
|
||||
rootNode = SelectionNode.createFromAccountsAndRelationships(relationshipSources, adis, currentFilter, commsManager);
|
||||
selectedNodes = new Node[]{rootNode};
|
||||
}
|
||||
vizEM.setRootContext(rootNode);
|
||||
try {
|
||||
vizEM.setSelectedNodes(selectedNodes);
|
||||
} catch (PropertyVetoException ex) {
|
||||
logger.log(Level.SEVERE, "Selection vetoed.", ex);
|
||||
relationshipBrowser.setSelectionInfo(new SelectionInfo(deviceInstances, currentFilter));
|
||||
} else {
|
||||
relationshipBrowser.setSelectionInfo(new SelectionInfo(Collections.EMPTY_SET, currentFilter));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user