diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseBrowser.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseBrowser.java index bbf43746f3..3af48d6000 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseBrowser.java @@ -23,11 +23,13 @@ import java.lang.reflect.InvocationTargetException; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionListener; import javax.swing.table.TableCellRenderer; -import javax.swing.table.TableColumn; +import javax.swing.table.TableColumnModel; +import org.netbeans.swing.etable.ETableColumn; +import org.netbeans.swing.etable.ETableColumnModel; import org.netbeans.swing.outline.DefaultOutlineModel; import org.netbeans.swing.outline.Outline; import org.openide.explorer.ExplorerManager; -import org.sleuthkit.autopsy.datamodel.NodeProperty; +import org.openide.nodes.Node; /** * A Swing JPanel with a JTabbedPane child component. The tabbed pane contains @@ -56,10 +58,10 @@ class CaseBrowser extends javax.swing.JPanel { private static final long serialVersionUID = 1L; - private Outline outline; + private final Outline outline; private ExplorerManager em; - private org.openide.explorer.view.OutlineView outlineView; - + private final org.openide.explorer.view.OutlineView outlineView; + private int originalPathColumnIndex = 0; /** * Creates new form CaseBrowser */ @@ -71,13 +73,28 @@ class CaseBrowser extends javax.swing.JPanel { outlineView.setPropertyColumns( Bundle.CaseNode_column_createdTime(), Bundle.CaseNode_column_createdTime(), Bundle.CaseNode_column_status(), Bundle.CaseNode_column_status(), - Bundle.CaseNode_column_metadataFilePath(), Bundle.CaseNode_column_metadataFilePath() - ); + Bundle.CaseNode_column_metadataFilePath(), Bundle.CaseNode_column_metadataFilePath()); + customize(); + + } + + private void customize() { + TableColumnModel columnModel = outline.getColumnModel(); + int dateColumnIndex = 0; + for (int index = 0; index < columnModel.getColumnCount(); index++) { //get indexes for hidden column and default sorting column + if (columnModel.getColumn(index).getHeaderValue().toString().equals(Bundle.CaseNode_column_metadataFilePath())) { + originalPathColumnIndex = index; + } else if (columnModel.getColumn(index).getHeaderValue().toString().equals(Bundle.CaseNode_column_createdTime())) { + dateColumnIndex = index; + } + } + ETableColumn column = (ETableColumn) columnModel.getColumn(originalPathColumnIndex); + ((ETableColumnModel) columnModel).setColumnHidden(column, true); outline.setRootVisible(false); + ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.CaseNode_column_name()); outline.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - outline.setColumnSorted(1, false, 1); //it would be nice if the column index wasn't hardcoded - + outline.setColumnSorted(dateColumnIndex, false, 1); //it would be nice if the column index wasn't hardcoded } /** @@ -102,37 +119,28 @@ class CaseBrowser extends javax.swing.JPanel { this.setVisible(true); } - public void addListSelectionListener(ListSelectionListener listener) { + void setRowSelectionAllowed(boolean allowed) { + outline.setRowSelectionAllowed(allowed); + } + + void addListSelectionListener(ListSelectionListener listener) { outline.getSelectionModel().addListSelectionListener(listener); } String getCasePath() { int[] selectedRows = outline.getSelectedRows(); - System.out.println("Explored Context: " + em.getExploredContext()); - System.out.println("EM ROOT NODe: " + em.getRootContext().getDisplayName()); if (selectedRows.length == 1) { - System.out.println("Selected Row: " + selectedRows[0]); - for (int colIndex = 0; colIndex < outline.getColumnCount(); colIndex++) { - TableColumn col = outline.getColumnModel().getColumn(colIndex); - System.out.println("COL: " + col.getHeaderValue().toString()); - if (col.getHeaderValue().toString().equals(Bundle.CaseNode_column_metadataFilePath())) { - try { - return ((NodeProperty)outline.getValueAt(selectedRows[0], colIndex)).getValue().toString(); - } catch (IllegalAccessException ex) { - - } catch (InvocationTargetException ex) { - - } - } + try { + return ((Node.Property) outline.getModel().getValueAt(outline.convertRowIndexToModel(selectedRows[0]), originalPathColumnIndex)).getValue().toString(); + } catch (IllegalAccessException | InvocationTargetException ex) { + System.out.println("THROW"); } - } return null; } - + boolean isRowSelected() { - System.out.println("SELECTED ROWS: " + outline.getSelectedRows().length); - return outline.getSelectedRows().length > 0; + return outline.getRowSelectionAllowed() && outline.getSelectedRows().length > 0; } private void setColumnWidths() { @@ -141,8 +149,8 @@ class CaseBrowser extends javax.swing.JPanel { final int rows = Math.min(100, outline.getRowCount()); - for (int column = 0; column < outline.getModel().getColumnCount(); column++) { - int columnWidthLimit = 500; + for (int column = 0; column < outline.getColumnModel().getColumnCount(); column++) { + int columnWidthLimit = 800; int columnWidth = 0; // find the maximum width needed to fit the values for the first 100 rows, at most diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseNode.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseNode.java index abd6b965d8..bde2cb0b73 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseNode.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseNode.java @@ -19,7 +19,6 @@ package org.sleuthkit.autopsy.casemodule; import java.awt.event.ActionEvent; -import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -38,6 +37,7 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; import org.sleuthkit.autopsy.datamodel.NodeProperty; + /** * Provides a root node for the results views with a single child node that * displays a message as the sole item in its property sheet, useful for @@ -66,18 +66,17 @@ public final class CaseNode extends AbstractNode { static class CaseNodeChildren extends ChildFactory> { - Map caseList; + private final Map caseMap; - public CaseNodeChildren(Map caseList) { - this.caseList = caseList; + CaseNodeChildren(Map caseMap) { + this.caseMap = caseMap; } @Override protected boolean createKeys(List> list) { - if (caseList != null && caseList.size() > 0) { - list.addAll(caseList.entrySet()); + if (caseMap != null && caseMap.size() > 0) { + list.addAll(caseMap.entrySet()); } - System.out.println("NUM OF KEYS: " + list.size()); return true; } @@ -94,18 +93,20 @@ public final class CaseNode extends AbstractNode { */ public static final class CaseNameNode extends DisplayableItemNode { - CaseMetadata multiUserCase; - String caseMetadataFilePath; - boolean caseHasAlert; + private final String caseName; + private final String caseCreatedDate; + private final String caseMetadataFilePath; + private final boolean caseHasAlert; CaseNameNode(Entry userCase) { super(Children.LEAF); - multiUserCase = userCase.getKey(); + caseName = userCase.getKey().getCaseDisplayName(); + caseCreatedDate = userCase.getKey().getCreatedDate(); caseHasAlert = userCase.getValue(); - super.setName(multiUserCase.getCaseDisplayName()); - setName(multiUserCase.getCaseDisplayName()); - setDisplayName(multiUserCase.getCaseDisplayName()); - caseMetadataFilePath = multiUserCase.getFilePath().toString(); + super.setName(caseName); + setName(caseName); + setDisplayName(caseName); + caseMetadataFilePath = userCase.getKey().getFilePath().toString(); } @Override @@ -122,7 +123,7 @@ public final class CaseNode extends AbstractNode { public String getItemType() { return getClass().getName(); } - + public String getMetadataFilePath() { return caseMetadataFilePath; } @@ -136,9 +137,9 @@ public final class CaseNode extends AbstractNode { s.put(ss); } ss.put(new NodeProperty<>(Bundle.CaseNode_column_name(), Bundle.CaseNode_column_name(), Bundle.CaseNode_column_name(), - multiUserCase.getCaseDisplayName())); + caseName)); ss.put(new NodeProperty<>(Bundle.CaseNode_column_createdTime(), Bundle.CaseNode_column_createdTime(), Bundle.CaseNode_column_createdTime(), - multiUserCase.getCreatedDate())); + caseCreatedDate)); ss.put(new NodeProperty<>(Bundle.CaseNode_column_status(), Bundle.CaseNode_column_status(), Bundle.CaseNode_column_status(), (caseHasAlert == true ? "Alert" : ""))); ss.put(new NodeProperty<>(Bundle.CaseNode_column_metadataFilePath(), Bundle.CaseNode_column_metadataFilePath(), Bundle.CaseNode_column_metadataFilePath(), @@ -150,7 +151,7 @@ public final class CaseNode extends AbstractNode { public Action[] getActions(boolean context) { List actions = new ArrayList<>(); actions.addAll(Arrays.asList(super.getActions(context))); - actions.add(new OpenMultiUserCaseAction(multiUserCase.getFilePath())); + actions.add(new OpenMultiUserCaseAction(caseMetadataFilePath)); return actions.toArray(new Action[actions.size()]); } } @@ -162,9 +163,9 @@ public final class CaseNode extends AbstractNode { private static final long serialVersionUID = 1L; - private final Path caseMetadataFilePath; + private final String caseMetadataFilePath; - public OpenMultiUserCaseAction(Path path) { + OpenMultiUserCaseAction(String path) { super("Open Case"); caseMetadataFilePath = path; } @@ -172,32 +173,32 @@ public final class CaseNode extends AbstractNode { @Override public void actionPerformed(ActionEvent e) { StartupWindowProvider.getInstance().close(); - openCaseThread(caseMetadataFilePath); + new Thread( + () -> { + try { + Case.openAsCurrentCase(caseMetadataFilePath); + } catch (CaseActionException ex) { + if (null != ex.getCause() && !(ex.getCause() instanceof CaseActionCancelledException)) { + // LOGGER.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", caseMetadataFilePath), ex); //NON-NLS + MessageNotifyUtil.Message.error(ex.getCause().getLocalizedMessage()); + } + SwingUtilities.invokeLater(() -> { + //GUI changes done back on the EDT + StartupWindowProvider.getInstance().open(); + }); + } finally { + SwingUtilities.invokeLater(() -> { + //GUI changes done back on the EDT + }); + } + } + ).start(); + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); //To change body of generated methods, choose Tools | Templates. } } - private static void openCaseThread(Path caseMetadataFilePath) { - - new Thread( - () -> { - try { - Case.openAsCurrentCase(caseMetadataFilePath.toString()); - } catch (CaseActionException ex) { - if (null != ex.getCause() && !(ex.getCause() instanceof CaseActionCancelledException)) { - // LOGGER.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", caseMetadataFilePath), ex); //NON-NLS - MessageNotifyUtil.Message.error(ex.getCause().getLocalizedMessage()); - } - SwingUtilities.invokeLater(() -> { - //GUI changes done back on the EDT - StartupWindowProvider.getInstance().open(); - }); - } finally { - SwingUtilities.invokeLater(() -> { - //GUI changes done back on the EDT - }); - } - } - ).start(); - } - } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java index e17faab27e..b4e16bfa91 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java @@ -45,13 +45,12 @@ import org.sleuthkit.autopsy.coordinationservice.CaseNodeData; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.autopsy.datamodel.EmptyNode; /** * A panel that allows a user to open cases created by auto ingest. */ -@NbBundle.Messages({"MultiUSerCasesPanel.caseListLoading.message=Retrieving list of cases, please wait..."}) +@NbBundle.Messages({"MultiUserCasesPanel.caseListLoading.message=Please wait..."}) final class MultiUserCasesPanel extends TopComponent implements ExplorerManager.Provider { private static final long serialVersionUID = 1L; @@ -73,7 +72,7 @@ final class MultiUserCasesPanel extends TopComponent implements ExplorerManager. caseListPanel = new CaseBrowser(); caseListPanel.open(); - + caseListPanel.setRowSelectionAllowed(false); caseExplorerScrollPane.add(caseListPanel); caseExplorerScrollPane.setViewportView(caseListPanel); /* @@ -92,11 +91,13 @@ final class MultiUserCasesPanel extends TopComponent implements ExplorerManager. */ void refresh() { if (tableWorker == null || tableWorker.isDone()) { + caseListPanel.setRowSelectionAllowed(false); //create a new TableWorker to and execute it in a background thread if one is not currently working //set the table to display text informing the user that the list is being retreived and disable case selection + EmptyNode emptyNode = new EmptyNode(Bundle.MultiUserCasesPanel_caseListLoading_message()); + explorerManager.setRootContext(emptyNode); tableWorker = new LoadCaseListWorker(); tableWorker.execute(); - } } @@ -117,7 +118,6 @@ final class MultiUserCasesPanel extends TopComponent implements ExplorerManager. */ private void openCase(String caseMetadataFilePath) { if (caseMetadataFilePath != null) { - System.out.println("OPENENING CASE: " + caseMetadataFilePath); setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); StartupWindowProvider.getInstance().close(); @@ -296,7 +296,7 @@ final class MultiUserCasesPanel extends TopComponent implements ExplorerManager. * @throws CoordinationServiceException */ private Map getCases() throws CoordinationService.CoordinationServiceException { - Map cases = new HashMap<>(); + Map casesMap = new HashMap<>(); List nodeList = CoordinationService.getInstance().getNodeList(CoordinationService.CategoryNode.CASES); for (String node : nodeList) { @@ -352,7 +352,7 @@ final class MultiUserCasesPanel extends TopComponent implements ExplorerManager. } CaseMetadata caseMetadata = new CaseMetadata(Paths.get(autFilePath)); - cases.put(caseMetadata, hasAlertStatus); + casesMap.put(caseMetadata, hasAlertStatus); } catch (CaseMetadata.CaseMetadataException ex) { LOGGER.log(Level.SEVERE, String.format("Error reading case metadata file '%s'.", autFilePath), ex); } catch (InterruptedException | CaseNodeData.InvalidDataException ex) { @@ -361,7 +361,7 @@ final class MultiUserCasesPanel extends TopComponent implements ExplorerManager. } } } - return cases; + return casesMap; } @Override @@ -381,18 +381,7 @@ final class MultiUserCasesPanel extends TopComponent implements ExplorerManager. EventQueue.invokeLater(() -> { CaseNode caseListNode = new CaseNode(cases); explorerManager.setRootContext(caseListNode); - String displayName = ""; - Content content = caseListNode.getLookup().lookup(Content.class); - if (content != null) { - try { - displayName = content.getUniquePath(); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Exception while calling Content.getUniquePath() for node: {0}", caseListNode); //NON-NLS - } - } else if (caseListNode.getLookup().lookup(String.class) != null) { - displayName = caseListNode.getLookup().lookup(String.class); - } - System.out.println("GET CASES DONE"); + caseListPanel.setRowSelectionAllowed(true); setButtons(); }); }