Enable actions on Attachements

This commit is contained in:
millmanorama 2018-03-14 10:57:02 +01:00
parent fafc9131d8
commit 3eaa5f1017
8 changed files with 152 additions and 39 deletions

View File

@ -84,11 +84,12 @@ public final class AccountsBrowser extends JPanel implements ExplorerManager.Pro
SwingUtilities.invokeLater(this::setColumnWidths);
}
});
final MessageBrowser messageBrowser = new MessageBrowser(accountsTableEM, messageBrowserEM);
jSplitPane1.setRightComponent(new MessageBrowser(accountsTableEM, messageBrowserEM));
jSplitPane1.setRightComponent(messageBrowser);
proxyLookup = new ProxyLookup(
ExplorerUtils.createLookup(messageBrowserEM, getActionMap()),
messageBrowser.getLookup(),
ExplorerUtils.createLookup(accountsTableEM, getActionMap()));
}

View File

@ -29,7 +29,6 @@ import javax.swing.JTabbedPane;
import javax.swing.LayoutStyle;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ProxyLookup;
import org.openide.windows.Mode;
import org.openide.windows.RetainLocation;
import org.openide.windows.TopComponent;
@ -57,12 +56,12 @@ public final class CVTTopComponent extends TopComponent {
* selections in the sub views can be exposed to context-sensitive
* actions.
*/
ProxyLookupImpl proxyLookup = new ProxyLookupImpl(accountsBrowser.getLookup());
ModifiableProxyLookup proxyLookup = new ModifiableProxyLookup(accountsBrowser.getLookup());
associateLookup(proxyLookup);
// Make sure the GAC is proxying the selection of the active tab.
// 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.changeLookups(selectedComponent.getLookup());
proxyLookup.setNewLookups(selectedComponent.getLookup());
filtersPane.setDeviceAccountTypeEnabled(browseVisualizeTabPane.getSelectedIndex() != 0);
});
@ -159,25 +158,4 @@ public final class CVTTopComponent extends TopComponent {
return modes.stream().filter(mode -> mode.getName().equals("cvt"))
.collect(Collectors.toList());
}
/**
* Extension of ProxyLookup that exposes the ability to change the Lookups
* delegated to.
*
*/
final private static class ProxyLookupImpl extends ProxyLookup {
ProxyLookupImpl(Lookup... lookups) {
super(lookups);
}
/**
* Set the Lookups delegated to by this lookup.
*
* @param lookups The new Lookups to delegate to.
*/
protected void changeLookups(Lookup... lookups) {
setLookups(lookups);
}
}
}

View File

@ -18,13 +18,18 @@
*/
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;
@ -33,15 +38,25 @@ import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
import org.sleuthkit.datamodel.AccountDeviceInstance;
/**
* The right hand side of the CVT. Has a DataResultPanel to show messages and
* other account details, and a ContentViewer to show individual
* 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.
*/
public final class MessageBrowser extends JPanel implements ExplorerManager.Provider {
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();
/**
* Listener that keeps the proxyLookup in sync with the focused area of the
* UI.
*/
private final FocusPropertyListener focusPropertyListener = new FocusPropertyListener();
/**
* Constructs the right hand side of the Communications Visualization Tool
@ -67,6 +82,10 @@ public final class MessageBrowser extends JPanel implements ExplorerManager.Prov
Bundle.MessageBrowser_DataResultViewerTable_title()));
messagesResultPanel.open();
//add listener that maintains correct selection in the Global Actions Context
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.addPropertyChangeListener("focusOwner", focusPropertyListener);
this.tableEM.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent pce) {
@ -101,7 +120,8 @@ public final class MessageBrowser extends JPanel implements ExplorerManager.Prov
}
return SelectionNode.createFromAccounts(accountDeviceInstances, adiNode.getFilter(), adiNode.getCommsManager());
}
});
}
);
}
@Override
@ -109,6 +129,18 @@ public final class MessageBrowser extends JPanel implements ExplorerManager.Prov
return gacExplorerManager;
}
@Override
public Lookup getLookup() {
return proxyLookup;
}
@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
@ -150,4 +182,38 @@ public final class MessageBrowser extends JPanel implements ExplorerManager.Prov
private javax.swing.JSplitPane splitPane;
// End of variables declaration//GEN-END:variables
/**
* 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 include have
* 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.
*/
private class FocusPropertyListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent propertyChangeEvent) {
if (propertyChangeEvent.getPropertyName().equalsIgnoreCase("focusOwner")) {
Component newFocusOwner = (Component) propertyChangeEvent.getNewValue();
if (newFocusOwner != null) {
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()));
}
}
}
}
}
}

View File

@ -19,6 +19,7 @@
package org.sleuthkit.autopsy.communications;
import java.beans.PropertyChangeEvent;
import org.openide.explorer.ExplorerManager;
import org.sleuthkit.autopsy.contentviewers.MessageContentViewer;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent;
@ -26,12 +27,18 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent;
* Extends MessageContentViewer so that it implements DataContent and can be set
* as the only ContentViewer for a DataResultPanel
*/
final class MessageDataContent extends MessageContentViewer implements DataContent {
final class MessageDataContent extends MessageContentViewer implements DataContent, ExplorerManager.Provider {
private static final long serialVersionUID = 1L;
private ExplorerManager em = new ExplorerManager();
@Override
public void propertyChange(PropertyChangeEvent evt) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public ExplorerManager getExplorerManager() {
return em;
}
}

View File

@ -0,0 +1,43 @@
/*
* 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 org.openide.util.Lookup;
import org.openide.util.lookup.ProxyLookup;
/**
* Extension of ProxyLookup that exposes the ability to change the Lookups
* delegated to.
*
*/
final class ModifiableProxyLookup extends ProxyLookup {
ModifiableProxyLookup(Lookup... lookups) {
super(lookups);
}
/**
* Set the Lookups delegated to by this lookup.
*
* @param lookups The new Lookups to delegate to.
*/
void setNewLookups(Lookup... lookups) {
setLookups(lookups);
}
}

View File

@ -120,10 +120,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
private final ExplorerManager vizEM = new ExplorerManager();
private final ExplorerManager gacEM = new ExplorerManager();
private final ProxyLookup proxyLookup = new ProxyLookup(
ExplorerUtils.createLookup(gacEM, getActionMap()),
ExplorerUtils.createLookup(vizEM, getActionMap()));
private final ProxyLookup proxyLookup;
private Frame windowAncestor;
private CommunicationsManager commsManager;
@ -239,8 +236,13 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
}
}
});
final MessageBrowser messageBrowser = new MessageBrowser(vizEM, gacEM);
splitPane.setRightComponent(new MessageBrowser(vizEM, gacEM));
splitPane.setRightComponent(messageBrowser);
proxyLookup = new ProxyLookup(
messageBrowser.getLookup(),
ExplorerUtils.createLookup(vizEM, getActionMap()));
//feed selection to explorermanager
graph.getSelectionModel().addListener(null, new SelectionListener());

View File

@ -90,7 +90,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
*/
private BlackboardArtifact artifact;
private final DataResultPanel drp;
private final ExplorerManager drpExplorerManager;
private ExplorerManager drpExplorerManager;
/**
* Creates new MessageContentViewer
@ -108,6 +108,12 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
Utilities.configureTextPaneAsRtf(rtfbodyTextPane);
resetComponent();
}
@Override
public void addNotify() {
super.addNotify(); //To change body of generated methods, choose Tools | Templates.
drp.open();
drpExplorerManager = drp.getExplorerManager();
drpExplorerManager.addPropertyChangeListener(evt ->

View File

@ -23,6 +23,8 @@ import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JTabbedPane;
import org.openide.explorer.ExplorerManager;
import org.openide.explorer.ExplorerUtils;
import org.openide.nodes.Node;
import org.openide.util.NbBundle;
import org.openide.windows.TopComponent;
@ -40,7 +42,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
//@TopComponent.Description(preferredID = "DataContentTopComponent")
//@TopComponent.Registration(mode = "output", openAtStartup = true)
//@TopComponent.OpenActionRegistration(displayName = "#CTL_DataContentAction", preferredID = "DataContentTopComponent")
public final class DataContentTopComponent extends TopComponent implements DataContent {
public final class DataContentTopComponent extends TopComponent implements DataContent, ExplorerManager.Provider {
private static final Logger logger = Logger.getLogger(DataContentTopComponent.class.getName());
@ -51,6 +53,7 @@ public final class DataContentTopComponent extends TopComponent implements DataC
private final boolean isDefault;
// the content panel holding tabs with content viewers
private final DataContentPanel dataContentPanel;
private final ExplorerManager explorerManager = new ExplorerManager();
// contains a list of the undocked TCs
private static final ArrayList<DataContentTopComponent> newWindowList = new ArrayList<>();
@ -68,6 +71,8 @@ public final class DataContentTopComponent extends TopComponent implements DataC
dataContentPanel = new DataContentPanel(isDefault);
add(dataContentPanel);
associateLookup(ExplorerUtils.createLookup(explorerManager, getActionMap()));
putClientProperty(TopComponent.PROP_CLOSING_DISABLED, isDefault); // prevent option to close compoment in GUI
logger.log(Level.INFO, "Created DataContentTopComponent instance: {0}", this); //NON-NLS
}
@ -128,6 +133,11 @@ public final class DataContentTopComponent extends TopComponent implements DataC
return getDefault();
}
@Override
public ExplorerManager getExplorerManager() {
return explorerManager;
}
@Override
public int getPersistenceType() {
return TopComponent.PERSISTENCE_NEVER;