/* * Autopsy Forensic Browser * * Copyright 2013 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.corecomponents; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.sleuthkit.autopsy.corecomponentinterfaces.DataResult; import java.util.logging.Level; import javax.swing.JComponent; import org.openide.explorer.ExplorerManager; import org.openide.explorer.ExplorerUtils; import org.openide.util.NbBundle; import org.openide.windows.TopComponent; import org.openide.nodes.Node; import org.openide.windows.Mode; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.actions.AddBookmarkTagAction; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer; import org.sleuthkit.autopsy.coreutils.Logger; /** * Top component which displays results (top-right editor mode by default). * * There is a main tc instance that responds to directory tree selections. * Others can also create an additional result viewer tc using one of the * factory methods, that can be: * * - added to top-right corner as an additional, closeable viewer - added to a * different, custom mode, - linked to a custom content viewer that responds to * selections from this top component. * * For embedding custom data result in other top components window, use * DataResultPanel component instead, since we cannot nest top components. * * Encapsulates the internal DataResultPanel and delegates to it. * * Implements DataResult interface by delegating to the encapsulated * DataResultPanel. */ public class DataResultTopComponent extends TopComponent implements DataResult, ExplorerManager.Provider { private static final Logger logger = Logger.getLogger(DataResultTopComponent.class.getName()); private ExplorerManager explorerManager = new ExplorerManager(); private DataResultPanel dataResultPanel; //embedded component with all the logic private boolean isMain; private String customModeName; //keep track of tcs opened for menu presenters private static final List<String> activeComponentIds = Collections.synchronizedList(new ArrayList<String>()); /** * Create a new data result top component * * @param isMain whether it is the main, application default result viewer, * there can be only 1 main result viewer * @param title title of the data result window */ public DataResultTopComponent(boolean isMain, String title) { associateLookup(ExplorerUtils.createLookup(explorerManager, getActionMap())); this.dataResultPanel = new DataResultPanel(isMain, title); initComponents(); customizeComponent(isMain, title); } /** * Create a new, custom data result top component, in addition to the * application main one * * @param name unique name of the data result window, also * used as title * @param customModeName custom mode to dock into * @param customContentViewer custom content viewer to send selection events * to */ DataResultTopComponent(String name, String mode, DataContentTopComponent customContentViewer) { associateLookup(ExplorerUtils.createLookup(explorerManager, getActionMap())); this.customModeName = mode; dataResultPanel = new DataResultPanel(name, customContentViewer); initComponents(); customizeComponent(isMain, name); } private void customizeComponent(boolean isMain, String title) { this.isMain = isMain; this.customModeName = null; setToolTipText(NbBundle.getMessage(DataResultTopComponent.class, "HINT_NodeTableTopComponent")); setTitle(title); // set the title setName(title); getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(AddBookmarkTagAction.BOOKMARK_SHORTCUT, "addBookmarkTag"); //NON-NLS getActionMap().put("addBookmarkTag", new AddBookmarkTagAction()); //NON-NLS putClientProperty(TopComponent.PROP_CLOSING_DISABLED, isMain); // set option to close compoment in GUI putClientProperty(TopComponent.PROP_MAXIMIZATION_DISABLED, true); putClientProperty(TopComponent.PROP_DRAGGING_DISABLED, true); activeComponentIds.add(title); } /** * Initialize previously created tc instance with additional data * * @param pathText * @param givenNode * @param totalMatches * @param newDataResult previously created with createInstance() * uninitialized instance */ public static void initInstance(String pathText, Node givenNode, int totalMatches, DataResultTopComponent newDataResult) { newDataResult.setNumMatches(totalMatches); newDataResult.open(); // open it first so the component can be initialized // set the tree table view newDataResult.setNode(givenNode); newDataResult.setPath(pathText); newDataResult.requestActive(); } /** * Creates a new non-default DataResult component and initializes it * * @param title Title of the component window * @param pathText Descriptive text about the source of the nodes * displayed * @param givenNode The new root node * @param totalMatches Cardinality of root node's children * * @return a new, not default, initialized DataResultTopComponent instance */ public static DataResultTopComponent createInstance(String title, String pathText, Node givenNode, int totalMatches) { DataResultTopComponent newDataResult = new DataResultTopComponent(false, title); initInstance(pathText, givenNode, totalMatches, newDataResult); return newDataResult; } /** * Creates a new non-default DataResult component linked with a custom data * content, and initializes it. * * * @param title Title of the component window * @param mode custom mode to dock this custom TopComponent to * @param pathText Descriptive text about the source of the nodes * displayed * @param givenNode The new root node * @param totalMatches Cardinality of root node's children * @param dataContentWindow a handle to data content top component window to * * @return a new, not default, initialized DataResultTopComponent instance */ public static DataResultTopComponent createInstance(String title, final String mode, String pathText, Node givenNode, int totalMatches, DataContentTopComponent dataContentWindow) { DataResultTopComponent newDataResult = new DataResultTopComponent(title, mode, dataContentWindow); initInstance(pathText, givenNode, totalMatches, newDataResult); return newDataResult; } /** * Creates a new non-default DataResult component. You probably want to use * initInstance after it * * @param title * * @return a new, not default, not fully initialized DataResultTopComponent * instance */ public static DataResultTopComponent createInstance(String title) { final DataResultTopComponent newDataResult = new DataResultTopComponent(false, title); return newDataResult; } @Override public ExplorerManager getExplorerManager() { return explorerManager; } /** * Get a list with names of active windows ids, e.g. for the menus * * @return */ public static List<String> getActiveComponentIds() { return new ArrayList<>(activeComponentIds); } /** * 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. */ // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { org.sleuthkit.autopsy.corecomponents.DataResultPanel dataResultPanelLocal = dataResultPanel; javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(dataResultPanelLocal, javax.swing.GroupLayout.DEFAULT_SIZE, 967, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(dataResultPanelLocal, javax.swing.GroupLayout.DEFAULT_SIZE, 579, Short.MAX_VALUE) ); }// </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables @Override public int getPersistenceType() { if (customModeName == null) { return TopComponent.PERSISTENCE_NEVER; } else { return TopComponent.PERSISTENCE_ALWAYS; } } @Override public void open() { setCustomMode(); super.open(); //To change body of generated methods, choose Tools | Templates. } @Override public List<DataResultViewer> getViewers() { return dataResultPanel.getViewers(); } private void setCustomMode() { if (customModeName != null) { Mode mode = WindowManager.getDefault().findMode(customModeName); if (mode != null) { StringBuilder message = new StringBuilder("Found custom mode, setting: "); //NON-NLS message.append(customModeName); logger.log(Level.INFO, message.toString()); mode.dockInto(this); } else { StringBuilder message = new StringBuilder("Could not find mode: "); //NON-NLS message.append(customModeName); message.append(", will dock into the default one"); //NON-NLS logger.log(Level.WARNING, message.toString()); } } } @Override public void componentOpened() { super.componentOpened(); this.dataResultPanel.open(); } @Override public void componentClosed() { super.componentClosed(); activeComponentIds.remove(this.getName()); dataResultPanel.close(); } @Override protected String preferredID() { return getName(); } @Override public String getPreferredID() { return getName(); } @Override public void setNode(Node selectedNode) { dataResultPanel.setNode(selectedNode); } @Override public void setTitle(String title) { setName(title); } @Override public void setPath(String pathText) { dataResultPanel.setPath(pathText); } @Override public boolean isMain() { return isMain; } @Override public boolean canClose() { return (!this.isMain) || !Case.isCaseOpen() || Case.getCurrentCase().hasData() == false; // only allow this window to be closed when there's no case opened or no image in this case } /** * Resets the tabs based on the selected Node. If the selected node is null * or not supported, disable that tab as well. * * @param selectedNode the selected content Node */ public void resetTabs(Node selectedNode) { dataResultPanel.resetTabs(selectedNode); } public void setSelectedNodes(Node[] selected) { dataResultPanel.setSelectedNodes(selected); } public Node getRootNode() { return dataResultPanel.getRootNode(); } void setNumMatches(int matches) { this.dataResultPanel.setNumMatches(matches); } }