19 package org.sleuthkit.autopsy.datasourcesummary.ui;
 
   22 import java.awt.Cursor;
 
   24 import java.awt.EventQueue;
 
   25 import java.beans.PropertyVetoException;
 
   26 import javax.swing.ListSelectionModel;
 
   27 import org.netbeans.swing.outline.DefaultOutlineModel;
 
   28 import org.netbeans.swing.outline.Outline;
 
   29 import org.openide.explorer.ExplorerManager;
 
   30 import java.util.ArrayList;
 
   31 import java.util.Collections;
 
   32 import java.util.List;
 
   34 import java.util.Observer;
 
   35 import java.util.logging.Level;
 
   37 import javax.swing.event.ListSelectionListener;
 
   38 import org.openide.nodes.Node;
 
   42 import static javax.swing.SwingConstants.RIGHT;
 
   43 import javax.swing.SwingUtilities;
 
   44 import javax.swing.SwingWorker;
 
   45 import javax.swing.table.TableColumn;
 
   55 final class DataSourceBrowser 
extends javax.swing.JPanel implements ExplorerManager.Provider {
 
   57     private static final long serialVersionUID = 1L;
 
   58     private static final Logger logger = Logger.getLogger(DataSourceBrowser.class.getName());
 
   59     private static final int COUNT_COLUMN_WIDTH = 20;
 
   60     private static final int INGEST_STATUS_WIDTH = 50;
 
   61     private static final int USAGE_COLUMN_WIDTH = 110;
 
   62     private static final int DATA_SOURCE_COLUMN_WIDTH = 280;
 
   63     private final Outline outline;
 
   64     private final org.openide.explorer.view.OutlineView outlineView;
 
   65     private final ExplorerManager explorerManager;
 
   66     private final List<DataSourceSummary> dataSourceSummaryList;
 
   67     private final RightAlignedTableCellRenderer rightAlignedRenderer = 
new RightAlignedTableCellRenderer();
 
   68     private SwingWorker<Void, Void> rootNodeWorker = null;
 
   75         rightAlignedRenderer.setHorizontalAlignment(RIGHT);
 
   76         explorerManager = 
new ExplorerManager();
 
   77         outlineView = 
new org.openide.explorer.view.OutlineView();
 
   78         this.setVisible(
true);
 
   79         outlineView.setPropertyColumns(
 
   80                 Bundle.DataSourceSummaryNode_column_status_header(), Bundle.DataSourceSummaryNode_column_status_header(),
 
   81                 Bundle.DataSourceSummaryNode_column_type_header(), Bundle.DataSourceSummaryNode_column_type_header(),
 
   82                 Bundle.DataSourceSummaryNode_column_files_header(), Bundle.DataSourceSummaryNode_column_files_header(),
 
   83                 Bundle.DataSourceSummaryNode_column_results_header(), Bundle.DataSourceSummaryNode_column_results_header(),
 
   84                 Bundle.DataSourceSummaryNode_column_tags_header(), Bundle.DataSourceSummaryNode_column_tags_header());
 
   85         outline = outlineView.getOutline();
 
   86         outline.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 
   87         dataSourceSummaryList = 
new ArrayList<>();
 
   88         outline.setRootVisible(
false);
 
   89         add(outlineView, java.awt.BorderLayout.CENTER);
 
   90         ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.DataSourceSummaryNode_column_dataSourceName_header());
 
   91         for (TableColumn column : Collections.list(outline.getColumnModel().getColumns())) {
 
   92             if (column.getHeaderValue().toString().equals(Bundle.DataSourceSummaryNode_column_files_header())
 
   93                     || column.getHeaderValue().toString().equals(Bundle.DataSourceSummaryNode_column_results_header())
 
   94                     || column.getHeaderValue().toString().equals(Bundle.DataSourceSummaryNode_column_tags_header())) {
 
   95                 column.setCellRenderer(rightAlignedRenderer);
 
   96                 column.setPreferredWidth(COUNT_COLUMN_WIDTH);
 
   97             } 
else if (column.getHeaderValue().toString().equals(Bundle.DataSourceSummaryNode_column_type_header())) {
 
   98                 column.setPreferredWidth(USAGE_COLUMN_WIDTH);
 
   99             } 
else if (column.getHeaderValue().toString().equals(Bundle.DataSourceSummaryNode_column_status_header())) {
 
  100                 column.setPreferredWidth(INGEST_STATUS_WIDTH);
 
  102                 column.setPreferredWidth(DATA_SOURCE_COLUMN_WIDTH);
 
  105         this.setVisible(
true);
 
  116     void selectDataSource(Long dataSourceId) {
 
  117         EventQueue.invokeLater(() -> {
 
  118             if (dataSourceId != null) {
 
  119                 for (Node node : explorerManager.getRootContext().getChildren().getNodes()) {
 
  120                     if (node instanceof DataSourceSummaryEntryNode && ((DataSourceSummaryEntryNode) node).getDataSource().getId() == dataSourceId) {
 
  122                             explorerManager.setExploredContextAndSelection(node, 
new Node[]{node});
 
  124                         } 
catch (PropertyVetoException ex) {
 
  125                             logger.log(Level.WARNING, 
"Failed to select the datasource in the explorer view", ex); 
 
  131             if (explorerManager.getRootContext().getChildren().getNodes().length > 0) {
 
  132                 outline.getSelectionModel().setSelectionInterval(0, 0);
 
  143     void addObserver(Observer observer) {
 
  144         ((DataSourceSummaryNode) explorerManager.getRootContext()).addObserver(observer);
 
  154     private List<DataSourceSummary> getDataSourceSummaryList(Map<Long, String> usageMap, Map<Long, Long> fileCountsMap) {
 
  155         List<DataSourceSummary> summaryList = 
new ArrayList<>();
 
  157         final Map<Long, Long> artifactCountsMap = CaseDataSourcesSummary.getCountsOfArtifacts();
 
  158         final Map<Long, Long> tagCountsMap = CaseDataSourcesSummary.getCountsOfTags();
 
  160             SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
 
  161             for (DataSource dataSource : skCase.getDataSources()) {
 
  162                 summaryList.add(
new DataSourceSummary(dataSource, usageMap.get(dataSource.getId()),
 
  163                         fileCountsMap.get(dataSource.getId()), artifactCountsMap.get(dataSource.getId()), tagCountsMap.get(dataSource.getId())));
 
  165         } 
catch (TskCoreException | NoCurrentCaseException ex) {
 
  166             logger.log(Level.WARNING, 
"Unable to datasources or their counts, providing empty results", ex);
 
  176     void addListSelectionListener(ListSelectionListener listener) {
 
  177         outline.getSelectionModel().addListSelectionListener(listener);
 
  185     DataSource getSelectedDataSource() {
 
  186         Node selectedNode[] = explorerManager.getSelectedNodes();
 
  187         if (selectedNode.length == 1 && selectedNode[0] instanceof DataSourceSummaryEntryNode) {
 
  188             return ((DataSourceSummaryEntryNode) selectedNode[0]).getDataSource();
 
  200     void refresh(
long dataSourceId, IngestJobInfo.IngestJobStatusType newStatus) {
 
  203         for (DataSourceSummary summary : dataSourceSummaryList) {
 
  204             if (summary.getDataSource().getId() == dataSourceId) {
 
  205                 summary.setIngestStatus(newStatus);
 
  209         Node[] selectedNodes = explorerManager.getSelectedNodes();
 
  210         SwingUtilities.invokeLater(() -> {
 
  211             explorerManager.setRootContext(
new DataSourceSummaryNode(dataSourceSummaryList));
 
  212             List<Node> nodesToSelect = 
new ArrayList<>();
 
  213             for (Node node : explorerManager.getRootContext().getChildren().getNodes()) {
 
  214                 if (node instanceof DataSourceSummaryEntryNode) {
 
  216                     for (Node selectedNode : selectedNodes) {
 
  217                         if (((DataSourceSummaryEntryNode) node).getDataSource().equals(((DataSourceSummaryEntryNode) selectedNode).getDataSource())) {
 
  218                             nodesToSelect.add(node);
 
  225                 explorerManager.setSelectedNodes(nodesToSelect.toArray(
new Node[nodesToSelect.size()]));
 
  226             } 
catch (PropertyVetoException ex) {
 
  227                 logger.log(Level.WARNING, 
"Error selecting previously selected nodes", ex);
 
  239     @SuppressWarnings(
"unchecked")
 
  241     private 
void initComponents() {
 
  243         setLayout(
new java.awt.BorderLayout());
 
  247     public ExplorerManager getExplorerManager() {
 
  248         return explorerManager;
 
  260     void populateBrowser(DataSourceSummaryDialog dsSummaryDialog, Long selectedDataSourceId) {
 
  261         dsSummaryDialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
 
  262         if (rootNodeWorker != null && !rootNodeWorker.isDone()) {
 
  263             rootNodeWorker.cancel(
true);
 
  266         dataSourceSummaryList.clear();
 
  267         rootNodeWorker = 
new SwingWorker<Void, Void>() {
 
  269             protected Void doInBackground() throws Exception {
 
  270                 Map<Long, String> usageMap = CaseDataSourcesSummary.getDataSourceTypes();
 
  271                 Map<Long, Long> fileCountsMap = CaseDataSourcesSummary.getCountsOfFiles();
 
  272                 dataSourceSummaryList.addAll(getDataSourceSummaryList(usageMap, fileCountsMap));
 
  277             protected void done() {
 
  278                 explorerManager.setRootContext(
new DataSourceSummaryNode(dataSourceSummaryList));
 
  279                 selectDataSource(selectedDataSourceId);
 
  280                 addObserver(dsSummaryDialog);
 
  281                 dsSummaryDialog.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
 
  284         rootNodeWorker.execute();
 
  292         if (rootNodeWorker != null && !rootNodeWorker.isDone()) {
 
  293             rootNodeWorker.cancel(
true);