mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
Refactor multi-user case UI for reuse, create admin case dashboard UI
This commit is contained in:
parent
52df9894ea
commit
f3ddd206a2
@ -313,6 +313,8 @@
|
||||
<package>org.sleuthkit.autopsy.appservices</package>
|
||||
<package>org.sleuthkit.autopsy.casemodule</package>
|
||||
<package>org.sleuthkit.autopsy.casemodule.events</package>
|
||||
<package>org.sleuthkit.autopsy.casemodule.multiusercases</package>
|
||||
<package>org.sleuthkit.autopsy.casemodule.multiusercasesbrowser</package>
|
||||
<package>org.sleuthkit.autopsy.casemodule.services</package>
|
||||
<package>org.sleuthkit.autopsy.contentviewers</package>
|
||||
<package>org.sleuthkit.autopsy.coordinationservice</package>
|
||||
|
@ -233,7 +233,10 @@ ImageFilePanel.md5HashTextField.text=
|
||||
ImageFilePanel.errorLabel.text=Error Label
|
||||
ImageFilePanel.hashValuesNoteLabel.text=NOTE: These values will not be validated when the data source is added.
|
||||
ImageFilePanel.hashValuesLabel.text=Hash Values (optional):
|
||||
OpenMultiUserCasePanel.searchLabel.text=Select any case and start typing to search by case name
|
||||
OpenMultiUserCasePanel.cancelButton.text=Cancel
|
||||
OpenMultiUserCasePanel.openSelectedCaseButton.text=Open Selected Case
|
||||
# To change this license header, choose License Headers in Project Properties.
|
||||
# To change this template file, choose Tools | Templates
|
||||
# and open the template in the editor.
|
||||
OpenMultiUserCasePanel.openSingleUserCaseButton.text=Open Single-User Case...
|
||||
OpenMultiUserCasePanel.openSelectedCaseButton.text=Open Selected Case
|
||||
OpenMultiUserCasePanel.searchLabel.text=Select any case and start typing to search by case name
|
||||
|
@ -18,7 +18,7 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
import org.sleuthkit.autopsy.coordinationservice.CaseNodeData;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData;
|
||||
import java.awt.Frame;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
@ -88,7 +88,7 @@ public final class CaseOpenAction extends CallableSystemAction implements Action
|
||||
* metadata file (.aut file). Upon confirming the selection, it will attempt
|
||||
* to open the case described by the file.
|
||||
*/
|
||||
void openCaseSelectionWindow() {
|
||||
public void openCaseSelectionWindow() {
|
||||
String optionsDlgTitle = NbBundle.getMessage(Case.class, "CloseCaseWhileIngesting.Warning.title");
|
||||
String optionsDlgMessage = NbBundle.getMessage(Case.class, "CloseCaseWhileIngesting.Warning");
|
||||
if (IngestRunningCheck.checkAndConfirmProceed(optionsDlgTitle, optionsDlgMessage)) {
|
||||
|
@ -24,7 +24,7 @@ import java.util.logging.Level;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.coordinationservice.CaseNodeData;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
|
||||
@ -32,7 +32,7 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
* An action that opens a multi-user case and hides the open multi-user case
|
||||
* dialog given the coordination service node data for the case.
|
||||
*/
|
||||
final class OpenMultiUserCaseAction extends AbstractAction {
|
||||
public final class OpenMultiUserCaseAction extends AbstractAction {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger logger = Logger.getLogger(OpenMultiUserCaseAction.class.getName());
|
||||
@ -42,11 +42,14 @@ final class OpenMultiUserCaseAction extends AbstractAction {
|
||||
* Constructs an action that opens a multi-user case and hides the open
|
||||
* multi-user case dialog given the coordination service node data for the
|
||||
* case.
|
||||
*
|
||||
* @param caseNodeData The coordination service node data for the case
|
||||
* associated with this action.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"OpenMultiUserCaseAction.menuItemText=Open Case"
|
||||
})
|
||||
OpenMultiUserCaseAction(CaseNodeData caseNodeData) {
|
||||
public OpenMultiUserCaseAction(CaseNodeData caseNodeData) {
|
||||
super(Bundle.OpenMultiUserCaseAction_menuItemText());
|
||||
this.caseNodeData = caseNodeData;
|
||||
}
|
||||
@ -92,7 +95,6 @@ final class OpenMultiUserCaseAction extends AbstractAction {
|
||||
|
||||
@Override
|
||||
public OpenMultiUserCaseAction clone() throws CloneNotSupportedException {
|
||||
super.clone();
|
||||
throw new CloneNotSupportedException();
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ import org.openide.windows.WindowManager;
|
||||
/**
|
||||
* A singleton JDialog that allows a user to open a multi-user case.
|
||||
*/
|
||||
final class OpenMultiUserCaseDialog extends JDialog {
|
||||
public final class OpenMultiUserCaseDialog extends JDialog {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static OpenMultiUserCaseDialog instance;
|
||||
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019-2019 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.casemodule;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.Action;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercasesbrowser.MultiUserCaseBrowserCustomizer;
|
||||
|
||||
/**
|
||||
* A customizer for a multi-user case browser panel that presents a tabular view
|
||||
* of the multi-user cases known to the coordination service in the open
|
||||
* multi-user case dialog.
|
||||
*/
|
||||
final class OpenMultiUserCaseNodeCustomizer implements MultiUserCaseBrowserCustomizer {
|
||||
|
||||
@Override
|
||||
public List<Column> getColumns() {
|
||||
List<Column> properties = new ArrayList<>();
|
||||
// properties.add(Column.DISPLAY_NAME);
|
||||
properties.add(Column.CREATE_DATE);
|
||||
properties.add(Column.DIRECTORY);
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SortColumn> getSortColumns() {
|
||||
List<SortColumn> sortColumns = new ArrayList<>();
|
||||
sortColumns.add(new SortColumn(Column.CREATE_DATE, false, 1));
|
||||
return sortColumns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowMultiSelect() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getActions(CaseNodeData nodeData) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(new OpenMultiUserCaseAction(nodeData));
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action getPreferredAction(CaseNodeData nodeData) {
|
||||
return new OpenMultiUserCaseAction(nodeData);
|
||||
}
|
||||
|
||||
}
|
@ -24,28 +24,28 @@
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Component id="caseExplorerScrollPane" max="32767" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="searchLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="32" max="-2" attributes="0"/>
|
||||
<Component id="openSingleUserCaseButton" linkSize="10" min="-2" pref="172" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="96" max="32767" attributes="0"/>
|
||||
<Component id="openSelectedCaseButton" linkSize="10" min="-2" pref="160" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="cancelButton" linkSize="10" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<Component id="searchLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="32" max="-2" attributes="0"/>
|
||||
<Component id="openSingleUserCaseButton" linkSize="10" min="-2" pref="172" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="74" max="32767" attributes="0"/>
|
||||
<Component id="openSelectedCaseButton" linkSize="10" min="-2" pref="160" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="cancelButton" linkSize="10" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="caseBrowserScrollPane" pref="948" max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
|
||||
<Component id="caseExplorerScrollPane" min="-2" pref="450" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="462" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="cancelButton" linkSize="7" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="openSingleUserCaseButton" linkSize="7" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
@ -54,6 +54,13 @@
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="caseBrowserScrollPane" min="-2" pref="445" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="49" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
@ -100,10 +107,6 @@
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Container class="javax.swing.JScrollPane" name="caseExplorerScrollPane">
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||
</Container>
|
||||
<Component class="javax.swing.JButton" name="openSelectedCaseButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
@ -114,5 +117,9 @@
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="openSelectedCaseButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Container class="javax.swing.JScrollPane" name="caseBrowserScrollPane">
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
|
@ -18,13 +18,15 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercasesbrowser.MultiUserCasesBrowserPanel;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import org.openide.explorer.ExplorerManager;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.Lookup;
|
||||
import org.sleuthkit.autopsy.coordinationservice.CaseNodeData;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercasesbrowser.MultiUserCaseNode;
|
||||
|
||||
/**
|
||||
* A JPanel that allows a user to open a multi-user case.
|
||||
@ -46,9 +48,9 @@ final class OpenMultiUserCasePanel extends JPanel {
|
||||
OpenMultiUserCasePanel(JDialog parentDialog) {
|
||||
this.parentDialog = parentDialog;
|
||||
initComponents(); // Machine generated code
|
||||
caseBrowserPanel = new MultiUserCasesBrowserPanel();
|
||||
caseExplorerScrollPane.add(caseBrowserPanel);
|
||||
caseExplorerScrollPane.setViewportView(caseBrowserPanel);
|
||||
caseBrowserPanel = new MultiUserCasesBrowserPanel(new ExplorerManager(), new OpenMultiUserCaseNodeCustomizer());
|
||||
caseBrowserScrollPane.add(caseBrowserPanel);
|
||||
caseBrowserScrollPane.setViewportView(caseBrowserPanel);
|
||||
openSelectedCaseButton.setEnabled(false);
|
||||
caseBrowserPanel.addListSelectionListener((ListSelectionEvent event) -> {
|
||||
openSelectedCaseButton.setEnabled(caseBrowserPanel.getExplorerManager().getSelectedNodes().length > 0);
|
||||
@ -60,7 +62,7 @@ final class OpenMultiUserCasePanel extends JPanel {
|
||||
* the coordination service..
|
||||
*/
|
||||
void refreshDisplay() {
|
||||
caseBrowserPanel.refreshCases();
|
||||
caseBrowserPanel.displayCases();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -75,8 +77,8 @@ final class OpenMultiUserCasePanel extends JPanel {
|
||||
openSingleUserCaseButton = new javax.swing.JButton();
|
||||
cancelButton = new javax.swing.JButton();
|
||||
searchLabel = new javax.swing.JLabel();
|
||||
caseExplorerScrollPane = new javax.swing.JScrollPane();
|
||||
openSelectedCaseButton = new javax.swing.JButton();
|
||||
caseBrowserScrollPane = new javax.swing.JScrollPane();
|
||||
|
||||
setName("Completed Cases"); // NOI18N
|
||||
setPreferredSize(new java.awt.Dimension(960, 485));
|
||||
@ -115,17 +117,19 @@ final class OpenMultiUserCasePanel extends JPanel {
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(caseExplorerScrollPane)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(searchLabel)
|
||||
.addGap(32, 32, 32)
|
||||
.addComponent(openSingleUserCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 172, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 96, Short.MAX_VALUE)
|
||||
.addComponent(openSelectedCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 160, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(cancelButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||
.addComponent(searchLabel)
|
||||
.addGap(32, 32, 32)
|
||||
.addComponent(openSingleUserCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 172, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 74, Short.MAX_VALUE)
|
||||
.addComponent(openSelectedCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 160, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(cancelButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap())
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(caseBrowserScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 948, Short.MAX_VALUE)
|
||||
.addContainerGap()))
|
||||
);
|
||||
|
||||
layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cancelButton, openSelectedCaseButton, openSingleUserCaseButton});
|
||||
@ -133,15 +137,18 @@ final class OpenMultiUserCasePanel extends JPanel {
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(6, 6, 6)
|
||||
.addComponent(caseExplorerScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 450, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGap(462, 462, 462)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(cancelButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(openSingleUserCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(searchLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(openSelectedCaseButton))
|
||||
.addContainerGap())
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(caseBrowserScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 445, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(49, Short.MAX_VALUE)))
|
||||
);
|
||||
|
||||
layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {cancelButton, openSelectedCaseButton, openSingleUserCaseButton});
|
||||
@ -179,14 +186,14 @@ final class OpenMultiUserCasePanel extends JPanel {
|
||||
Node[] selectedNodes = explorerManager.getSelectedNodes();
|
||||
if (selectedNodes.length > 0 && selectedNodes[0] instanceof MultiUserCaseNode) {
|
||||
MultiUserCaseNode caseNode = (MultiUserCaseNode) selectedNodes[0];
|
||||
CaseNodeData nodeData = caseNode.getCaseNodeData();
|
||||
CaseNodeData nodeData = caseNode.getLookup().lookup(CaseNodeData.class);
|
||||
new OpenMultiUserCaseAction(nodeData).actionPerformed(evt);
|
||||
}
|
||||
}//GEN-LAST:event_openSelectedCaseButtonActionPerformed
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton cancelButton;
|
||||
private javax.swing.JScrollPane caseExplorerScrollPane;
|
||||
private javax.swing.JScrollPane caseBrowserScrollPane;
|
||||
private javax.swing.JButton openSelectedCaseButton;
|
||||
private javax.swing.JButton openSingleUserCaseButton;
|
||||
private javax.swing.JLabel searchLabel;
|
||||
|
@ -16,7 +16,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.coordinationservice;
|
||||
package org.sleuthkit.autopsy.casemodule.multiusercases;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
@ -16,9 +16,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
package org.sleuthkit.autopsy.casemodule.multiusercases;
|
||||
|
||||
import org.sleuthkit.autopsy.coordinationservice.CaseNodeData;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.LinkOption;
|
||||
@ -28,6 +27,7 @@ import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.casemodule.CaseMetadata;
|
||||
import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
|
||||
@ -35,7 +35,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
* Queries the coordination service to collect the multi-user case node data
|
||||
* stored in the case directory lock ZooKeeper nodes.
|
||||
*/
|
||||
final class MultiUserCaseNodeDataCollector {
|
||||
final public class MultiUserCaseNodeDataCollector {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(MultiUserCaseNodeDataCollector.class.getName());
|
||||
private static final String CASE_AUTO_INGEST_LOG_NAME = "AUTO_INGEST_LOG.TXT"; //NON-NLS
|
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019-2019 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.casemodule.multiusercasesbrowser;
|
||||
|
||||
import java.util.List;
|
||||
import javax.swing.Action;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData;
|
||||
|
||||
/**
|
||||
* The interface for defining a customizer for a multi-user case browser panel
|
||||
* that presents a tabular view of the multi-user cases known to the
|
||||
* coordination service.
|
||||
*/
|
||||
public interface MultiUserCaseBrowserCustomizer {
|
||||
|
||||
/**
|
||||
* An enumeration of the columns that can be added to the browser's tabular
|
||||
* view. NOTE THAT THE DISPLAY_NAME COLUMN IS ADDED AUTOMATICALLY BY THE
|
||||
* BROWSER AND ALL OTHER COLUMNS ARE OPTIONAL.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"MultiUserCaseBrowserCustomizer.column.displayName=Name",
|
||||
"MultiUserCaseBrowserCustomizer.column.createTime=Create Time",
|
||||
"MultiUserCaseBrowserCustomizer.column.directory=Directory"
|
||||
})
|
||||
public enum Column {
|
||||
DISPLAY_NAME(Bundle.MultiUserCaseBrowserCustomizer_column_displayName()),
|
||||
CREATE_DATE(Bundle.MultiUserCaseBrowserCustomizer_column_createTime()),
|
||||
DIRECTORY(Bundle.MultiUserCaseBrowserCustomizer_column_directory());
|
||||
|
||||
private final String displayName;
|
||||
|
||||
private Column(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the columns the tabular view in the browser should display. The
|
||||
* columns will be displayed in the order in which they appear in the list.
|
||||
* NOTE THAT THE DISPLAY_NAME COLUMN IS ADDED AS THE FIRST COLUMN
|
||||
* AUTOMATICALLY AND SHOULD NOT BE INCLUDED IN THIS LIST.
|
||||
*
|
||||
* @return A Column object.
|
||||
*/
|
||||
List<Column> getColumns();
|
||||
|
||||
/**
|
||||
* Gets a specification of the columns, if any, that define the default
|
||||
* sorting of the MultiUserCaseNodes in the browser.
|
||||
*
|
||||
* @return A list, possibly empty, of SortColumn objects.
|
||||
*/
|
||||
List<SortColumn> getSortColumns();
|
||||
|
||||
/**
|
||||
* Whether or not the browser should allow multiple selection of the
|
||||
* MultiUserCaseNodes displayed in the browser.
|
||||
*
|
||||
* @return True or false.
|
||||
*/
|
||||
boolean allowMultiSelect();
|
||||
|
||||
/**
|
||||
* Gets the context menu Actions for the MultiUserCaseNodes diplayed in the
|
||||
* browser. Can include actions that work with multiple node selection.
|
||||
*
|
||||
* @param nodeData The coordination service node data for a given
|
||||
* MultiUserCaseNode. Ignored for multi-select actions.
|
||||
*
|
||||
* @return A list of Actions.
|
||||
*/
|
||||
List<Action> getActions(CaseNodeData nodeData);
|
||||
|
||||
/**
|
||||
* Gets the preferred action for the MultiUserCaseNodes displayed in the
|
||||
* browser, i.e., the action to be performed when a node is double clicked.
|
||||
*
|
||||
* @param nodeData The coordination service node data for a given
|
||||
* MultiUserCaseNode.
|
||||
*
|
||||
* @return The preferred action.
|
||||
*/
|
||||
Action getPreferredAction(CaseNodeData nodeData);
|
||||
|
||||
/**
|
||||
* A specification of the sorting details for a column in the browser's
|
||||
* OutlineView.
|
||||
*/
|
||||
public final static class SortColumn {
|
||||
|
||||
private final Column column;
|
||||
private final boolean sortAscending;
|
||||
private final int sortRank;
|
||||
|
||||
/**
|
||||
* Constucts a specification of the sorting details for a column in the
|
||||
* browser's OutlineView.
|
||||
*
|
||||
* @param column
|
||||
* @param sortAscending
|
||||
* @param sortRank
|
||||
*/
|
||||
public SortColumn(Column column, boolean sortAscending, int sortRank) {
|
||||
this.column = column;
|
||||
this.sortAscending = sortAscending;
|
||||
this.sortRank = sortRank;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the column to be sorted.
|
||||
*
|
||||
* @return The column.
|
||||
*/
|
||||
public Column column() {
|
||||
return column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether or not the sort should be ascending.
|
||||
*
|
||||
* @return True or false.
|
||||
*/
|
||||
public boolean sortAscending() {
|
||||
return sortAscending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rank of the sort, i.e., should it be the first column to be
|
||||
* sorted, the second column, etc.
|
||||
*
|
||||
* @return The sort rank.
|
||||
*/
|
||||
public int sortRank() {
|
||||
return sortRank;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -16,44 +16,45 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
package org.sleuthkit.autopsy.casemodule.multiusercasesbrowser;
|
||||
|
||||
import org.sleuthkit.autopsy.coordinationservice.CaseNodeData;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javax.swing.Action;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercasesbrowser.MultiUserCaseBrowserCustomizer.Column;
|
||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||
|
||||
/**
|
||||
* A NetBeans Explorer View node that represents a multi-user case.
|
||||
* A NetBeans Explorer View node that represents a multi-user case in a
|
||||
* multi-user cases browser panel.
|
||||
*/
|
||||
final class MultiUserCaseNode extends AbstractNode {
|
||||
public final class MultiUserCaseNode extends AbstractNode {
|
||||
|
||||
private final CaseNodeData caseNodeData;
|
||||
private final MultiUserCaseBrowserCustomizer customizer;
|
||||
|
||||
/**
|
||||
* Constructs a NetBeans Explorer View node that represents a multi-user
|
||||
* case.
|
||||
* casein a multi-user cases browser panel.
|
||||
*
|
||||
* @param caseNodeData The coordination service node data for the case.
|
||||
* @param customizer A browser customizer that supplies the actions and
|
||||
* property sheet properties of the node.
|
||||
*/
|
||||
MultiUserCaseNode(CaseNodeData caseNodeData) {
|
||||
super(Children.LEAF);
|
||||
MultiUserCaseNode(CaseNodeData caseNodeData, MultiUserCaseBrowserCustomizer customizer) {
|
||||
super(Children.LEAF, Lookups.fixed(caseNodeData));
|
||||
super.setName(caseNodeData.getDisplayName());
|
||||
setName(caseNodeData.getDisplayName());
|
||||
setDisplayName(caseNodeData.getDisplayName());
|
||||
super.setDisplayName(caseNodeData.getDisplayName());
|
||||
this.caseNodeData = caseNodeData;
|
||||
this.customizer = customizer;
|
||||
}
|
||||
|
||||
@NbBundle.Messages({
|
||||
"MultiUserCaseNode.column.name=Name",
|
||||
"MultiUserCaseNode.column.createTime=Create Time",
|
||||
"MultiUserCaseNode.column.path=Path"
|
||||
})
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet sheet = super.createSheet();
|
||||
@ -62,42 +63,33 @@ final class MultiUserCaseNode extends AbstractNode {
|
||||
sheetSet = Sheet.createPropertiesSet();
|
||||
sheet.put(sheetSet);
|
||||
}
|
||||
sheetSet.put(new NodeProperty<>(Bundle.MultiUserCaseNode_column_name(),
|
||||
Bundle.MultiUserCaseNode_column_name(),
|
||||
Bundle.MultiUserCaseNode_column_name(),
|
||||
caseNodeData.getDisplayName()));
|
||||
sheetSet.put(new NodeProperty<>(Bundle.MultiUserCaseNode_column_createTime(),
|
||||
Bundle.MultiUserCaseNode_column_createTime(),
|
||||
Bundle.MultiUserCaseNode_column_createTime(),
|
||||
caseNodeData.getCreateDate()));
|
||||
sheetSet.put(new NodeProperty<>(Bundle.MultiUserCaseNode_column_path(),
|
||||
Bundle.MultiUserCaseNode_column_path(),
|
||||
Bundle.MultiUserCaseNode_column_path(),
|
||||
caseNodeData.getDirectory().toString()));
|
||||
for (Column property : customizer.getColumns()) {
|
||||
String propName = property.getDisplayName();
|
||||
switch (property) {
|
||||
case CREATE_DATE:
|
||||
sheetSet.put(new NodeProperty<>(propName, propName, propName, caseNodeData.getCreateDate()));
|
||||
break;
|
||||
case DIRECTORY:
|
||||
sheetSet.put(new NodeProperty<>(propName, propName, propName, caseNodeData.getDirectory().toString()));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sheet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action[] getActions(boolean context) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(new OpenMultiUserCaseAction(this.caseNodeData));
|
||||
actions.add(new OpenCaseAutoIngestLogAction(this.caseNodeData));
|
||||
actions.addAll(customizer.getActions(caseNodeData));
|
||||
actions.addAll(Arrays.asList(super.getActions(context)));
|
||||
return actions.toArray(new Action[actions.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action getPreferredAction() {
|
||||
return new OpenMultiUserCaseAction(this.caseNodeData);
|
||||
return customizer.getPreferredAction(caseNodeData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the coordintaion service case node data this Explorer View node
|
||||
* represents.
|
||||
*
|
||||
* @return The case node data.
|
||||
*/
|
||||
CaseNodeData getCaseNodeData() {
|
||||
return this.caseNodeData;
|
||||
}
|
||||
|
||||
}
|
@ -32,7 +32,7 @@
|
||||
</Property>
|
||||
<Property name="opaque" type="boolean" value="false"/>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[5, 5]"/>
|
||||
<Dimension value="[500, 500]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
@ -16,80 +16,60 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
package org.sleuthkit.autopsy.casemodule.multiusercasesbrowser;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
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.openide.util.NbBundle;
|
||||
import org.openide.explorer.view.OutlineView;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercasesbrowser.MultiUserCaseBrowserCustomizer.Column;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercasesbrowser.MultiUserCaseBrowserCustomizer.SortColumn;
|
||||
|
||||
/**
|
||||
* A JPanel with a scroll pane child component that contains a NetBeans
|
||||
* OutlineView that can be used to display a list of the multi-user cases known
|
||||
* to the coordination service.
|
||||
* A JPanel that contains a NetBeans OutlineView that is used to provide a
|
||||
* tabular view of the multi-user cases known to the coordination service. The
|
||||
* outline view set up, including the property sheets and actions of the
|
||||
* MultiUserCaseNodes it displays, are defined using a
|
||||
* MultiUserCaseBrowserCustomizer. Each MultiUserCaseNode has a CaseNodeData
|
||||
* object in its Lookup.
|
||||
*/
|
||||
@SuppressWarnings("PMD.SingularField") // Matisse-generated UI widgets cause lots of false positives
|
||||
final class MultiUserCasesBrowserPanel extends javax.swing.JPanel implements ExplorerManager.Provider {
|
||||
@SuppressWarnings("PMD.SingularField") // Matisse-generated UI widgets cause lots of false positives for this in PMD
|
||||
public final class MultiUserCasesBrowserPanel extends javax.swing.JPanel implements ExplorerManager.Provider {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final ExplorerManager explorerManager;
|
||||
private final MultiUserCaseBrowserCustomizer customizer;
|
||||
private final OutlineView outlineView;
|
||||
private final Outline outline;
|
||||
|
||||
/**
|
||||
* Constructs a JPanel with a scroll pane child component that contains a
|
||||
* NetBeans OutlineView that can be used to display a list of the multi-user
|
||||
* cases known to the coordination service.
|
||||
* Constructs a JPanel that contains a NetBeans OutlineView that is used to
|
||||
* provide a tabular view of the multi-user cases known to the coordination
|
||||
* service. The outline view set up, including the property sheets and
|
||||
* actions of the MultiUserCaseNodes it displays, are defined using a
|
||||
* MultiUserCaseBrowserCustomizer. Each MultiUserCaseNode has a CaseNodeData
|
||||
* object in its Lookup.
|
||||
*
|
||||
* @param explorerManager The ExplorerManager for the browser's OutlineView.
|
||||
* @param customizer A customizer for the browser.
|
||||
*/
|
||||
MultiUserCasesBrowserPanel() {
|
||||
explorerManager = new ExplorerManager();
|
||||
outlineView = new org.openide.explorer.view.OutlineView();
|
||||
public MultiUserCasesBrowserPanel(ExplorerManager explorerManager, MultiUserCaseBrowserCustomizer customizer) {
|
||||
this.explorerManager = explorerManager;
|
||||
this.customizer = customizer;
|
||||
initComponents();
|
||||
outline = outlineView.getOutline();
|
||||
outlineView = new org.openide.explorer.view.OutlineView();
|
||||
outline = this.outlineView.getOutline();
|
||||
configureOutlineView();
|
||||
explorerManager.setRootContext(new MultiUserCasesRootNode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the child scroll pane component's child OutlineView component.
|
||||
*/
|
||||
private void configureOutlineView() {
|
||||
outlineView.setPropertyColumns(
|
||||
Bundle.MultiUserCaseNode_column_createTime(), Bundle.MultiUserCaseNode_column_createTime(),
|
||||
Bundle.MultiUserCaseNode_column_path(), Bundle.MultiUserCaseNode_column_path());
|
||||
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.MultiUserCaseNode_column_name());
|
||||
outline.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
TableColumnModel columnModel = outline.getColumnModel();
|
||||
int pathColumnIndex = 0;
|
||||
int dateColumnIndex = 0;
|
||||
for (int index = 0; index < columnModel.getColumnCount(); index++) {
|
||||
if (columnModel.getColumn(index).getHeaderValue().toString().equals(Bundle.MultiUserCaseNode_column_path())) {
|
||||
pathColumnIndex = index;
|
||||
} else if (columnModel.getColumn(index).getHeaderValue().toString().equals(Bundle.MultiUserCaseNode_column_createTime())) {
|
||||
dateColumnIndex = index;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Hide path column by default (user can unhide it)
|
||||
*/
|
||||
ETableColumn column = (ETableColumn) columnModel.getColumn(pathColumnIndex);
|
||||
((ETableColumnModel) columnModel).setColumnHidden(column, true);
|
||||
outline.setRootVisible(false);
|
||||
|
||||
/*
|
||||
* Sort on Created date column in descending order by default.
|
||||
*/
|
||||
outline.setColumnSorted(dateColumnIndex, false, 1);
|
||||
|
||||
caseTableScrollPane.add(outlineView);
|
||||
caseTableScrollPane.setViewportView(outlineView);
|
||||
this.setVisible(true);
|
||||
this.setVisible(true);
|
||||
displayCases();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -97,23 +77,58 @@ final class MultiUserCasesBrowserPanel extends javax.swing.JPanel implements Exp
|
||||
return explorerManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the child scroll pane component's child OutlineView component.
|
||||
*/
|
||||
private void configureOutlineView() {
|
||||
/*
|
||||
* Set up the outline view columns and sorting.
|
||||
*/
|
||||
Map<Column, SortColumn> sortColumns = new HashMap<>();
|
||||
for (SortColumn sortColumn : customizer.getSortColumns()) {
|
||||
sortColumns.put(sortColumn.column(), sortColumn);
|
||||
}
|
||||
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Column.DISPLAY_NAME.getDisplayName());
|
||||
if (sortColumns.containsKey(Column.DISPLAY_NAME)) {
|
||||
SortColumn sortColumn = sortColumns.get(Column.DISPLAY_NAME);
|
||||
outline.setColumnSorted(0, sortColumn.sortAscending(), sortColumn.sortRank());
|
||||
}
|
||||
List<Column> sheetProperties = customizer.getColumns();
|
||||
for (int index = 0; index < sheetProperties.size(); ++index) {
|
||||
Column property = sheetProperties.get(index);
|
||||
String propertyName = property.getDisplayName();
|
||||
outlineView.addPropertyColumn(propertyName, propertyName, propertyName);
|
||||
if (sortColumns.containsKey(property)) {
|
||||
SortColumn sortColumn = sortColumns.get(property);
|
||||
outline.setColumnSorted(index + 1, sortColumn.sortAscending(), sortColumn.sortRank());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Hide the root node and configure the node selection mode.
|
||||
*/
|
||||
outline.setRootVisible(false);
|
||||
outline.setSelectionMode(customizer.allowMultiSelect() ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION : ListSelectionModel.SINGLE_SELECTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener to changes in case selection in this browser.
|
||||
*
|
||||
* @param listener the ListSelectionListener to add
|
||||
*/
|
||||
void addListSelectionListener(ListSelectionListener listener) {
|
||||
public void addListSelectionListener(ListSelectionListener listener) {
|
||||
outline.getSelectionModel().addListSelectionListener(listener);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the list of multi-user cases in this browser.
|
||||
* Fetches and displays the list of multi-user cases known to the
|
||||
* coordination service in this browser.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"MultiUserCasesBrowserPanel.waitNode.message=Please Wait..."
|
||||
})
|
||||
void refreshCases() {
|
||||
explorerManager.setRootContext(new MultiUserCasesRootNode());
|
||||
public void displayCases() {
|
||||
explorerManager.setRootContext(new MultiUserCasesRootNode(customizer));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -134,7 +149,7 @@ final class MultiUserCasesBrowserPanel extends javax.swing.JPanel implements Exp
|
||||
caseTableScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
caseTableScrollPane.setMinimumSize(new java.awt.Dimension(0, 5));
|
||||
caseTableScrollPane.setOpaque(false);
|
||||
caseTableScrollPane.setPreferredSize(new java.awt.Dimension(5, 5));
|
||||
caseTableScrollPane.setPreferredSize(new java.awt.Dimension(500, 500));
|
||||
add(caseTableScrollPane, java.awt.BorderLayout.CENTER);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
@ -16,15 +16,16 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
package org.sleuthkit.autopsy.casemodule.multiusercasesbrowser;
|
||||
|
||||
import org.sleuthkit.autopsy.coordinationservice.CaseNodeData;
|
||||
import java.util.List;
|
||||
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.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercases.MultiUserCaseNodeDataCollector;
|
||||
import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
|
||||
@ -42,8 +43,8 @@ final class MultiUserCasesRootNode extends AbstractNode {
|
||||
* @param case A list of coordination service node data objects representing
|
||||
* multi-user cases.
|
||||
*/
|
||||
MultiUserCasesRootNode() {
|
||||
super(Children.create(new MultiUserCasesRootNodeChildren(), true));
|
||||
MultiUserCasesRootNode(MultiUserCaseBrowserCustomizer childNodeCustomizer) {
|
||||
super(Children.create(new MultiUserCasesRootNodeChildren(childNodeCustomizer), true));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -53,6 +54,12 @@ final class MultiUserCasesRootNode extends AbstractNode {
|
||||
*/
|
||||
private static class MultiUserCasesRootNodeChildren extends ChildFactory<CaseNodeData> {
|
||||
|
||||
private MultiUserCaseBrowserCustomizer nodeCustomizer;
|
||||
|
||||
MultiUserCasesRootNodeChildren(MultiUserCaseBrowserCustomizer nodeCustomizer) {
|
||||
this.nodeCustomizer = nodeCustomizer;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<CaseNodeData> keys) {
|
||||
try {
|
||||
@ -66,7 +73,7 @@ final class MultiUserCasesRootNode extends AbstractNode {
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(CaseNodeData key) {
|
||||
return new MultiUserCaseNode(key);
|
||||
return new MultiUserCaseNode(key, this.nodeCustomizer);
|
||||
}
|
||||
|
||||
}
|
@ -4,4 +4,4 @@ OpenIDE-Module: org.sleuthkit.autopsy.experimental
|
||||
OpenIDE-Module-Layer: org/sleuthkit/autopsy/experimental/autoingest/layer.xml
|
||||
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties
|
||||
OpenIDE-Module-Requires: org.openide.windows.WindowManager
|
||||
OpenIDE-Module-Specification-Version: 1.0
|
||||
OpenIDE-Module-Specification-Version: 1.0
|
||||
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019-2019 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
|
||||
* 9
|
||||
* 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.experimental.autoingest;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.Action;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercasesbrowser.MultiUserCaseBrowserCustomizer;
|
||||
|
||||
/**
|
||||
* A customizer for a multi-user case browser panel that presents a tabular view
|
||||
* of the multi-user cases known to the coordination service in the
|
||||
* administrative dashboard for auto ingest cases.
|
||||
*/
|
||||
final class AutoIngestCasesDashboardNodeCustomizer implements MultiUserCaseBrowserCustomizer {
|
||||
|
||||
private final DeleteCaseInputDirectoriesAction deleteCaseInputAction;
|
||||
private final DeleteCasesForReprocessingAction deleteCaseOutputAction;
|
||||
private final DeleteCasesAction deleteCaseAction;
|
||||
|
||||
/**
|
||||
* Constructs a customizer for a multi-user case browser panel that presents
|
||||
* a tabular view of the multi-user cases known to the coordination service
|
||||
* in the administrative dashboard for auto ingest cases.
|
||||
*/
|
||||
AutoIngestCasesDashboardNodeCustomizer() {
|
||||
/*
|
||||
* These actions are shared by all nodes in order to support multiple
|
||||
* selection.
|
||||
*/
|
||||
deleteCaseInputAction = new DeleteCaseInputDirectoriesAction();
|
||||
deleteCaseOutputAction = new DeleteCasesForReprocessingAction();
|
||||
deleteCaseAction = new DeleteCasesAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Column> getColumns() {
|
||||
List<Column> properties = new ArrayList<>();
|
||||
properties.add(Column.CREATE_DATE);
|
||||
properties.add(Column.DIRECTORY);
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SortColumn> getSortColumns() {
|
||||
List<SortColumn> sortColumns = new ArrayList<>();
|
||||
sortColumns.add(new SortColumn(Column.DISPLAY_NAME, true, 1));
|
||||
return sortColumns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowMultiSelect() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getActions(CaseNodeData nodeData) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(new OpenCaseAction(nodeData));
|
||||
actions.add(new OpenAutoIngestLogAction(nodeData));
|
||||
actions.add(deleteCaseInputAction);
|
||||
actions.add(deleteCaseOutputAction);
|
||||
actions.add(deleteCaseAction);
|
||||
actions.add(new ShowCaseDeletionStatusAction(nodeData));
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action getPreferredAction(CaseNodeData nodeData) {
|
||||
return new OpenCaseAction(nodeData);
|
||||
}
|
||||
|
||||
}
|
@ -81,6 +81,7 @@ public final class AutoIngestDashboardTopComponent extends TopComponent {
|
||||
if (AutoIngestDashboard.isAdminAutoIngestDashboard()) {
|
||||
EventQueue.invokeLater(() -> {
|
||||
AinStatusDashboardTopComponent.openTopComponent(dashboard.getMonitor());
|
||||
MultiUserCasesDashboardTopComponent.openTopComponent();
|
||||
});
|
||||
}
|
||||
tc.open();
|
||||
|
@ -63,7 +63,7 @@ import org.sleuthkit.autopsy.casemodule.Case.CaseType;
|
||||
import org.sleuthkit.autopsy.casemodule.CaseActionException;
|
||||
import org.sleuthkit.autopsy.casemodule.CaseDetails;
|
||||
import org.sleuthkit.autopsy.casemodule.CaseMetadata;
|
||||
import org.sleuthkit.autopsy.coordinationservice.CaseNodeData;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData;
|
||||
import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
|
||||
import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException;
|
||||
import org.sleuthkit.autopsy.coordinationservice.CoordinationService.Lock;
|
||||
|
@ -262,3 +262,8 @@ AinStatusDashboard.refreshButton.text=&Refresh
|
||||
AinStatusDashboard.clusterMetricsButton.text=Auto Ingest &Metrics
|
||||
AinStatusDashboard.nodeStatusTableTitle.text=Auto Ingest Nodes
|
||||
AinStatusDashboard.healthMonitorButton.text=Health Monitor
|
||||
|
||||
# To change this license header, choose License Headers in Project Properties.
|
||||
# To change this template file, choose Tools | Templates
|
||||
# and open the template in the editor.
|
||||
MultiUserCasesDashboardTopComponent.refreshButton.text=Refresh
|
||||
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019-2019 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.experimental.autoingest;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import javax.swing.AbstractAction;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.Utilities;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData;
|
||||
|
||||
/**
|
||||
* An action that deletes the auto ingest job input directories associated with
|
||||
* one or more multi-user cases. The coordination service nodes for the auto
|
||||
* ingest jobs are not deleted. This supports the use case where the directories
|
||||
* may need to be directed to reclaim space, but the option to restore the
|
||||
* directories without having the jobs be reprocessed is retained.
|
||||
*
|
||||
* This cases to delete are discovered by querying the actions global context
|
||||
* lookup for CaseNodeData objects. See
|
||||
* https://platform.netbeans.org/tutorials/nbm-selection-1.html and
|
||||
* https://platform.netbeans.org/tutorials/nbm-selection-2.html for details.
|
||||
*/
|
||||
final class DeleteCaseInputDirectoriesAction extends AbstractAction {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@NbBundle.Messages({
|
||||
"DeleteCaseInputDirectoriesAction.menuItemText=Delete Input Directories"
|
||||
})
|
||||
DeleteCaseInputDirectoriesAction() {
|
||||
super(Bundle.DeleteCaseInputDirectoriesAction_menuItemText());
|
||||
setEnabled(false); // RJCTODO: Enable when implemented
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
final Collection<CaseNodeData> selectedNodeData = new ArrayList<>(Utilities.actionsGlobalContext().lookupAll(CaseNodeData.class));
|
||||
if (!selectedNodeData.isEmpty()) {
|
||||
/*
|
||||
* RJCTODO: Create a background task that does the deletion and
|
||||
* displays results in a dialog with a scrolling text pane.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeleteCaseInputDirectoriesAction clone() throws CloneNotSupportedException {
|
||||
throw new CloneNotSupportedException();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019-2019 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.experimental.autoingest;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import javax.swing.AbstractAction;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.Utilities;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData;
|
||||
|
||||
/**
|
||||
* An action that completely deletes one or more multi-user cases, including any
|
||||
* associated auto ingest job input directories and coordination service nodes.
|
||||
*
|
||||
* This cases to delete are discovered by querying the actions global context
|
||||
* lookup for CaseNodeData objects. See
|
||||
* https://platform.netbeans.org/tutorials/nbm-selection-1.html and
|
||||
* https://platform.netbeans.org/tutorials/nbm-selection-2.html for details.
|
||||
*/
|
||||
final class DeleteCasesAction extends AbstractAction {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@NbBundle.Messages({
|
||||
"DeleteCasesAction.menuItemText=Delete Case and Jobs"
|
||||
})
|
||||
DeleteCasesAction() {
|
||||
super(Bundle.DeleteCasesAction_menuItemText());
|
||||
setEnabled(false); // RJCTODO: Enable when implemented
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
final Collection<CaseNodeData> selectedNodeData = new ArrayList<>(Utilities.actionsGlobalContext().lookupAll(CaseNodeData.class));
|
||||
if (!selectedNodeData.isEmpty()) {
|
||||
/*
|
||||
* RJCTODO: Create a background task that does the deletion and
|
||||
* displays results in a dialog with a scrolling text pane.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeleteCasesAction clone() throws CloneNotSupportedException {
|
||||
throw new CloneNotSupportedException();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019-2019 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.experimental.autoingest;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import javax.swing.AbstractAction;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.Utilities;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData;
|
||||
|
||||
/**
|
||||
* An action that deletes everything except the auto ingest job input
|
||||
* directories for one or more multi-user cases. This supports the use case
|
||||
* where a case needs to be reprocessed, so the input directories are not
|
||||
* deleted even though the coordination service nodes for the auto ingest jobs
|
||||
* are deleted.
|
||||
*
|
||||
* This cases to delete are discovered by querying the actions global context
|
||||
* lookup for CaseNodeData objects. See
|
||||
* https://platform.netbeans.org/tutorials/nbm-selection-1.html and
|
||||
* https://platform.netbeans.org/tutorials/nbm-selection-2.html for details.
|
||||
*/
|
||||
final class DeleteCasesForReprocessingAction extends AbstractAction {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@NbBundle.Messages({
|
||||
"DeleteCasesForReprocessingAction.menuItemText=Delete for Reprocessing"
|
||||
})
|
||||
DeleteCasesForReprocessingAction() {
|
||||
super(Bundle.DeleteCasesForReprocessingAction_menuItemText());
|
||||
setEnabled(false); // RJCTODO: Enable when implemented
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
final Collection<CaseNodeData> selectedNodeData = new ArrayList<>(Utilities.actionsGlobalContext().lookupAll(CaseNodeData.class));
|
||||
if (!selectedNodeData.isEmpty()) {
|
||||
/*
|
||||
* RJCTODO: Create a background task that does the deletion and
|
||||
* displays results in a dialog with a scrolling text pane.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeleteCasesForReprocessingAction clone() throws CloneNotSupportedException {
|
||||
throw new CloneNotSupportedException();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" 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="true"/>
|
||||
<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" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="refreshButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="458" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Component id="caseBrowserScrollPane" max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="caseBrowserScrollPane" pref="246" max="32767" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="refreshButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JButton" name="refreshButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="MultiUserCasesDashboardTopComponent.refreshButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="refreshButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Container class="javax.swing.JScrollPane" name="caseBrowserScrollPane">
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019-2019 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.experimental.autoingest;
|
||||
|
||||
import org.openide.explorer.ExplorerManager;
|
||||
import org.openide.explorer.ExplorerUtils;
|
||||
import org.openide.windows.TopComponent;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.windows.Mode;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercasesbrowser.MultiUserCasesBrowserPanel;
|
||||
|
||||
/**
|
||||
* A top component that provides an adminstrative dashboard for multi-user
|
||||
* cases.
|
||||
*/
|
||||
@TopComponent.Description(
|
||||
preferredID = "MultiUserCasesDashboardTopComponent",
|
||||
persistenceType = TopComponent.PERSISTENCE_ALWAYS
|
||||
)
|
||||
@TopComponent.Registration(
|
||||
mode = "dashboard",
|
||||
openAtStartup = false
|
||||
)
|
||||
@TopComponent.OpenActionRegistration(
|
||||
displayName = "#CTL_MultiUserCasesDashboardAction",
|
||||
preferredID = "MultiUserCasesDashboardTopComponent"
|
||||
)
|
||||
@Messages({
|
||||
"CTL_MultiUserCasesDashboardAction=Multi-User Cases Dashboard",
|
||||
"CTL_MultiUserCasesDashboardTopComponent=Cases",
|
||||
"HINT_MultiUserCasesDashboardTopComponent=This is an adminstrative dashboard for multi-user cases"
|
||||
})
|
||||
@SuppressWarnings("PMD.SingularField") // Prevent these warnings about generated code
|
||||
public final class MultiUserCasesDashboardTopComponent extends TopComponent implements ExplorerManager.Provider {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final ExplorerManager explorerManager;
|
||||
private final MultiUserCasesBrowserPanel caseBrowserPanel;
|
||||
|
||||
/**
|
||||
* Opens a singleton top component that provides an adminstrative dashboard
|
||||
* for multi-user cases. The top component is docked into the "dashboard
|
||||
* mode" defined by the auto ingest jobs top component.
|
||||
*/
|
||||
// RJCTODO: Consider moving all of the dashboard code into its own
|
||||
// admindashboards or dashboards package.
|
||||
public static void openTopComponent() {
|
||||
MultiUserCasesDashboardTopComponent topComponent = (MultiUserCasesDashboardTopComponent) WindowManager.getDefault().findTopComponent("MultiUserCasesDashboardTopComponent");
|
||||
if (topComponent != null) {
|
||||
if (!topComponent.isOpened()) {
|
||||
Mode mode = WindowManager.getDefault().findMode("dashboard"); // NON-NLS
|
||||
if (mode != null) {
|
||||
mode.dockInto(topComponent);
|
||||
}
|
||||
topComponent.open();
|
||||
}
|
||||
topComponent.toFront();
|
||||
topComponent.requestActive();
|
||||
}
|
||||
}
|
||||
|
||||
public MultiUserCasesDashboardTopComponent() {
|
||||
initComponents();
|
||||
setName(Bundle.CTL_MultiUserCasesDashboardTopComponent());
|
||||
setToolTipText(Bundle.HINT_MultiUserCasesDashboardTopComponent());
|
||||
explorerManager = new ExplorerManager();
|
||||
associateLookup(ExplorerUtils.createLookup(explorerManager, getActionMap()));
|
||||
caseBrowserPanel = new MultiUserCasesBrowserPanel(explorerManager, new AutoIngestCasesDashboardNodeCustomizer());
|
||||
caseBrowserScrollPane.add(caseBrowserPanel);
|
||||
caseBrowserScrollPane.setViewportView(caseBrowserPanel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentOpened() {
|
||||
//caseBrowserPanel.displayCases();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentClosed() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExplorerManager getExplorerManager() {
|
||||
return explorerManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
|
||||
refreshButton = new javax.swing.JButton();
|
||||
caseBrowserScrollPane = new javax.swing.JScrollPane();
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(refreshButton, org.openide.util.NbBundle.getMessage(MultiUserCasesDashboardTopComponent.class, "MultiUserCasesDashboardTopComponent.refreshButton.text")); // NOI18N
|
||||
refreshButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
refreshButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(refreshButton)
|
||||
.addGap(0, 458, Short.MAX_VALUE))
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addComponent(caseBrowserScrollPane)
|
||||
.addContainerGap())))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(caseBrowserScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 246, Short.MAX_VALUE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(refreshButton)
|
||||
.addContainerGap())
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void refreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshButtonActionPerformed
|
||||
caseBrowserPanel.displayCases();
|
||||
}//GEN-LAST:event_refreshButtonActionPerformed
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JScrollPane caseBrowserScrollPane;
|
||||
private javax.swing.JButton refreshButton;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
package org.sleuthkit.autopsy.experimental.autoingest;
|
||||
|
||||
import java.awt.Desktop;
|
||||
import java.awt.event.ActionEvent;
|
||||
@ -26,7 +26,7 @@ import java.nio.file.Paths;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.AbstractAction;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.coordinationservice.CaseNodeData;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
|
||||
@ -34,10 +34,10 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
* An action that opens a case auto ingest log given the coordination service
|
||||
* node data for the case.
|
||||
*/
|
||||
final class OpenCaseAutoIngestLogAction extends AbstractAction {
|
||||
public final class OpenAutoIngestLogAction extends AbstractAction {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger logger = Logger.getLogger(OpenCaseAutoIngestLogAction.class.getName());
|
||||
private static final Logger logger = Logger.getLogger(OpenAutoIngestLogAction.class.getName());
|
||||
private static final String CASE_AUTO_INGEST_LOG_FILE_NAME = "auto_ingest_log.txt";
|
||||
private final Path caseAutoIngestLogFilePath;
|
||||
|
||||
@ -48,17 +48,17 @@ final class OpenCaseAutoIngestLogAction extends AbstractAction {
|
||||
* @param caseNodeData The coordination service node data for the case.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"OpenCaseAutoIngestLogAction.menuItemText=Open Auto Ingest Log File"
|
||||
"OpenAutoIngestLogAction.menuItemText=Open Auto Ingest Log File"
|
||||
})
|
||||
OpenCaseAutoIngestLogAction(CaseNodeData caseNodeData) {
|
||||
super(Bundle.OpenCaseAutoIngestLogAction_menuItemText());
|
||||
public OpenAutoIngestLogAction(CaseNodeData caseNodeData) {
|
||||
super(Bundle.OpenAutoIngestLogAction_menuItemText());
|
||||
this.caseAutoIngestLogFilePath = Paths.get(caseNodeData.getDirectory().toString(), CASE_AUTO_INGEST_LOG_FILE_NAME);
|
||||
this.setEnabled(caseAutoIngestLogFilePath.toFile().exists());
|
||||
}
|
||||
|
||||
@NbBundle.Messages({
|
||||
"OpenCaseAutoIngestLogAction.deletedLogErrorMsg=The case auto ingest log has been deleted.",
|
||||
"OpenCaseAutoIngestLogAction.logOpenFailedErrorMsg=Failed to open case auto ingest log. See application log for details."
|
||||
"OpenAutoIngestLogAction.deletedLogErrorMsg=The case auto ingest log has been deleted.",
|
||||
"OpenAutoIngestLogAction.logOpenFailedErrorMsg=Failed to open case auto ingest log. See application log for details."
|
||||
})
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
@ -66,16 +66,16 @@ final class OpenCaseAutoIngestLogAction extends AbstractAction {
|
||||
if (caseAutoIngestLogFilePath.toFile().exists()) {
|
||||
Desktop.getDesktop().edit(caseAutoIngestLogFilePath.toFile());
|
||||
} else {
|
||||
MessageNotifyUtil.Message.error(Bundle.OpenCaseAutoIngestLogAction_deletedLogErrorMsg());
|
||||
MessageNotifyUtil.Message.error(Bundle.OpenAutoIngestLogAction_deletedLogErrorMsg());
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Error opening case auto ingest log file at %s", caseAutoIngestLogFilePath), ex); //NON-NLS
|
||||
MessageNotifyUtil.Message.error(Bundle.OpenCaseAutoIngestLogAction_logOpenFailedErrorMsg());
|
||||
MessageNotifyUtil.Message.error(Bundle.OpenAutoIngestLogAction_logOpenFailedErrorMsg());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenCaseAutoIngestLogAction clone() throws CloneNotSupportedException {
|
||||
public OpenAutoIngestLogAction clone() throws CloneNotSupportedException {
|
||||
super.clone();
|
||||
throw new CloneNotSupportedException();
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019-2019 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.experimental.autoingest;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.io.File;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.CaseActionCancelledException;
|
||||
import org.sleuthkit.autopsy.casemodule.CaseActionException;
|
||||
import org.sleuthkit.autopsy.casemodule.CaseMetadata;
|
||||
import org.sleuthkit.autopsy.casemodule.OpenMultiUserCaseDialog;
|
||||
import org.sleuthkit.autopsy.casemodule.StartupWindowProvider;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
|
||||
/**
|
||||
* An action that opens a multi-user case known to the coordination service.
|
||||
*/
|
||||
final class OpenCaseAction extends AbstractAction {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger logger = Logger.getLogger(org.sleuthkit.autopsy.casemodule.OpenMultiUserCaseAction.class.getName());
|
||||
private final CaseNodeData caseNodeData;
|
||||
|
||||
/**
|
||||
* Constructs an action that opens a multi-user case known to the
|
||||
* coordination service.
|
||||
*
|
||||
* @param caseNodeData The coordination service node data for the case.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"OpenCaseAction.menuItemText=Open"
|
||||
})
|
||||
public OpenCaseAction(CaseNodeData caseNodeData) {
|
||||
super(Bundle.OpenCaseAction_menuItemText());
|
||||
this.caseNodeData = caseNodeData;
|
||||
}
|
||||
|
||||
@NbBundle.Messages({
|
||||
"# {0} - caseErrorMessage", "OpenCaseAction.errorMsg=Failed to open case: {0}"
|
||||
})
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
new Thread(() -> {
|
||||
String caseMetadataFilePath = null;
|
||||
File caseDirectory = caseNodeData.getDirectory().toFile();
|
||||
File[] filesInDirectory = caseDirectory.listFiles();
|
||||
if (filesInDirectory != null) {
|
||||
for (File file : filesInDirectory) {
|
||||
if (file.getName().toLowerCase().endsWith(CaseMetadata.getFileExtension()) && file.isFile()) {
|
||||
caseMetadataFilePath = file.getPath();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (caseMetadataFilePath != null) {
|
||||
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
|
||||
}
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
MessageNotifyUtil.Message.error(Bundle.OpenCaseAction_errorMsg(ex.getLocalizedMessage()));
|
||||
StartupWindowProvider.getInstance().open();
|
||||
OpenMultiUserCaseDialog.getInstance().setVisible(true);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
MessageNotifyUtil.Message.error(Bundle.OpenCaseAction_errorMsg("Could not locate case metadata file."));
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenCaseAction clone() throws CloneNotSupportedException {
|
||||
throw new CloneNotSupportedException();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.experimental.autoingest;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import javax.swing.AbstractAction;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData;
|
||||
|
||||
/**
|
||||
* An action that shows a popup that enumerates the deletion status of the
|
||||
* various parts of a multi-user case known to the coordination service.
|
||||
*/
|
||||
final class ShowCaseDeletionStatusAction extends AbstractAction {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final CaseNodeData caseNodeData;
|
||||
|
||||
/**
|
||||
* Constructs an action that shows a popup that enumerates the deletion
|
||||
* status of the various parts of a multi-user case known to the
|
||||
* coordination service.
|
||||
*
|
||||
* @param caseNodeData The coordination service node data for the case.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"ShowCaseDeletionStatusAction.menuItemText=Show Deletion Status"
|
||||
})
|
||||
public ShowCaseDeletionStatusAction(CaseNodeData caseNodeData) {
|
||||
super(Bundle.ShowCaseDeletionStatusAction_menuItemText());
|
||||
this.caseNodeData = caseNodeData;
|
||||
setEnabled(false); // RJCTODO: Enable when implemented
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
// RJCTODO: Implement
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShowCaseDeletionStatusAction clone() throws CloneNotSupportedException {
|
||||
throw new CloneNotSupportedException();
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user