From d11c827e7bc2172e5964673899e22d66b5c5d99d Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 22 Aug 2017 15:05:15 -0400 Subject: [PATCH 1/2] New AID implemented. --- Experimental/manifest.mf | 3 +- Experimental/nbproject/project.xml | 11 +- .../autoingest/AutoIngestControlPanel.form | 475 +++++ .../autoingest/AutoIngestControlPanel.java | 1731 +++++++++++++++++ .../autoingest/AutoIngestDashboard.form | 41 +- .../autoingest/AutoIngestDashboard.java | 417 +--- .../AutoIngestDashboardOpenAction.java | 111 ++ .../AutoIngestDashboardTopComponent.form | 28 + .../AutoIngestDashboardTopComponent.java | 135 ++ .../experimental/autoingest/Bundle.properties | 35 + .../configuration/StartupWindow.java | 11 +- .../netbeans/core/startup/Bundle.properties | 2 +- .../core/windows/view/ui/Bundle.properties | 2 +- 13 files changed, 2540 insertions(+), 462 deletions(-) create mode 100755 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.form create mode 100755 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java create mode 100755 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java create mode 100755 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.form create mode 100755 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.java diff --git a/Experimental/manifest.mf b/Experimental/manifest.mf index cafb630948..15ed8c19f7 100644 --- a/Experimental/manifest.mf +++ b/Experimental/manifest.mf @@ -3,4 +3,5 @@ AutoUpdate-Show-In-Client: true 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-Specification-Version: 1.0 +OpenIDE-Module-Requires: org.openide.windows.WindowManager +OpenIDE-Module-Specification-Version: 1.0 \ No newline at end of file diff --git a/Experimental/nbproject/project.xml b/Experimental/nbproject/project.xml index 280fbc431b..843d3dfb36 100644 --- a/Experimental/nbproject/project.xml +++ b/Experimental/nbproject/project.xml @@ -24,6 +24,15 @@ 1.44.1 + + org.netbeans.modules.settings + + + + 1 + 1.49.1 + + org.openide.awt @@ -158,4 +167,4 @@ - + \ No newline at end of file diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.form new file mode 100755 index 0000000000..f7fc33d78e --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.form @@ -0,0 +1,475 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java new file mode 100755 index 0000000000..d48cd31c7f --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java @@ -0,0 +1,1731 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015-2017 Basis Technology Corp. + * Contact: carrier sleuthkit 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 com.google.common.util.concurrent.ThreadFactoryBuilder; +import java.awt.Cursor; +import java.awt.Desktop; +import java.awt.EventQueue; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import java.util.Observable; +import java.util.Observer; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.logging.Level; +import javax.swing.DefaultListSelectionModel; +import java.awt.Color; +import java.beans.PropertyChangeEvent; +import java.io.File; +import java.util.Collections; +import java.util.logging.Logger; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.SwingWorker; +import javax.swing.UIManager; +import javax.swing.event.ListSelectionEvent; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableColumn; +import org.netbeans.api.options.OptionsDisplayer; +import org.openide.DialogDisplayer; +import org.openide.LifecycleManager; +import org.openide.NotifyDescriptor; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.util.NbBundle; +import org.openide.util.actions.CallableSystemAction; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.casemodule.CaseNewAction; +import org.sleuthkit.autopsy.casemodule.CaseOpenAction; +import org.sleuthkit.autopsy.core.ServicesMonitor; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.coreutils.NetworkUtils; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.ingest.IngestProgressSnapshotDialog; +import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestManager.CaseDeletionResult; +import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestManager.JobsSnapshot; + +/** + * A panel for monitoring automated ingest by a cluster, and for controlling + * automated ingest for a single node within the cluster. There can be at most + * one such panel per node. + */ +public final class AutoIngestControlPanel extends JPanel implements Observer { + + private static final long serialVersionUID = 1L; + private static final int GENERIC_COL_MIN_WIDTH = 30; + private static final int GENERIC_COL_MAX_WIDTH = 2000; + private static final int PENDING_TABLE_COL_PREFERRED_WIDTH = 280; + private static final int RUNNING_TABLE_COL_PREFERRED_WIDTH = 175; + private static final int ACTIVITY_TIME_COL_MIN_WIDTH = 250; + private static final int ACTIVITY_TIME_COL_MAX_WIDTH = 450; + private static final int TIME_COL_MIN_WIDTH = 30; + private static final int TIME_COL_MAX_WIDTH = 250; + private static final int TIME_COL_PREFERRED_WIDTH = 140; + private static final int NAME_COL_MIN_WIDTH = 100; + private static final int NAME_COL_MAX_WIDTH = 250; + private static final int NAME_COL_PREFERRED_WIDTH = 140; + private static final int ACTIVITY_COL_MIN_WIDTH = 70; + private static final int ACTIVITY_COL_MAX_WIDTH = 2000; + private static final int ACTIVITY_COL_PREFERRED_WIDTH = 300; + private static final int STATUS_COL_MIN_WIDTH = 55; + private static final int STATUS_COL_MAX_WIDTH = 250; + private static final int STATUS_COL_PREFERRED_WIDTH = 55; + private static final int COMPLETED_TIME_COL_MIN_WIDTH = 30; + private static final int COMPLETED_TIME_COL_MAX_WIDTH = 2000; + private static final int COMPLETED_TIME_COL_PREFERRED_WIDTH = 280; + private static final String UPDATE_TASKS_THREAD_NAME = "AID-update-tasks-%d"; + private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName(); + private static final Logger SYS_LOGGER = AutoIngestSystemLogger.getLogger(); + private static AutoIngestControlPanel instance; + private final DefaultTableModel pendingTableModel; + private final DefaultTableModel runningTableModel; + private final DefaultTableModel completedTableModel; + private AutoIngestManager manager; + private ExecutorService updateExecutor; + private boolean isPaused; + private boolean autoIngestStarted; + private Color pendingTableBackground; + private Color pendingTablelForeground; + + /* + * The enum is used in conjunction with the DefaultTableModel class to + * provide table models for the JTables used to display a view of the + * pending jobs queue, running jobs list, and completed jobs list. The enum + * allows the columns of the table model to be described by either an enum + * ordinal or a column header string. + */ + private enum JobsTableModelColumns { + + CASE(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.Case")), + DATA_SOURCE(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.ImageFolder")), + HOST_NAME(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.HostName")), + CREATED_TIME(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.CreatedTime")), + STARTED_TIME(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.StartedTime")), + COMPLETED_TIME(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.CompletedTime")), + STAGE(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.Stage")), + STAGE_TIME(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.StageTime")), + STATUS(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.Status")), + CASE_DIRECTORY_PATH(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.CaseFolder")), + IS_LOCAL_JOB(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.LocalJob")), + MANIFEST_FILE_PATH(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.ManifestFilePath")); + + private final String header; + + private JobsTableModelColumns(String header) { + this.header = header; + } + + private String getColumnHeader() { + return header; + } + + private static final String[] headers = { + CASE.getColumnHeader(), + DATA_SOURCE.getColumnHeader(), + HOST_NAME.getColumnHeader(), + CREATED_TIME.getColumnHeader(), + STARTED_TIME.getColumnHeader(), + COMPLETED_TIME.getColumnHeader(), + STAGE.getColumnHeader(), + STATUS.getColumnHeader(), + STAGE_TIME.getColumnHeader(), + CASE_DIRECTORY_PATH.getColumnHeader(), + IS_LOCAL_JOB.getColumnHeader(), + MANIFEST_FILE_PATH.getColumnHeader()}; + } + + /** + * Gets the singleton automated ingest control and monitoring panel for this + * cluster node. + * + * @return The panel. + */ + public static AutoIngestControlPanel getInstance() { + if (null == instance) { + /* + * Two stage construction is used here to avoid publishing a + * reference to the panel to the Observable auto ingest manager + * before object construction is complete. + */ + instance = new AutoIngestControlPanel(); + } + return instance; + } + + /** + * Constructs a panel for monitoring automated ingest by a cluster, and for + * controlling automated ingest for a single node within the cluster. + */ + private AutoIngestControlPanel() { + //Disable the main window so they can only use the dashboard (if we used setVisible the taskBar icon would go away) + WindowManager.getDefault().getMainWindow().setEnabled(false); + + manager = AutoIngestManager.getInstance(); + + pendingTableModel = new DefaultTableModel(JobsTableModelColumns.headers, 0) { + private static final long serialVersionUID = 1L; + + @Override + public boolean isCellEditable(int row, int column) { + return false; + } + }; + + runningTableModel = new DefaultTableModel(JobsTableModelColumns.headers, 0) { + private static final long serialVersionUID = 1L; + + @Override + public boolean isCellEditable(int row, int column) { + return false; + } + }; + + completedTableModel = new DefaultTableModel(JobsTableModelColumns.headers, 0) { + private static final long serialVersionUID = 1L; + + @Override + public boolean isCellEditable(int row, int column) { + return false; + } + }; + + initComponents(); // Generated code. + setServicesStatusMessage(); + initPendingJobsTable(); + initRunningJobsTable(); + initCompletedJobsTable(); + initButtons(); + + /* + * Must set this flag, otherwise pop up menus don't close properly. + */ + UIManager.put("PopupMenu.consumeEventOnClose", false); + } + + /** + * Queries the services monitor and sets the text for the services status + * text box. + */ + private void setServicesStatusMessage() { + new SwingWorker() { + + String caseDatabaseServerStatus = ServicesMonitor.ServiceStatus.DOWN.toString(); + String keywordSearchServiceStatus = ServicesMonitor.ServiceStatus.DOWN.toString(); + String messagingStatus = ServicesMonitor.ServiceStatus.DOWN.toString(); + + @Override + protected Void doInBackground() throws Exception { + caseDatabaseServerStatus = getServiceStatus(ServicesMonitor.Service.REMOTE_CASE_DATABASE); + keywordSearchServiceStatus = getServiceStatus(ServicesMonitor.Service.REMOTE_KEYWORD_SEARCH); + messagingStatus = getServiceStatus(ServicesMonitor.Service.MESSAGING); + return null; + } + + /** + * Gets a status string for a given service. + * + * @param service The service to test. + * + * @return The status string. + */ + private String getServiceStatus(ServicesMonitor.Service service) { + String serviceStatus = NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Unknown"); + try { + ServicesMonitor servicesMonitor = ServicesMonitor.getInstance(); + serviceStatus = servicesMonitor.getServiceStatus(service.toString()); + if (serviceStatus.compareTo(ServicesMonitor.ServiceStatus.UP.toString()) == 0) { + serviceStatus = NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Up"); + } else { + serviceStatus = NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Down"); + } + } catch (ServicesMonitor.ServicesMonitorException ex) { + SYS_LOGGER.log(Level.SEVERE, String.format("Dashboard error getting service status for %s", service), ex); + } + return serviceStatus; + } + + @Override + protected void done() { + tbServicesStatusMessage.setText(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.tbServicesStatusMessage.Message", caseDatabaseServerStatus, keywordSearchServiceStatus, keywordSearchServiceStatus, messagingStatus)); + String upStatus = NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Up"); + if (caseDatabaseServerStatus.compareTo(upStatus) != 0 + || keywordSearchServiceStatus.compareTo(upStatus) != 0 + || messagingStatus.compareTo(upStatus) != 0) { + tbServicesStatusMessage.setForeground(Color.RED); + } else { + tbServicesStatusMessage.setForeground(Color.BLACK); + } + } + + }.execute(); + } + + /** + * Sets up the JTable that presents a view of the system-wide pending jobs + * queue. + */ + private void initPendingJobsTable() { + /* + * Remove some of the jobs table model columns from the JTable. This + * does not remove the columns from the model, just from this table. + */ + pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.HOST_NAME.getColumnHeader())); + pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.STARTED_TIME.getColumnHeader())); + pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.COMPLETED_TIME.getColumnHeader())); + pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.STAGE.getColumnHeader())); + pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.STAGE_TIME.getColumnHeader())); + pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader())); + pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.IS_LOCAL_JOB.getColumnHeader())); + pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.STATUS.getColumnHeader())); + pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader())); + + /* + * Set up a column to display the cases associated with the jobs. + */ + TableColumn column; + column = pendingTable.getColumn(JobsTableModelColumns.CASE.getColumnHeader()); + column.setMinWidth(GENERIC_COL_MIN_WIDTH); + column.setMaxWidth(GENERIC_COL_MAX_WIDTH); + column.setPreferredWidth(PENDING_TABLE_COL_PREFERRED_WIDTH); + column.setWidth(PENDING_TABLE_COL_PREFERRED_WIDTH); + + /* + * Set up a column to display the image folders associated with the + * jobs. + */ + column = pendingTable.getColumn(JobsTableModelColumns.DATA_SOURCE.getColumnHeader()); + column.setMaxWidth(GENERIC_COL_MAX_WIDTH); + column.setPreferredWidth(PENDING_TABLE_COL_PREFERRED_WIDTH); + column.setWidth(PENDING_TABLE_COL_PREFERRED_WIDTH); + + /* + * Set up a column to display the create times of the jobs. + */ + column = pendingTable.getColumn(JobsTableModelColumns.CREATED_TIME.getColumnHeader()); + column.setCellRenderer(new LongDateCellRenderer()); + column.setMinWidth(TIME_COL_MIN_WIDTH); + column.setMaxWidth(TIME_COL_MAX_WIDTH); + column.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); + column.setWidth(TIME_COL_PREFERRED_WIDTH); + + /** + * Prevent sorting when a column header is clicked. + */ + pendingTable.setAutoCreateRowSorter(false); + + /* + * Create a row selection listener to enable/disable the prioritize + * folder and prioritize case buttons. + */ + pendingTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> { + if (e.getValueIsAdjusting()) { + return; + } + int row = pendingTable.getSelectedRow(); + enablePendingTableButtons((row >= 0) && (row < pendingTable.getRowCount())); + }); + + /* + * Save the background color of the table so it can be restored on + * resume, after being grayed out on pause. Note the assumption that all + * of the tables use the same background color. + */ + pendingTableBackground = pendingTable.getBackground(); + pendingTablelForeground = pendingTable.getForeground(); + } + + /** + * Sets up the JTable that presents a view of the system-wide running jobs + * list. + */ + private void initRunningJobsTable() { + /* + * Remove some of the jobs table model columns from the JTable. This + * does not remove the columns from the model, just from this table. + */ + runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.CREATED_TIME.getColumnHeader())); + runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.STARTED_TIME.getColumnHeader())); + runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.COMPLETED_TIME.getColumnHeader())); + runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.STATUS.getColumnHeader())); + runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader())); + runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.IS_LOCAL_JOB.getColumnHeader())); + runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader())); + + /* + * Set up a column to display the cases associated with the jobs. + */ + TableColumn column; + column = runningTable.getColumn(JobsTableModelColumns.CASE.getColumnHeader()); + column.setMinWidth(GENERIC_COL_MIN_WIDTH); + column.setMaxWidth(GENERIC_COL_MAX_WIDTH); + column.setPreferredWidth(RUNNING_TABLE_COL_PREFERRED_WIDTH); + column.setWidth(RUNNING_TABLE_COL_PREFERRED_WIDTH); + + /* + * Set up a column to display the image folders associated with the + * jobs. + */ + column = runningTable.getColumn(JobsTableModelColumns.DATA_SOURCE.getColumnHeader()); + column.setMinWidth(GENERIC_COL_MIN_WIDTH); + column.setMaxWidth(GENERIC_COL_MAX_WIDTH); + column.setPreferredWidth(RUNNING_TABLE_COL_PREFERRED_WIDTH); + column.setWidth(RUNNING_TABLE_COL_PREFERRED_WIDTH); + + /* + * Set up a column to display the host names of the cluster nodes + * processing the jobs. + */ + column = runningTable.getColumn(JobsTableModelColumns.HOST_NAME.getColumnHeader()); + column.setMinWidth(NAME_COL_MIN_WIDTH); + column.setMaxWidth(NAME_COL_MAX_WIDTH); + column.setPreferredWidth(NAME_COL_PREFERRED_WIDTH); + column.setWidth(NAME_COL_PREFERRED_WIDTH); + + /* + * Set up a column to display the ingest activities associated with the + * jobs. + */ + column = runningTable.getColumn(JobsTableModelColumns.STAGE.getColumnHeader()); + column.setMinWidth(ACTIVITY_COL_MIN_WIDTH); + column.setMaxWidth(ACTIVITY_COL_MAX_WIDTH); + column.setPreferredWidth(ACTIVITY_COL_PREFERRED_WIDTH); + column.setWidth(ACTIVITY_COL_PREFERRED_WIDTH); + + /* + * Set up a column to display the ingest activity times associated with + * the jobs. + */ + column = runningTable.getColumn(JobsTableModelColumns.STAGE_TIME.getColumnHeader()); + column.setCellRenderer(new DurationCellRenderer()); + column.setMinWidth(GENERIC_COL_MIN_WIDTH); + column.setMaxWidth(ACTIVITY_TIME_COL_MAX_WIDTH); + column.setPreferredWidth(ACTIVITY_TIME_COL_MIN_WIDTH); + column.setWidth(ACTIVITY_TIME_COL_MIN_WIDTH); + + /* + * Prevent sorting when a column header is clicked. + */ + runningTable.setAutoCreateRowSorter(false); + + /* + * Create a row selection listener to enable/disable the cancel current + * job, cancel current module, and show progress buttons. + */ + runningTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> { + if (e.getValueIsAdjusting()) { + return; + } + updateRunningTableButtonsBasedOnSelectedRow(); + }); + } + + private void updateRunningTableButtonsBasedOnSelectedRow() { + int row = runningTable.getSelectedRow(); + if (row >= 0 && row < runningTable.getRowCount()) { + if ((boolean) runningTableModel.getValueAt(row, JobsTableModelColumns.IS_LOCAL_JOB.ordinal())) { + enableRunningTableButtons(true); + return; + } + } + enableRunningTableButtons(false); + } + + /** + * Sets up the JTable that presents a view of the system-wide competed jobs + * list. + */ + private void initCompletedJobsTable() { + /* + * Remove some of the jobs table model columns from the JTable. This + * does not remove the columns from the model, just from this table. + */ + completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.STARTED_TIME.getColumnHeader())); + completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.STAGE.getColumnHeader())); + completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.STAGE_TIME.getColumnHeader())); + completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.IS_LOCAL_JOB.getColumnHeader())); + completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.HOST_NAME.getColumnHeader())); + completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader())); + completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader())); + + /* + * Set up a column to display the cases associated with the jobs. + */ + TableColumn column; + column = completedTable.getColumn(JobsTableModelColumns.CASE.getColumnHeader()); + column.setMinWidth(COMPLETED_TIME_COL_MIN_WIDTH); + column.setMaxWidth(COMPLETED_TIME_COL_MAX_WIDTH); + column.setPreferredWidth(COMPLETED_TIME_COL_PREFERRED_WIDTH); + column.setWidth(COMPLETED_TIME_COL_PREFERRED_WIDTH); + + /* + * Set up a column to display the image folders associated with the + * jobs. + */ + column = completedTable.getColumn(JobsTableModelColumns.DATA_SOURCE.getColumnHeader()); + column.setMinWidth(COMPLETED_TIME_COL_MIN_WIDTH); + column.setMaxWidth(COMPLETED_TIME_COL_MAX_WIDTH); + column.setPreferredWidth(COMPLETED_TIME_COL_PREFERRED_WIDTH); + column.setWidth(COMPLETED_TIME_COL_PREFERRED_WIDTH); + + /* + * Set up a column to display the create times of the jobs. + */ + column = completedTable.getColumn(JobsTableModelColumns.CREATED_TIME.getColumnHeader()); + column.setCellRenderer(new LongDateCellRenderer()); + column.setMinWidth(TIME_COL_MIN_WIDTH); + column.setMaxWidth(TIME_COL_MAX_WIDTH); + column.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); + column.setWidth(TIME_COL_PREFERRED_WIDTH); + + /* + * Set up a column to display the completed times of the jobs. + */ + column = completedTable.getColumn(JobsTableModelColumns.COMPLETED_TIME.getColumnHeader()); + column.setCellRenderer(new LongDateCellRenderer()); + column.setMinWidth(TIME_COL_MIN_WIDTH); + column.setMaxWidth(TIME_COL_MAX_WIDTH); + column.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); + column.setWidth(TIME_COL_PREFERRED_WIDTH); + + /* + * Set up a column to display the statuses of the jobs, with a cell + * renderer that will choose an icon to represent the job status. + */ + column = completedTable.getColumn(JobsTableModelColumns.STATUS.getColumnHeader()); + column.setCellRenderer(new CaseStatusIconCellRenderer()); + column.setMinWidth(STATUS_COL_MIN_WIDTH); + column.setMaxWidth(STATUS_COL_MAX_WIDTH); + column.setPreferredWidth(STATUS_COL_PREFERRED_WIDTH); + column.setWidth(STATUS_COL_PREFERRED_WIDTH); + + /* + * Prevent sorting when a column header is clicked. + */ + completedTable.setAutoCreateRowSorter(false); + + /* + * Create a row selection listener to enable/disable the delete case and + * show log buttons. + */ + completedTable.getSelectionModel() + .addListSelectionListener((ListSelectionEvent e) -> { + if (e.getValueIsAdjusting()) { + return; + } + int row = completedTable.getSelectedRow(); + boolean enabled = row >= 0 && row < completedTable.getRowCount(); + bnDeleteCase.setEnabled(enabled); + bnShowCaseLog.setEnabled(enabled); + bnReprocessJob.setEnabled(enabled); + }); + } + + /** + * Sets the initial state of the buttons on the panel. + */ + private void initButtons() { + bnOptions.setEnabled(true); + bnDeleteCase.setEnabled(false); + enablePendingTableButtons(false); + bnShowCaseLog.setEnabled(false); + bnReprocessJob.setEnabled(false); + bnPause.setText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.bnStart.text")); + bnPause.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.bnStart.toolTipText")); + bnPause.setEnabled(true); //initial label for bnPause is 'Start' and it's enabled for user to start the process + bnRefresh.setEnabled(false); //at initial stage, nothing to refresh + enableRunningTableButtons(false); + tbStatusMessage.setText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.bnStart.startMessage")); + } + + /** + * Enables or disables buttons related to the running jobs table. + * + * @param enable Enable/disable the buttons. + */ + private void enableRunningTableButtons(Boolean enable) { + bnCancelJob.setEnabled(enable); + bnCancelModule.setEnabled(enable); + bnShowProgress.setEnabled(enable); + } + + /** + * Enables or disables buttons related to pending jobs table. + * + * @param enable Enable/disable the buttons. + */ + private void enablePendingTableButtons(Boolean enable) { + bnPrioritizeCase.setEnabled(enable); + bnPrioritizeJob.setEnabled(enable); + } + + /** + * Starts up the auto ingest manager and adds this panel as an observer, + * subscribes to services monitor events and starts a task to populate the + * auto ingest job tables. The Refresh and Pause buttons are enabled. + */ + private void startUp() { + + /* + * Starts up the auto ingest manager (AIM). + */ + try { + manager.startUp(); + autoIngestStarted = true; + } catch (AutoIngestManager.AutoIngestManagerStartupException ex) { + SYS_LOGGER.log(Level.SEVERE, "Dashboard error starting up auto ingest", ex); + tbStatusMessage.setText(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.AutoIngestStartupError")); + manager = null; + + JOptionPane.showMessageDialog(this, + NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.AutoIngestStartupFailed.Message"), + NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.AutoIngestStartupFailed.Title"), + JOptionPane.ERROR_MESSAGE); + bnOptions.setEnabled(true); + + /* + * If the AIM cannot be started, there is nothing more to do. + */ + return; + } + + /* + * Subscribe to services monitor events. + */ + ServicesMonitor.getInstance().addSubscriber((PropertyChangeEvent evt) -> { + setServicesStatusMessage(); + }); + + /* + * Register with the AIM as an observer. + */ + manager.addObserver(this); + + /* + * Populate the pending, running, and completed auto ingest job tables. + */ + updateExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(UPDATE_TASKS_THREAD_NAME).build()); + updateExecutor.submit(new UpdateAllJobsTablesTask()); + manager.scanInputDirsNow(); + + //bnPause.setEnabled(true); + bnPause.setText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.bnPause.text")); + bnPause.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.bnPause.toolTipText")); + bnRefresh.setEnabled(true); + bnOptions.setEnabled(false); + + tbStatusMessage.setText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.bnPause.running")); + } + + /** + * Shuts down auto ingest by shutting down the auto ingest manager and doing + * an application exit. + */ + public void shutdown() { + /* + * Confirm that the user wants to proceed, letting him or her no that if + * there is a currently running job it will be cancelled. TODO (RC): If + * a wait cursor is provided, this could perhaps be made conditional on + * a running job check again. Or the simple check in isLocalJobRunning + * could be used. Was this previously used and I removed it thinking it + * was grabbing the monitor? + */ + Object[] options = { + NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.OK"), + NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.Cancel")}; + int reply = JOptionPane.OK_OPTION; + + if (null != manager && IngestManager.getInstance().isIngestRunning()) { + reply = JOptionPane.showOptionDialog(this, + NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.ExitConsequences"), + NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.ConfirmExitHeader"), + JOptionPane.DEFAULT_OPTION, + JOptionPane.WARNING_MESSAGE, + null, + options, + options[JOptionPane.NO_OPTION]); + } + if (reply == JOptionPane.OK_OPTION) { + /* + * Provide user feedback. Call setCursor on this to ensure it + * appears (if there is time to see it). + */ + this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + tbStatusMessage.setText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.ExitingStatus")); + + /* + * Shut down the table refresh task executor. + */ + if (null != updateExecutor) { + updateExecutor.shutdownNow(); + } + + /* + * Stop observing the auto ingest manager (AIM). + */ + if (null != manager) { + manager.deleteObserver(this); + } + + /* + * Shut down the AIM and close. + */ + new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + if (null != manager) { + manager.shutDown(); + } + return null; + } + + @Override + protected void done() { + AutoIngestControlPanel.this.setCursor(Cursor.getDefaultCursor()); + LifecycleManager.getDefault().exit(); + } + }.execute(); + } + } + + /** + * @inheritDoc + */ + @NbBundle.Messages({ + "AutoIngestControlPanel.bnPause.paused=Paused", + "AutoIngestControlPanel.PauseDueToDatabaseServiceDown=Paused, unable to communicate with case database service.", + "AutoIngestControlPanel.PauseDueToKeywordSearchServiceDown=Paused, unable to communicate with keyword search service.", + "AutoIngestControlPanel.PauseDueToCoordinationServiceDown=Paused, unable to communicate with coordination service.", + "AutoIngestControlPanel.PauseDueToWriteStateFilesFailure=Paused, unable to write to shared images or cases location.", + "AutoIngestControlPanel.PauseDueToSharedConfigError=Paused, unable to update shared configuration.", + "AutoIngestControlPanel.PauseDueToIngestJobStartFailure=Paused, unable to start ingest job processing.", + "AutoIngestControlPanel.PauseDueToFileExporterError=Paused, unable to load File Exporter settings.", + "AutoIngestControlPanel.bnPause.running=Running", + "AutoIngestControlPanel.bnStart.startMessage=Waiting to start", + "AutoIngestControlPanel.bnStart.text=Start", + "AutoIngestControlPanel.bnStart.toolTipText=Start processing auto ingest jobs" + }) + @Override + public void update(Observable o, Object arg) { + + if (arg instanceof AutoIngestManager.Event) { + switch ((AutoIngestManager.Event) arg) { + case INPUT_SCAN_COMPLETED: + case JOB_STARTED: + case JOB_COMPLETED: + case CASE_DELETED: + updateExecutor.submit(new UpdateAllJobsTablesTask()); + break; + case PAUSED_BY_REQUEST: + EventQueue.invokeLater(() -> { + tbStatusMessage.setText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPause.paused")); + bnOptions.setEnabled(true); + bnRefresh.setEnabled(false); + isPaused = true; + }); + break; + case PAUSED_FOR_SYSTEM_ERROR: + EventQueue.invokeLater(() -> { + tbStatusMessage.setText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.PauseDueToSystemError")); + bnOptions.setEnabled(true); + bnRefresh.setEnabled(false); + pause(false); + isPaused = true; + setServicesStatusMessage(); + }); + break; + case RESUMED: + EventQueue.invokeLater(() -> { + tbStatusMessage.setText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPause.running")); + }); + break; + case CASE_PRIORITIZED: + updateExecutor.submit(new UpdatePendingJobsTableTask()); + break; + case JOB_STATUS_UPDATED: + updateExecutor.submit(new UpdateRunningJobsTablesTask()); + break; + default: + break; + } + } + } + + /** + * Requests a pause of auto ingest processing by the auto ingest manager and + * handles updates to the components that implement the pause and resume + * feature. Note that this feature is needed to get around restrictions on + * changing ingest module selections and settings while an ingest job is + * running, and that the auto ingest manager will not actually pause until + * the current auto ingest job completes. + * + * @param buttonClicked Is this pause request in response to a user gesture + * or a nofification from the auto ingest manager + * (AIM)? + */ + private void pause(boolean buttonClicked) { + /** + * Gray out the cells in the pending table to give a visual indicator of + * the pausing/paused state. + */ + pendingTable.setBackground(Color.LIGHT_GRAY); + pendingTable.setForeground(Color.DARK_GRAY); + + /** + * Change the pause button text and tool tip to make it a resume button. + */ + bnPause.setText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.bnResume.text")); + bnPause.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.bnPause.toolTipTextResume")); + + if (buttonClicked) { + /** + * Ask the auto ingest manager to pause when it completes the + * currently running job, if any. + */ + manager.pause(); + bnRefresh.setEnabled(false); + } + } + + /** + * Requests a resume of auto ingest processing by the auto ingest manager + * and handles updates to the components that implement the pause and resume + * feature. Note that this feature is needed to get around restrictions on + * changing ingest module selections and settings while an ingest job is + * running, and that the auto ingest manager will not actually pause until + * the current auto ingest job completes. + */ + private void resume() { + /** + * Change the resume button text and tool tip to make it a pause button. + */ + bnOptions.setEnabled(false); + bnPause.setText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.bnPause.text")); + bnPause.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.bnPause.toolTipText")); + tbStatusMessage.setText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.bnPause.running")); + bnRefresh.setEnabled(true); + + /** + * Remove the graying out of the pending table. + */ + pendingTable.setBackground(pendingTableBackground); + pendingTable.setForeground(pendingTablelForeground); + + /** + * Ask the auto ingest manager to resume processing. + */ + manager.resume(); + } + + /** + * A runnable task that gets the pending auto ingest jobs list from the auto + * ingest manager and queues a components refresh task for execution in the + * EDT. + */ + private class UpdatePendingJobsTableTask implements Runnable { + + /** + * @inheritDoc + */ + @Override + public void run() { + List pendingJobs = new ArrayList<>(); + manager.getJobs(pendingJobs, null, null); + EventQueue.invokeLater(new RefreshComponentsTask(pendingJobs, null, null)); + } + } + + /** + * A runnable task that gets the running auto ingest jobs list from the auto + * ingest manager and queues a components refresh task for execution in the + * EDT. + */ + private class UpdateRunningJobsTablesTask implements Runnable { + + /** + * @inheritDoc + */ + @Override + public void run() { + List runningJobs = new ArrayList<>(); + manager.getJobs(null, runningJobs, null); + EventQueue.invokeLater(new RefreshComponentsTask(null, runningJobs, null)); + } + } + + /** + * A runnable task that gets the pending, running and completed auto ingest + * jobs lists from the auto ingest manager and queues a components refresh + * task for execution in the EDT. Note that this task is frequently used + * when only the pending and updated lists definitely need to be updated. + * This is because the cost of updating the running jobs list is both very + * small and it is beneficial to keep running job status up to date if there + * is a running job. + */ + private class UpdateAllJobsTablesTask implements Runnable { + + /** + * @inheritDoc + */ + @Override + public void run() { + List pendingJobs = new ArrayList<>(); + List runningJobs = new ArrayList<>(); + List completedJobs = new ArrayList<>(); + manager.getJobs(pendingJobs, runningJobs, completedJobs); + // Sort the completed jobs list by completed date + Collections.sort(completedJobs, new AutoIngestJob.ReverseDateCompletedComparator()); + EventQueue.invokeLater(new RefreshComponentsTask(pendingJobs, runningJobs, completedJobs)); + } + } + + /** + * A runnable task that refreshes the components on this panel to reflect + * the current state of one or more auto ingest job lists obtained from the + * auto ingest manager. + */ + private class RefreshComponentsTask implements Runnable { + + private final List pendingJobs; + private final List runningJobs; + private final List completedJobs; + + /** + * Constructs a runnable task that refreshes the components on this + * panel to reflect the current state of the auto ingest jobs. + * + * @param pendingJobs A list of pending jobs, may be null if the + * pending jobs are unchanged. + * @param runningJobs A list of running jobs, may be null if the + * running jobs are unchanged. + * @param completedJobs A list of completed jobs, may be null if the + * completed jobs are unchanged. + */ + RefreshComponentsTask(List pendingJobs, List runningJobs, List completedJobs) { + this.pendingJobs = pendingJobs; + this.runningJobs = runningJobs; + this.completedJobs = completedJobs; + } + + /** + * @inheritDoc + */ + @Override + public void run() { + /* + * NOTE: There is a problem with our approach of preserving table + * row selections - what if the number of rows has changed as result + * of calling refreshTable(). Then it is possible for what used to + * be (for example) row 1 to now be in some other row or be removed + * from the table. This code will re-set the selection back to what + * it used to be before calling refreshTable(), i.e. row 1 + */ + + if (null != pendingJobs) { + Path currentRow = getSelectedEntry(pendingTable, pendingTableModel); + refreshTable(pendingJobs, pendingTableModel, null); + setSelectedEntry(pendingTable, pendingTableModel, currentRow); + } + + if (null != runningJobs) { + if (!isLocalJobRunning()) { + enableRunningTableButtons(false); + } else { + updateRunningTableButtonsBasedOnSelectedRow(); + } + Path currentRow = getSelectedEntry(runningTable, runningTableModel); + refreshTable(runningJobs, runningTableModel, null); + setSelectedEntry(runningTable, runningTableModel, currentRow); + } + + if (null != completedJobs) { + Path currentRow = getSelectedEntry(completedTable, completedTableModel); + refreshTable(completedJobs, completedTableModel, null); + setSelectedEntry(completedTable, completedTableModel, currentRow); + } + } + + /** + * Checks whether there is a job that is running on local AIN. + * + * @return true is local job is found, false otherwise. + */ + private boolean isLocalJobRunning() { + for (AutoIngestJob job : runningJobs) { + if (isLocalJob(job)) { + return true; + } + } + return false; + } + + /** + * Checks whether or not an automated ingest job is local to this node. + * + * @param job The job. + * + * @return True or fale. + */ + private boolean isLocalJob(AutoIngestJob job) { + return job.getNodeName().equals(LOCAL_HOST_NAME); + } + + /** + * Get a path representing the current selection on the table passed in. + * If there is no selection, return null. + * + * @param table The table to get + * @param tableModel The tableModel of the table to get + * + * @return a path representing the current selection + */ + Path getSelectedEntry(JTable table, DefaultTableModel tableModel) { + try { + int currentlySelectedRow = table.getSelectedRow(); + if (currentlySelectedRow >= 0 && currentlySelectedRow < table.getRowCount()) { + return Paths.get(tableModel.getValueAt(currentlySelectedRow, JobsTableModelColumns.CASE.ordinal()).toString(), + tableModel.getValueAt(currentlySelectedRow, JobsTableModelColumns.DATA_SOURCE.ordinal()).toString()); + } + } catch (Exception ignored) { + return null; + } + return null; + } + + /** + * Set the selection on the table to the passed-in path's item, if that + * item exists in the table. If it does not, clears the table selection. + * + * @param table The table to set + * @param tableModel The tableModel of the table to set + * @param path The path of the item to set + */ + void setSelectedEntry(JTable table, DefaultTableModel tableModel, Path path) { + if (path != null) { + try { + for (int row = 0; row < table.getRowCount(); ++row) { + Path temp = Paths.get(tableModel.getValueAt(row, JobsTableModelColumns.CASE.ordinal()).toString(), + tableModel.getValueAt(row, JobsTableModelColumns.DATA_SOURCE.ordinal()).toString()); + if (temp.compareTo(path) == 0) { // found it + table.setRowSelectionInterval(row, row); + return; + } + } + } catch (Exception ignored) { + table.clearSelection(); + } + } + table.clearSelection(); + } + } + + /** + * Reloads the table model for an auto ingest jobs table, refreshing the + * JTable that uses the model. + * + * @param jobs The list of auto ingest jobs. + * @param tableModel The table model. + * @param comparator An optional comparator (may be null) for sorting the + * table model. + */ + private void refreshTable(List jobs, DefaultTableModel tableModel, Comparator comparator) { + try { + if (comparator != null) { + jobs.sort(comparator); + } + tableModel.setRowCount(0); + for (AutoIngestJob job : jobs) { + AutoIngestJob.StageDetails status = job.getStageDetails(); + tableModel.addRow(new Object[]{ + job.getManifest().getCaseName(), // CASE + job.getManifest().getDataSourcePath().getFileName(), // DATA_SOURCE + job.getNodeName(), // HOST_NAME + job.getManifest().getDateFileCreated(), // CREATED_TIME + job.getStageStartDate(), // STARTED_TIME + job.getCompletedDate(), // COMPLETED_TIME + status.getDescription(), // ACTIVITY + job.hasErrors(), // STATUS + ((Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime())), // ACTIVITY_TIME + job.getCaseDirectoryPath(), // CASE_DIRECTORY_PATH + job.getNodeName().equals(LOCAL_HOST_NAME), // IS_LOCAL_JOB + job.getManifest().getFilePath()}); // MANIFEST_FILE_PATH + } + } catch (Exception ex) { + SYS_LOGGER.log(Level.SEVERE, "Dashboard error refreshing table", ex); + } + } + + /** + * Get the current lists of jobs and update the UI. + */ + private void refreshTables(){ + JobsSnapshot jobsSnapshot = manager.getCurrentJobsSnapshot(); + refreshTable(jobsSnapshot.getCompletedJobs(), completedTableModel, null); + refreshTable(jobsSnapshot.getPendingJobs(), pendingTableModel, null); + refreshTable(jobsSnapshot.getRunningJobs(), runningTableModel, null); + } + + /** + * 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. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + pendingScrollPane = new javax.swing.JScrollPane(); + pendingTable = new javax.swing.JTable(); + runningScrollPane = new javax.swing.JScrollPane(); + runningTable = new javax.swing.JTable(); + completedScrollPane = new javax.swing.JScrollPane(); + completedTable = new javax.swing.JTable(); + bnCancelJob = new javax.swing.JButton(); + bnDeleteCase = new javax.swing.JButton(); + lbPending = new javax.swing.JLabel(); + lbRunning = new javax.swing.JLabel(); + lbCompleted = new javax.swing.JLabel(); + bnRefresh = new javax.swing.JButton(); + bnCancelModule = new javax.swing.JButton(); + bnExit = new javax.swing.JButton(); + bnOptions = new javax.swing.JButton(); + bnShowProgress = new javax.swing.JButton(); + bnPause = new javax.swing.JButton(); + bnPrioritizeCase = new javax.swing.JButton(); + bnShowCaseLog = new javax.swing.JButton(); + tbStatusMessage = new javax.swing.JTextField(); + lbStatus = new javax.swing.JLabel(); + bnPrioritizeJob = new javax.swing.JButton(); + lbServicesStatus = new javax.swing.JLabel(); + tbServicesStatusMessage = new javax.swing.JTextField(); + bnOpenLogDir = new javax.swing.JButton(); + bnReprocessJob = new javax.swing.JButton(); + + pendingTable.setModel(pendingTableModel); + pendingTable.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.pendingTable.toolTipText")); // NOI18N + pendingTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS); + pendingTable.setRowHeight(20); + pendingTable.setSelectionModel(new DefaultListSelectionModel() { + private static final long serialVersionUID = 1L; + @Override + public void setSelectionInterval(int index0, int index1) { + if (index0 == pendingTable.getSelectedRow()) { + pendingTable.clearSelection(); + } else { + super.setSelectionInterval(index0, index1); + } + } + }); + pendingTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); + pendingScrollPane.setViewportView(pendingTable); + + runningTable.setModel(runningTableModel); + runningTable.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.runningTable.toolTipText")); // NOI18N + runningTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS); + runningTable.setRowHeight(20); + runningTable.setSelectionModel(new DefaultListSelectionModel() { + private static final long serialVersionUID = 1L; + @Override + public void setSelectionInterval(int index0, int index1) { + if (index0 == runningTable.getSelectedRow()) { + runningTable.clearSelection(); + } else { + super.setSelectionInterval(index0, index1); + } + } + }); + runningTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); + runningScrollPane.setViewportView(runningTable); + + completedTable.setModel(completedTableModel); + completedTable.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.completedTable.toolTipText")); // NOI18N + completedTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS); + completedTable.setRowHeight(20); + completedTable.setSelectionModel(new DefaultListSelectionModel() { + private static final long serialVersionUID = 1L; + @Override + public void setSelectionInterval(int index0, int index1) { + if (index0 == completedTable.getSelectedRow()) { + completedTable.clearSelection(); + } else { + super.setSelectionInterval(index0, index1); + } + } + }); + completedTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); + completedScrollPane.setViewportView(completedTable); + + org.openide.awt.Mnemonics.setLocalizedText(bnCancelJob, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnCancelJob.text")); // NOI18N + bnCancelJob.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnCancelJob.toolTipText")); // NOI18N + bnCancelJob.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnCancelJobActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(bnDeleteCase, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnDeleteCase.text")); // NOI18N + bnDeleteCase.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnDeleteCase.toolTipText")); // NOI18N + bnDeleteCase.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnDeleteCaseActionPerformed(evt); + } + }); + + lbPending.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(lbPending, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.lbPending.text")); // NOI18N + + lbRunning.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(lbRunning, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.lbRunning.text")); // NOI18N + + lbCompleted.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(lbCompleted, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.lbCompleted.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(bnRefresh, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnRefresh.text")); // NOI18N + bnRefresh.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnRefresh.toolTipText")); // NOI18N + bnRefresh.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnRefreshActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(bnCancelModule, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnCancelModule.text")); // NOI18N + bnCancelModule.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnCancelModule.toolTipText")); // NOI18N + bnCancelModule.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnCancelModuleActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(bnExit, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnExit.text")); // NOI18N + bnExit.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnExit.toolTipText")); // NOI18N + bnExit.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnExitActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(bnOptions, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnOptions.text")); // NOI18N + bnOptions.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnOptions.toolTipText")); // NOI18N + bnOptions.setEnabled(false); + bnOptions.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnOptionsActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(bnShowProgress, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnShowProgress.text")); // NOI18N + bnShowProgress.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnShowProgress.toolTipText")); // NOI18N + bnShowProgress.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnShowProgressActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(bnPause, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPause.text")); // NOI18N + bnPause.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPause.toolTipText")); // NOI18N + bnPause.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnPauseActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(bnPrioritizeCase, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPrioritizeCase.text")); // NOI18N + bnPrioritizeCase.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPrioritizeCase.toolTipText")); // NOI18N + bnPrioritizeCase.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnPrioritizeCaseActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(bnShowCaseLog, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnShowCaseLog.text")); // NOI18N + bnShowCaseLog.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnShowCaseLog.toolTipText")); // NOI18N + bnShowCaseLog.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnShowCaseLogActionPerformed(evt); + } + }); + + tbStatusMessage.setEditable(false); + tbStatusMessage.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N + tbStatusMessage.setText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.tbStatusMessage.text")); // NOI18N + tbStatusMessage.setBorder(null); + + lbStatus.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(lbStatus, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.lbStatus.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(bnPrioritizeJob, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPrioritizeJob.text")); // NOI18N + bnPrioritizeJob.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPrioritizeJob.toolTipText")); // NOI18N + bnPrioritizeJob.setActionCommand(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPrioritizeJob.actionCommand")); // NOI18N + bnPrioritizeJob.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnPrioritizeJobActionPerformed(evt); + } + }); + + lbServicesStatus.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(lbServicesStatus, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.lbServicesStatus.text")); // NOI18N + + tbServicesStatusMessage.setEditable(false); + tbServicesStatusMessage.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N + tbServicesStatusMessage.setText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.tbServicesStatusMessage.text")); // NOI18N + tbServicesStatusMessage.setBorder(null); + + org.openide.awt.Mnemonics.setLocalizedText(bnOpenLogDir, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnOpenLogDir.text")); // NOI18N + bnOpenLogDir.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnOpenLogDirActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(bnReprocessJob, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnReprocessJob.text")); // NOI18N + bnReprocessJob.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnReprocessJobActionPerformed(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() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lbPending, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(pendingScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 920, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(bnPrioritizeCase, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(bnPrioritizeJob, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(bnPause) + .addGap(18, 18, 18) + .addComponent(bnRefresh, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addComponent(bnOptions) + .addGap(18, 18, 18) + .addComponent(bnOpenLogDir) + .addGap(18, 18, 18) + .addComponent(bnExit, javax.swing.GroupLayout.PREFERRED_SIZE, 94, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(runningScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 920, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(completedScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 920, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(bnCancelJob, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE) + .addComponent(bnShowProgress, javax.swing.GroupLayout.DEFAULT_SIZE, 116, Short.MAX_VALUE) + .addComponent(bnCancelModule, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE) + .addComponent(bnDeleteCase, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE) + .addComponent(bnShowCaseLog, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(bnReprocessJob, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addGroup(layout.createSequentialGroup() + .addComponent(lbStatus) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(tbStatusMessage, javax.swing.GroupLayout.PREFERRED_SIZE, 861, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(lbCompleted) + .addComponent(lbRunning) + .addGroup(layout.createSequentialGroup() + .addComponent(lbServicesStatus) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(tbServicesStatusMessage, javax.swing.GroupLayout.PREFERRED_SIZE, 861, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGap(0, 0, Short.MAX_VALUE))) + .addContainerGap()) + ); + + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {bnCancelJob, bnCancelModule, bnDeleteCase, bnExit, bnOpenLogDir, bnOptions, bnPause, bnRefresh, bnShowProgress}); + + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lbStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(tbStatusMessage, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lbServicesStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(tbServicesStatusMessage, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lbPending, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(pendingScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addGap(82, 82, 82) + .addComponent(bnPrioritizeCase) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnPrioritizeJob))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lbRunning) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(34, 34, 34) + .addComponent(bnShowProgress) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnCancelJob) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnCancelModule)) + .addGroup(layout.createSequentialGroup() + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(runningScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(68, 68, 68) + .addComponent(bnReprocessJob) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnDeleteCase) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnShowCaseLog)) + .addGroup(layout.createSequentialGroup() + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lbCompleted) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(completedScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 179, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(bnExit) + .addComponent(bnOpenLogDir)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(bnPause) + .addComponent(bnRefresh) + .addComponent(bnOptions))))) + .addContainerGap()) + ); + + layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {bnCancelJob, bnCancelModule, bnDeleteCase, bnExit, bnOpenLogDir, bnOptions, bnRefresh, bnShowProgress}); + + }// //GEN-END:initComponents + + /** + * Handles a click on the refresh button. Requests an immediate scan of the + * input folders for new jobs and queues a refresh of all three of the jobs + * tables. + * + * @param evt - The button click event. + */ + private void bnRefreshActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnRefreshActionPerformed + this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + manager.scanInputDirsAndWait(); + refreshTables(); + this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + }//GEN-LAST:event_bnRefreshActionPerformed + + /** + * Handles a click on the delete case button. If an entry is selected that + * can be deleted, pops up a confirmation dialog. Upon confirmation, asks + * AutoIngestManager to delete the entry and asks for an updated view. + * + * @param evt The button click event. + */ + private void bnDeleteCaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnDeleteCaseActionPerformed + if (completedTableModel.getRowCount() < 0 || completedTable.getSelectedRow() < 0) { + return; + } + + String caseName = (String) completedTable.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal()); + Object[] options = { + org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.Delete"), + org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.DoNotDelete") + }; + Object[] msgContent = {org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.DeleteAreYouSure") + "\"" + caseName + "\"?"}; + int reply = JOptionPane.showOptionDialog(this, + msgContent, + org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.ConfirmDeletionHeader"), + JOptionPane.DEFAULT_OPTION, + JOptionPane.WARNING_MESSAGE, + null, + options, + options[JOptionPane.NO_OPTION]); + if (reply == JOptionPane.YES_OPTION) { + bnDeleteCase.setEnabled(false); + bnShowCaseLog.setEnabled(false); + if (completedTableModel.getRowCount() > 0 && completedTable.getSelectedRow() >= 0) { + Path caseDirectoryPath = (Path) completedTableModel.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal()); + completedTable.clearSelection(); + this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + CaseDeletionResult result = manager.deleteCase(caseName, caseDirectoryPath); + refreshTables(); + this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + if (CaseDeletionResult.FAILED == result) { + JOptionPane.showMessageDialog(this, + String.format("Could not delete case %s. It may be in in use.", caseName), + org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.DeletionFailed"), + JOptionPane.INFORMATION_MESSAGE); + } else if (CaseDeletionResult.PARTIALLY_DELETED == result) { + JOptionPane.showMessageDialog(this, + String.format("Could not delete case %s. See system log for details.", caseName), + org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.DeletionFailed"), + JOptionPane.INFORMATION_MESSAGE); + } + } + } + }//GEN-LAST:event_bnDeleteCaseActionPerformed + + /** + * Handles a click on the cancel auto ingest job button. Cancels the + * selected job. + * + * @param evt The button click event. + */ + private void bnCancelJobActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnCancelJobActionPerformed + Object[] options = { + org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.CancelJob"), + org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.DoNotCancelJob")}; + int reply = JOptionPane.showOptionDialog(this, + NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.CancelJobAreYouSure"), + NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.ConfirmCancellationHeader"), + JOptionPane.DEFAULT_OPTION, + JOptionPane.WARNING_MESSAGE, + null, + options, + options[1]); + if (reply == 0) { + /* + * Call setCursor on this to ensure it appears (if there is time to + * see it). + */ + this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + manager.cancelCurrentJob(); + refreshTables(); + this.setCursor(Cursor.getDefaultCursor()); + } + }//GEN-LAST:event_bnCancelJobActionPerformed + + /** + * Handles a click on the show auto ingest job progress button. Displays an + * ingest job progress panel. + * + * @param evt The button click event. + */ + private void bnShowProgressActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnShowProgressActionPerformed + IngestProgressSnapshotDialog dialog = new IngestProgressSnapshotDialog(this.getTopLevelAncestor(), true); + }//GEN-LAST:event_bnShowProgressActionPerformed + + /** + * Handles a click on the pause/resume auto ingest job button. Sends a + * pause/resume request to the auto ingest manager. + * + * @param evt The button click event. + */ + private void bnPauseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPauseActionPerformed + + if (!autoIngestStarted) { + //put up a wait cursor during the start up operation + this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + startUp(); + + this.setCursor(null); + //done for startup + return; + } + if (!isPaused) { + tbStatusMessage.setText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.bnPause.pausing")); + pause(true); + } else { + resume(); + } + isPaused = !isPaused; + }//GEN-LAST:event_bnPauseActionPerformed + + /** + * Handles a click on the options button. Displays the options window. + * + * @param evt The button click event. + */ + private void bnOptionsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOptionsActionPerformed + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + OptionsDisplayer.getDefault().open(); + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + }//GEN-LAST:event_bnOptionsActionPerformed + + /** + * Handles a click on the cancel ingest module button. Cancels the currently + * running data source level ingest module for the selected job. + * + * @param evt The button click event. + */ + private void bnCancelModuleActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnCancelModuleActionPerformed + Object[] options = { + org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.CancelModule"), + org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.DoNotCancelModule")}; + int reply = JOptionPane.showOptionDialog(this, + NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.CancelModuleAreYouSure"), + NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.ConfirmCancellationHeader"), + JOptionPane.DEFAULT_OPTION, + JOptionPane.WARNING_MESSAGE, + null, + options, + options[1]); + if (reply == 0) { + /* + * Call setCursor on this to ensure it appears (if there is time to + * see it). + */ + this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + manager.cancelCurrentDataSourceLevelIngestModule(); + refreshTables(); + this.setCursor(Cursor.getDefaultCursor()); + } + }//GEN-LAST:event_bnCancelModuleActionPerformed + + /** + * Handles a click on the exit button. Shuts down auto ingest. + * + * @param evt The button click event. + */ + private void bnExitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnExitActionPerformed + shutdown(); + }//GEN-LAST:event_bnExitActionPerformed + + /** + * Handle a click on the prioritize case button. Requests prioritization of + * all of the auto ingest jobs for a case. + * + * @param evt The button click event. + */ + private void bnPrioritizeCaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPrioritizeCaseActionPerformed + if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { + this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + String caseName = (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal())).toString(); + manager.prioritizeCase(caseName); + refreshTables(); + pendingTable.clearSelection(); + enablePendingTableButtons(false); + AutoIngestControlPanel.this.setCursor(Cursor.getDefaultCursor()); + } + }//GEN-LAST:event_bnPrioritizeCaseActionPerformed + + /** + * Handles a click on the show log button. Displays the auto ingest job log + * for a case in NotePad. + * + * @param evt The button click event. + */ + private void bnShowCaseLogActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnShowCaseLogActionPerformed + try { + int selectedRow = completedTable.getSelectedRow(); + if (selectedRow != -1) { + Path caseDirectoryPath = (Path) completedTableModel.getValueAt(selectedRow, JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal()); + if (null != caseDirectoryPath) { + Path pathToLog = AutoIngestJobLogger.getLogPath(caseDirectoryPath); + if (pathToLog.toFile().exists()) { + Desktop.getDesktop().edit(pathToLog.toFile()); + } else { + JOptionPane.showMessageDialog(this, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.ShowLogFailed.Message"), + org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.ShowLogFailed.Title"), JOptionPane.ERROR_MESSAGE); + } + } else { + MessageNotifyUtil.Message.warn("The case directory for this job has been deleted."); + } + } + } catch (IOException ex) { + SYS_LOGGER.log(Level.SEVERE, "Dashboard error attempting to display case auto ingest log", ex); + Object[] options = {org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "DisplayLogDialog.okay")}; + JOptionPane.showOptionDialog(this, + org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "DisplayLogDialog.cannotFindLog"), + org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "DisplayLogDialog.unableToShowLogFile"), + JOptionPane.DEFAULT_OPTION, + JOptionPane.PLAIN_MESSAGE, + null, + options, + options[0]); + } + }//GEN-LAST:event_bnShowCaseLogActionPerformed + + private void bnPrioritizeJobActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPrioritizeJobActionPerformed + if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { + this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + Path manifestFilePath = (Path) (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal())); + manager.prioritizeJob(manifestFilePath); + refreshTables(); + pendingTable.clearSelection(); + enablePendingTableButtons(false); + AutoIngestControlPanel.this.setCursor(Cursor.getDefaultCursor()); + } + }//GEN-LAST:event_bnPrioritizeJobActionPerformed + + private void bnOpenLogDirActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOpenLogDirActionPerformed + Path logDirPath = Paths.get(PlatformUtil.getUserDirectory().getAbsolutePath(), "var", "log"); + File logDir = logDirPath.toFile(); + try { + Desktop.getDesktop().open(logDir); + } catch (IOException ex) { + DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message( + String.format("Unable to open log directory %s:\n%s", logDirPath, ex.getLocalizedMessage()), + NotifyDescriptor.ERROR_MESSAGE)); + } + }//GEN-LAST:event_bnOpenLogDirActionPerformed + + private void bnReprocessJobActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnReprocessJobActionPerformed + if (completedTableModel.getRowCount() < 0 || completedTable.getSelectedRow() < 0) { + return; + } + this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + Path manifestPath = (Path) completedTableModel.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal()); + manager.reprocessJob(manifestPath); + refreshTables(); + AutoIngestControlPanel.this.setCursor(Cursor.getDefaultCursor()); + }//GEN-LAST:event_bnReprocessJobActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton bnCancelJob; + private javax.swing.JButton bnCancelModule; + private javax.swing.JButton bnDeleteCase; + private javax.swing.JButton bnExit; + private javax.swing.JButton bnOpenLogDir; + private javax.swing.JButton bnOptions; + private javax.swing.JButton bnPause; + private javax.swing.JButton bnPrioritizeCase; + private javax.swing.JButton bnPrioritizeJob; + private javax.swing.JButton bnRefresh; + private javax.swing.JButton bnReprocessJob; + private javax.swing.JButton bnShowCaseLog; + private javax.swing.JButton bnShowProgress; + private javax.swing.JScrollPane completedScrollPane; + private javax.swing.JTable completedTable; + private javax.swing.JLabel lbCompleted; + private javax.swing.JLabel lbPending; + private javax.swing.JLabel lbRunning; + private javax.swing.JLabel lbServicesStatus; + private javax.swing.JLabel lbStatus; + private javax.swing.JScrollPane pendingScrollPane; + private javax.swing.JTable pendingTable; + private javax.swing.JScrollPane runningScrollPane; + private javax.swing.JTable runningTable; + private javax.swing.JTextField tbServicesStatusMessage; + private javax.swing.JTextField tbStatusMessage; + // End of variables declaration//GEN-END:variables + +} \ No newline at end of file diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form index b1d90f4479..4ae066784f 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form @@ -235,9 +235,6 @@ - - - @@ -248,9 +245,6 @@ - - - @@ -291,9 +285,6 @@ - - - @@ -304,9 +295,6 @@ - - - @@ -317,9 +305,6 @@ - - - @@ -331,9 +316,6 @@ - - - @@ -344,9 +326,6 @@ - - - @@ -357,9 +336,6 @@ - - - @@ -370,9 +346,6 @@ - - - @@ -383,9 +356,6 @@ - - - @@ -423,9 +393,6 @@ - - - @@ -457,9 +424,6 @@ - - - @@ -467,9 +431,6 @@ - - - - + \ No newline at end of file diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java index 157d371eed..653aedf252 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,9 +20,7 @@ package org.sleuthkit.autopsy.experimental.autoingest; import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.awt.Cursor; -import java.awt.Desktop; import java.awt.EventQueue; -import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.time.Instant; @@ -38,7 +36,6 @@ import java.util.logging.Level; import javax.swing.DefaultListSelectionModel; import java.awt.Color; import java.beans.PropertyChangeEvent; -import java.io.File; import java.util.Collections; import java.util.logging.Logger; import javax.swing.JOptionPane; @@ -49,25 +46,12 @@ import javax.swing.UIManager; import javax.swing.event.ListSelectionEvent; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableColumn; -import org.netbeans.api.options.OptionsDisplayer; -import org.openide.DialogDisplayer; import org.openide.LifecycleManager; -import org.openide.NotifyDescriptor; -import org.openide.filesystems.FileObject; -import org.openide.filesystems.FileUtil; import org.openide.util.NbBundle; -import org.openide.util.actions.CallableSystemAction; import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.casemodule.CaseNewAction; -import org.sleuthkit.autopsy.casemodule.CaseOpenAction; import org.sleuthkit.autopsy.core.ServicesMonitor; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.NetworkUtils; -import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.ingest.IngestManager; -import org.sleuthkit.autopsy.ingest.IngestProgressSnapshotDialog; -import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestManager.CaseDeletionResult; -import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestManager.JobsSnapshot; /** * A panel for monitoring automated ingest by a cluster, and for controlling @@ -105,7 +89,6 @@ public final class AutoIngestDashboard extends JPanel implements Observer { private final DefaultTableModel pendingTableModel; private final DefaultTableModel runningTableModel; private final DefaultTableModel completedTableModel; - private AutoIngestManager manager; private ExecutorService updateExecutor; private boolean isPaused; private boolean autoIngestStarted; @@ -182,11 +165,6 @@ public final class AutoIngestDashboard extends JPanel implements Observer { * controlling automated ingest for a single node within the cluster. */ private AutoIngestDashboard() { - //Disable the main window so they can only use the dashboard (if we used setVisible the taskBar icon would go away) - WindowManager.getDefault().getMainWindow().setEnabled(false); - - manager = AutoIngestManager.getInstance(); - pendingTableModel = new DefaultTableModel(JobsTableModelColumns.headers, 0) { private static final long serialVersionUID = 1L; @@ -590,28 +568,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer { */ private void startUp() { - /* - * Starts up the auto ingest manager (AIM). - */ - try { - manager.startUp(); - autoIngestStarted = true; - } catch (AutoIngestManager.AutoIngestManagerStartupException ex) { - SYS_LOGGER.log(Level.SEVERE, "Dashboard error starting up auto ingest", ex); - tbStatusMessage.setText(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.AutoIngestStartupError")); - manager = null; - - JOptionPane.showMessageDialog(this, - NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.AutoIngestStartupFailed.Message"), - NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.AutoIngestStartupFailed.Title"), - JOptionPane.ERROR_MESSAGE); - bnOptions.setEnabled(true); - - /* - * If the AIM cannot be started, there is nothing more to do. - */ - return; - } + autoIngestStarted = true; /* * Subscribe to services monitor events. @@ -620,17 +577,11 @@ public final class AutoIngestDashboard extends JPanel implements Observer { setServicesStatusMessage(); }); - /* - * Register with the AIM as an observer. - */ - manager.addObserver(this); - /* * Populate the pending, running, and completed auto ingest job tables. */ updateExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(UPDATE_TASKS_THREAD_NAME).build()); updateExecutor.submit(new UpdateAllJobsTablesTask()); - manager.scanInputDirsNow(); //bnPause.setEnabled(true); bnPause.setText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnPause.text")); @@ -659,7 +610,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer { NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.Cancel")}; int reply = JOptionPane.OK_OPTION; - if (null != manager && IngestManager.getInstance().isIngestRunning()) { + if (IngestManager.getInstance().isIngestRunning()) { reply = JOptionPane.showOptionDialog(this, NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.ExitConsequences"), NbBundle.getMessage(AutoIngestDashboard.class, "ConfirmationDialog.ConfirmExitHeader"), @@ -684,13 +635,6 @@ public final class AutoIngestDashboard extends JPanel implements Observer { updateExecutor.shutdownNow(); } - /* - * Stop observing the auto ingest manager (AIM). - */ - if (null != manager) { - manager.deleteObserver(this); - } - /* * Shut down the AIM and close. */ @@ -698,9 +642,6 @@ public final class AutoIngestDashboard extends JPanel implements Observer { @Override protected Void doInBackground() throws Exception { - if (null != manager) { - manager.shutDown(); - } return null; } @@ -807,7 +748,6 @@ public final class AutoIngestDashboard extends JPanel implements Observer { * Ask the auto ingest manager to pause when it completes the * currently running job, if any. */ - manager.pause(); bnRefresh.setEnabled(false); } } @@ -835,11 +775,6 @@ public final class AutoIngestDashboard extends JPanel implements Observer { */ pendingTable.setBackground(pendingTableBackground); pendingTable.setForeground(pendingTablelForeground); - - /** - * Ask the auto ingest manager to resume processing. - */ - manager.resume(); } /** @@ -855,7 +790,6 @@ public final class AutoIngestDashboard extends JPanel implements Observer { @Override public void run() { List pendingJobs = new ArrayList<>(); - manager.getJobs(pendingJobs, null, null); EventQueue.invokeLater(new RefreshComponentsTask(pendingJobs, null, null)); } } @@ -873,7 +807,6 @@ public final class AutoIngestDashboard extends JPanel implements Observer { @Override public void run() { List runningJobs = new ArrayList<>(); - manager.getJobs(null, runningJobs, null); EventQueue.invokeLater(new RefreshComponentsTask(null, runningJobs, null)); } } @@ -897,7 +830,6 @@ public final class AutoIngestDashboard extends JPanel implements Observer { List pendingJobs = new ArrayList<>(); List runningJobs = new ArrayList<>(); List completedJobs = new ArrayList<>(); - manager.getJobs(pendingJobs, runningJobs, completedJobs); // Sort the completed jobs list by completed date Collections.sort(completedJobs, new AutoIngestJob.ReverseDateCompletedComparator()); EventQueue.invokeLater(new RefreshComponentsTask(pendingJobs, runningJobs, completedJobs)); @@ -1084,10 +1016,6 @@ public final class AutoIngestDashboard extends JPanel implements Observer { * Get the current lists of jobs and update the UI. */ private void refreshTables(){ - JobsSnapshot jobsSnapshot = manager.getCurrentJobsSnapshot(); - refreshTable(jobsSnapshot.getCompletedJobs(), completedTableModel, null); - refreshTable(jobsSnapshot.getPendingJobs(), pendingTableModel, null); - refreshTable(jobsSnapshot.getRunningJobs(), runningTableModel, null); } /** @@ -1182,19 +1110,9 @@ public final class AutoIngestDashboard extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnCancelJob, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnCancelJob.text")); // NOI18N bnCancelJob.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnCancelJob.toolTipText")); // NOI18N - bnCancelJob.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnCancelJobActionPerformed(evt); - } - }); org.openide.awt.Mnemonics.setLocalizedText(bnDeleteCase, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnDeleteCase.text")); // NOI18N bnDeleteCase.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnDeleteCase.toolTipText")); // NOI18N - bnDeleteCase.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnDeleteCaseActionPerformed(evt); - } - }); lbPending.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(lbPending, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.lbPending.text")); // NOI18N @@ -1207,68 +1125,28 @@ public final class AutoIngestDashboard extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnRefresh, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnRefresh.text")); // NOI18N bnRefresh.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnRefresh.toolTipText")); // NOI18N - bnRefresh.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnRefreshActionPerformed(evt); - } - }); org.openide.awt.Mnemonics.setLocalizedText(bnCancelModule, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnCancelModule.text")); // NOI18N bnCancelModule.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnCancelModule.toolTipText")); // NOI18N - bnCancelModule.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnCancelModuleActionPerformed(evt); - } - }); org.openide.awt.Mnemonics.setLocalizedText(bnExit, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnExit.text")); // NOI18N bnExit.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnExit.toolTipText")); // NOI18N - bnExit.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnExitActionPerformed(evt); - } - }); org.openide.awt.Mnemonics.setLocalizedText(bnOptions, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnOptions.text")); // NOI18N bnOptions.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnOptions.toolTipText")); // NOI18N bnOptions.setEnabled(false); - bnOptions.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnOptionsActionPerformed(evt); - } - }); org.openide.awt.Mnemonics.setLocalizedText(bnShowProgress, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnShowProgress.text")); // NOI18N bnShowProgress.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnShowProgress.toolTipText")); // NOI18N - bnShowProgress.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnShowProgressActionPerformed(evt); - } - }); org.openide.awt.Mnemonics.setLocalizedText(bnPause, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnPause.text")); // NOI18N bnPause.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnPause.toolTipText")); // NOI18N - bnPause.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnPauseActionPerformed(evt); - } - }); org.openide.awt.Mnemonics.setLocalizedText(bnPrioritizeCase, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnPrioritizeCase.text")); // NOI18N bnPrioritizeCase.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnPrioritizeCase.toolTipText")); // NOI18N - bnPrioritizeCase.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnPrioritizeCaseActionPerformed(evt); - } - }); org.openide.awt.Mnemonics.setLocalizedText(bnShowCaseLog, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnShowCaseLog.text")); // NOI18N bnShowCaseLog.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnShowCaseLog.toolTipText")); // NOI18N - bnShowCaseLog.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnShowCaseLogActionPerformed(evt); - } - }); tbStatusMessage.setEditable(false); tbStatusMessage.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N @@ -1281,11 +1159,6 @@ public final class AutoIngestDashboard extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnPrioritizeJob, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnPrioritizeJob.text")); // NOI18N bnPrioritizeJob.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnPrioritizeJob.toolTipText")); // NOI18N bnPrioritizeJob.setActionCommand(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnPrioritizeJob.actionCommand")); // NOI18N - bnPrioritizeJob.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnPrioritizeJobActionPerformed(evt); - } - }); lbServicesStatus.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(lbServicesStatus, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.lbServicesStatus.text")); // NOI18N @@ -1296,18 +1169,8 @@ public final class AutoIngestDashboard extends JPanel implements Observer { tbServicesStatusMessage.setBorder(null); org.openide.awt.Mnemonics.setLocalizedText(bnOpenLogDir, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnOpenLogDir.text")); // NOI18N - bnOpenLogDir.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnOpenLogDirActionPerformed(evt); - } - }); org.openide.awt.Mnemonics.setLocalizedText(bnReprocessJob, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnReprocessJob.text")); // NOI18N - bnReprocessJob.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnReprocessJobActionPerformed(evt); - } - }); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -1427,278 +1290,6 @@ public final class AutoIngestDashboard extends JPanel implements Observer { }// //GEN-END:initComponents - /** - * Handles a click on the refresh button. Requests an immediate scan of the - * input folders for new jobs and queues a refresh of all three of the jobs - * tables. - * - * @param evt - The button click event. - */ - private void bnRefreshActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnRefreshActionPerformed - this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - manager.scanInputDirsAndWait(); - refreshTables(); - this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - }//GEN-LAST:event_bnRefreshActionPerformed - - /** - * Handles a click on the delete case button. If an entry is selected that - * can be deleted, pops up a confirmation dialog. Upon confirmation, asks - * AutoIngestManager to delete the entry and asks for an updated view. - * - * @param evt The button click event. - */ - private void bnDeleteCaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnDeleteCaseActionPerformed - if (completedTableModel.getRowCount() < 0 || completedTable.getSelectedRow() < 0) { - return; - } - - String caseName = (String) completedTable.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal()); - Object[] options = { - org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "ConfirmationDialog.Delete"), - org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "ConfirmationDialog.DoNotDelete") - }; - Object[] msgContent = {org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "ConfirmationDialog.DeleteAreYouSure") + "\"" + caseName + "\"?"}; - int reply = JOptionPane.showOptionDialog(this, - msgContent, - org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "ConfirmationDialog.ConfirmDeletionHeader"), - JOptionPane.DEFAULT_OPTION, - JOptionPane.WARNING_MESSAGE, - null, - options, - options[JOptionPane.NO_OPTION]); - if (reply == JOptionPane.YES_OPTION) { - bnDeleteCase.setEnabled(false); - bnShowCaseLog.setEnabled(false); - if (completedTableModel.getRowCount() > 0 && completedTable.getSelectedRow() >= 0) { - Path caseDirectoryPath = (Path) completedTableModel.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal()); - completedTable.clearSelection(); - this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - CaseDeletionResult result = manager.deleteCase(caseName, caseDirectoryPath); - refreshTables(); - this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - if (CaseDeletionResult.FAILED == result) { - JOptionPane.showMessageDialog(this, - String.format("Could not delete case %s. It may be in in use.", caseName), - org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.DeletionFailed"), - JOptionPane.INFORMATION_MESSAGE); - } else if (CaseDeletionResult.PARTIALLY_DELETED == result) { - JOptionPane.showMessageDialog(this, - String.format("Could not delete case %s. See system log for details.", caseName), - org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.DeletionFailed"), - JOptionPane.INFORMATION_MESSAGE); - } - } - } - }//GEN-LAST:event_bnDeleteCaseActionPerformed - - /** - * Handles a click on the cancel auto ingest job button. Cancels the - * selected job. - * - * @param evt The button click event. - */ - private void bnCancelJobActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnCancelJobActionPerformed - Object[] options = { - org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "ConfirmationDialog.CancelJob"), - org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "ConfirmationDialog.DoNotCancelJob")}; - int reply = JOptionPane.showOptionDialog(this, - NbBundle.getMessage(AutoIngestDashboard.class, "ConfirmationDialog.CancelJobAreYouSure"), - NbBundle.getMessage(AutoIngestDashboard.class, "ConfirmationDialog.ConfirmCancellationHeader"), - JOptionPane.DEFAULT_OPTION, - JOptionPane.WARNING_MESSAGE, - null, - options, - options[1]); - if (reply == 0) { - /* - * Call setCursor on this to ensure it appears (if there is time to - * see it). - */ - this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - manager.cancelCurrentJob(); - refreshTables(); - this.setCursor(Cursor.getDefaultCursor()); - } - }//GEN-LAST:event_bnCancelJobActionPerformed - - /** - * Handles a click on the show auto ingest job progress button. Displays an - * ingest job progress panel. - * - * @param evt The button click event. - */ - private void bnShowProgressActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnShowProgressActionPerformed - IngestProgressSnapshotDialog dialog = new IngestProgressSnapshotDialog(this.getTopLevelAncestor(), true); - }//GEN-LAST:event_bnShowProgressActionPerformed - - /** - * Handles a click on the pause/resume auto ingest job button. Sends a - * pause/resume request to the auto ingest manager. - * - * @param evt The button click event. - */ - private void bnPauseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPauseActionPerformed - - if (!autoIngestStarted) { - //put up a wait cursor during the start up operation - this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - - startUp(); - - this.setCursor(null); - //done for startup - return; - } - if (!isPaused) { - tbStatusMessage.setText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnPause.pausing")); - pause(true); - } else { - resume(); - } - isPaused = !isPaused; - }//GEN-LAST:event_bnPauseActionPerformed - - /** - * Handles a click on the options button. Displays the options window. - * - * @param evt The button click event. - */ - private void bnOptionsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOptionsActionPerformed - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - OptionsDisplayer.getDefault().open(); - setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - }//GEN-LAST:event_bnOptionsActionPerformed - - /** - * Handles a click on the cancel ingest module button. Cancels the currently - * running data source level ingest module for the selected job. - * - * @param evt The button click event. - */ - private void bnCancelModuleActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnCancelModuleActionPerformed - Object[] options = { - org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "ConfirmationDialog.CancelModule"), - org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "ConfirmationDialog.DoNotCancelModule")}; - int reply = JOptionPane.showOptionDialog(this, - NbBundle.getMessage(AutoIngestDashboard.class, "ConfirmationDialog.CancelModuleAreYouSure"), - NbBundle.getMessage(AutoIngestDashboard.class, "ConfirmationDialog.ConfirmCancellationHeader"), - JOptionPane.DEFAULT_OPTION, - JOptionPane.WARNING_MESSAGE, - null, - options, - options[1]); - if (reply == 0) { - /* - * Call setCursor on this to ensure it appears (if there is time to - * see it). - */ - this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - manager.cancelCurrentDataSourceLevelIngestModule(); - refreshTables(); - this.setCursor(Cursor.getDefaultCursor()); - } - }//GEN-LAST:event_bnCancelModuleActionPerformed - - /** - * Handles a click on the exit button. Shuts down auto ingest. - * - * @param evt The button click event. - */ - private void bnExitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnExitActionPerformed - shutdown(); - }//GEN-LAST:event_bnExitActionPerformed - - /** - * Handle a click on the prioritize case button. Requests prioritization of - * all of the auto ingest jobs for a case. - * - * @param evt The button click event. - */ - private void bnPrioritizeCaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPrioritizeCaseActionPerformed - if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { - this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - String caseName = (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal())).toString(); - manager.prioritizeCase(caseName); - refreshTables(); - pendingTable.clearSelection(); - enablePendingTableButtons(false); - AutoIngestDashboard.this.setCursor(Cursor.getDefaultCursor()); - } - }//GEN-LAST:event_bnPrioritizeCaseActionPerformed - - /** - * Handles a click on the show log button. Displays the auto ingest job log - * for a case in NotePad. - * - * @param evt The button click event. - */ - private void bnShowCaseLogActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnShowCaseLogActionPerformed - try { - int selectedRow = completedTable.getSelectedRow(); - if (selectedRow != -1) { - Path caseDirectoryPath = (Path) completedTableModel.getValueAt(selectedRow, JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal()); - if (null != caseDirectoryPath) { - Path pathToLog = AutoIngestJobLogger.getLogPath(caseDirectoryPath); - if (pathToLog.toFile().exists()) { - Desktop.getDesktop().edit(pathToLog.toFile()); - } else { - JOptionPane.showMessageDialog(this, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.ShowLogFailed.Message"), - org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.ShowLogFailed.Title"), JOptionPane.ERROR_MESSAGE); - } - } else { - MessageNotifyUtil.Message.warn("The case directory for this job has been deleted."); - } - } - } catch (IOException ex) { - SYS_LOGGER.log(Level.SEVERE, "Dashboard error attempting to display case auto ingest log", ex); - Object[] options = {org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "DisplayLogDialog.okay")}; - JOptionPane.showOptionDialog(this, - org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "DisplayLogDialog.cannotFindLog"), - org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "DisplayLogDialog.unableToShowLogFile"), - JOptionPane.DEFAULT_OPTION, - JOptionPane.PLAIN_MESSAGE, - null, - options, - options[0]); - } - }//GEN-LAST:event_bnShowCaseLogActionPerformed - - private void bnPrioritizeJobActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPrioritizeJobActionPerformed - if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { - this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - Path manifestFilePath = (Path) (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal())); - manager.prioritizeJob(manifestFilePath); - refreshTables(); - pendingTable.clearSelection(); - enablePendingTableButtons(false); - AutoIngestDashboard.this.setCursor(Cursor.getDefaultCursor()); - } - }//GEN-LAST:event_bnPrioritizeJobActionPerformed - - private void bnOpenLogDirActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOpenLogDirActionPerformed - Path logDirPath = Paths.get(PlatformUtil.getUserDirectory().getAbsolutePath(), "var", "log"); - File logDir = logDirPath.toFile(); - try { - Desktop.getDesktop().open(logDir); - } catch (IOException ex) { - DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message( - String.format("Unable to open log directory %s:\n%s", logDirPath, ex.getLocalizedMessage()), - NotifyDescriptor.ERROR_MESSAGE)); - } - }//GEN-LAST:event_bnOpenLogDirActionPerformed - - private void bnReprocessJobActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnReprocessJobActionPerformed - if (completedTableModel.getRowCount() < 0 || completedTable.getSelectedRow() < 0) { - return; - } - this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - Path manifestPath = (Path) completedTableModel.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal()); - manager.reprocessJob(manifestPath); - refreshTables(); - AutoIngestDashboard.this.setCursor(Cursor.getDefaultCursor()); - }//GEN-LAST:event_bnReprocessJobActionPerformed - // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton bnCancelJob; private javax.swing.JButton bnCancelModule; @@ -1728,4 +1319,4 @@ public final class AutoIngestDashboard extends JPanel implements Observer { private javax.swing.JTextField tbStatusMessage; // End of variables declaration//GEN-END:variables -} +} \ No newline at end of file diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java new file mode 100755 index 0000000000..5c9c95b71a --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java @@ -0,0 +1,111 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2017 Basis Technology Corp. + * Contact: carrier sleuthkit 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.Component; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionRegistration; +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle.Messages; +import org.openide.util.actions.CallableSystemAction; +import org.openide.util.actions.Presenter; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.core.RuntimeProperties; +import org.sleuthkit.autopsy.core.UserPreferences; +import static org.sleuthkit.autopsy.core.UserPreferences.SelectedMode.REVIEW; +import org.sleuthkit.autopsy.coreutils.Logger; + +@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.experimental.autoingest.AutoIngestDashboardOpenAction") +@ActionReference(path = "Menu/Tools", position = 104) +@ActionRegistration(displayName = "#CTL_AutoIngestDashboardOpenAction", lazy = false) +@Messages({"CTL_AutoIngestDashboardOpenAction=Auto Ingest Dashboard"}) +public final class AutoIngestDashboardOpenAction extends CallableSystemAction implements Presenter.Toolbar { + + private static final Logger LOGGER = Logger.getLogger(AutoIngestDashboardOpenAction.class.getName()); + private static final String VIEW_IMAGES_VIDEOS = Bundle.CTL_AutoIngestDashboardOpenAction(); + + private final JButton toolbarButton = new JButton(); + private final PropertyChangeListener pcl; + + public AutoIngestDashboardOpenAction() { + super(); + toolbarButton.addActionListener(actionEvent -> performAction()); + pcl = (PropertyChangeEvent evt) -> { + if (evt.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) { + setEnabled(RuntimeProperties.runningWithGUI() && evt.getNewValue() != null); + } + }; + Case.addPropertyChangeListener(pcl); + this.setEnabled(false); + } + + @Override + public boolean isEnabled() { + UserPreferences.SelectedMode mode = UserPreferences.getMode(); + return (mode == REVIEW); + } + + /** Returns the toolbar component of this action + * + * @return component the toolbar button */ + @Override + public Component getToolbarPresenter() { + ImageIcon icon = new ImageIcon(getClass().getResource("btn_icon_image_gallery_26.png")); //NON-NLS + toolbarButton.setIcon(icon); + toolbarButton.setText(this.getName()); + return toolbarButton; + } + + /** + * Set this action to be enabled/disabled + * + * @param value whether to enable this action or not + */ + @Override + public void setEnabled(boolean value) { + super.setEnabled(value); + toolbarButton.setEnabled(value); + } + + @Override + @SuppressWarnings("fallthrough") + public void performAction() { + AutoIngestDashboardTopComponent.openTopComponent(); + } + + @Override + public String getName() { + return VIEW_IMAGES_VIDEOS; + } + + @Override + public HelpCtx getHelpCtx() { + return HelpCtx.DEFAULT_HELP; + } + + @Override + public boolean asynchronous() { + return false; // run on edt + } +} \ No newline at end of file diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.form new file mode 100755 index 0000000000..63887aceb0 --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.form @@ -0,0 +1,28 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.java new file mode 100755 index 0000000000..cfb2e7e18f --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.java @@ -0,0 +1,135 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2017 Basis Technology Corp. + * Contact: carrier sleuthkit 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.util.logging.Level; +import org.netbeans.api.settings.ConvertAsProperties; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +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.coreutils.Logger; + +/** + * Top component which displays the Auto Ingest Dashboard interface. + */ +@ConvertAsProperties( + dtd = "-//org.sleuthkit.autopsy.experimental.autoingest//AutoIngestDashboard//EN", + autostore = false +) +@TopComponent.Description( + preferredID = "AutoIngestDashboardTopComponent", + //iconBase="SET/PATH/TO/ICON/HERE", + persistenceType = TopComponent.PERSISTENCE_NEVER +) +@TopComponent.Registration(mode = "dashboard", openAtStartup = false) +@Messages({ + "CTL_AutoIngestDashboardAction=Auto Ingest Dashboard", + "CTL_AutoIngestDashboardTopComponent=Auto Ingest Dashboard", + "HINT_AutoIngestDashboardTopComponent=This is an Auto Ingest Dashboard window" +}) +public final class AutoIngestDashboardTopComponent extends TopComponent { + public final static String PREFERRED_ID = "AutoIngestDashboardTopComponent"; // NON-NLS + private static final Logger LOGGER = Logger.getLogger(AutoIngestDashboardTopComponent.class.getName()); + private static boolean topComponentInitialized = false; + + public static void openTopComponent() { + final AutoIngestDashboardTopComponent tc = (AutoIngestDashboardTopComponent) WindowManager.getDefault().findTopComponent(PREFERRED_ID); + if (tc != null) { + topComponentInitialized = true; + WindowManager.getDefault().isTopComponentFloating(tc); + Mode mode = WindowManager.getDefault().findMode("dashboard"); // NON-NLS + if (mode != null) { + mode.dockInto(tc); + } + + AutoIngestDashboard dashboard = AutoIngestDashboard.getInstance(); + tc.add(dashboard); + dashboard.setSize(dashboard.getPreferredSize()); + + tc.open(); + tc.requestActive(); + } + } + + public static void closeTopComponent() { + if (topComponentInitialized) { + final TopComponent etc = WindowManager.getDefault().findTopComponent(PREFERRED_ID); + if (etc != null) { + try { + etc.close(); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "failed to close " + PREFERRED_ID, e); // NON-NLS + } + } + } + } + + public AutoIngestDashboardTopComponent() { + initComponents(); + setName(Bundle.CTL_AutoIngestDashboardTopComponent()); + setToolTipText(Bundle.HINT_AutoIngestDashboardTopComponent()); + } + + /** + * 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. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 400, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 300, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables + @Override + public void componentOpened() { + // TODO add custom code on component opening + } + + @Override + public void componentClosed() { + // TODO add custom code on component closing + } + + void writeProperties(java.util.Properties p) { + // better to version settings since initial version as advocated at + // http://wiki.apidesign.org/wiki/PropertyFiles + p.setProperty("version", "1.0"); + // TODO store your settings + } + + void readProperties(java.util.Properties p) { + String version = p.getProperty("version"); + // TODO read your settings according to their version + } +} \ No newline at end of file diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties index a659557b17..28b5796c3f 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties @@ -298,3 +298,38 @@ AutoIngestCasePanel.bnOpen.text=&Open AutoIngestCasePanel.bnShowLog.toolTipText=Display case log file for selected case AutoIngestCasePanel.bnShowLog.text=&Show Log AutoIngestCasePanel.rbGroupLabel.text=Show cases accessed in the last 10: +AutoIngestControlPanel.tbStatusMessage.text= +AutoIngestControlPanel.bnShowCaseLog.toolTipText=Display case log file for selected case +AutoIngestControlPanel.bnShowCaseLog.text=Show Case &Log +AutoIngestControlPanel.bnDeleteCase.toolTipText=Delete the selected Case in its entirety +AutoIngestControlPanel.bnDeleteCase.text=&Delete Case +AutoIngestControlPanel.bnCancelJob.toolTipText=Cancel processing of the current Job and move on to the next Job. This functionality is only available for jobs running on current AIM node. +AutoIngestControlPanel.bnCancelJob.text=&Cancel Job +AutoIngestControlPanel.completedTable.toolTipText=The Completed table shows all Jobs that have been processed already +AutoIngestControlPanel.runningTable.toolTipText=The Running table displays the currently running Job and information about it +AutoIngestControlPanel.pendingTable.toolTipText=The Pending table displays the order upcoming Jobs will be processed with the top of the list first +AutoIngestControlPanel.bnPrioritizeCase.toolTipText=Move all images associated with a case to top of Pending queue. +AutoIngestControlPanel.bnPrioritizeCase.text=Prioriti&ze Case +AutoIngestControlPanel.bnPause.toolTipText=Suspend processing of Pending Jobs +AutoIngestControlPanel.bnPause.text=Pause +AutoIngestControlPanel.bnShowProgress.toolTipText=Show the progress of the currently running Job. This functionality is only available for jobs running on current AIM node. +AutoIngestControlPanel.bnShowProgress.text=Ingest Progress +AutoIngestControlPanel.bnOptions.toolTipText=Display options panel. All processing must be paused to open the options panel. +AutoIngestControlPanel.bnOptions.text=&Options +AutoIngestControlPanel.bnExit.toolTipText=Exit Application +AutoIngestControlPanel.bnExit.text=&Exit +AutoIngestControlPanel.bnCancelModule.toolTipText=Cancel processing of the current module within the Job and move on to the next module within the Job. This functionality is only available for jobs running on current AIM node. +AutoIngestControlPanel.bnCancelModule.text=Cancel &Module +AutoIngestControlPanel.bnRefresh.toolTipText=Refresh displayed tables +AutoIngestControlPanel.bnRefresh.text=&Refresh +AutoIngestControlPanel.lbCompleted.text=Completed Jobs +AutoIngestControlPanel.lbRunning.text=Running Jobs +AutoIngestControlPanel.lbPending.text=Pending Jobs +AutoIngestControlPanel.bnReprocessJob.text=Reprocess Job +AutoIngestControlPanel.bnOpenLogDir.text=Open System Logs Directory +AutoIngestControlPanel.tbServicesStatusMessage.text= +AutoIngestControlPanel.lbServicesStatus.text=Services Status: +AutoIngestControlPanel.bnPrioritizeJob.actionCommand= +AutoIngestControlPanel.bnPrioritizeJob.toolTipText=Move this folder to the top of the Pending queue. +AutoIngestControlPanel.bnPrioritizeJob.text=Prioritize Job +AutoIngestControlPanel.lbStatus.text=Status: \ No newline at end of file diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/StartupWindow.java b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/StartupWindow.java index a88ccfd4f2..f36fa45f12 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/StartupWindow.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/StartupWindow.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -35,7 +35,7 @@ import org.sleuthkit.autopsy.casemodule.CueBannerPanel; import org.sleuthkit.autopsy.casemodule.StartupWindowInterface; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.NetworkUtils; -import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestDashboard; +import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestControlPanel; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestCasePanel; /** @@ -80,6 +80,7 @@ public final class StartupWindow extends JDialog implements StartupWindowInterfa public void open() { if (caseManagementPanel != null) { + caseManagementPanel.updateView(); caseManagementPanel.setCursor(Cursor.getDefaultCursor()); } @@ -112,11 +113,11 @@ public final class StartupWindow extends JDialog implements StartupWindowInterfa this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { - AutoIngestDashboard.getInstance().shutdown(); + AutoIngestControlPanel.getInstance().shutdown(); } }); setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); - add(AutoIngestDashboard.getInstance()); + add(AutoIngestControlPanel.getInstance()); break; case REVIEW: this.setTitle(NbBundle.getMessage(StartupWindow.class, "StartupWindow.ReviewMode") + " (" + LOCAL_HOST_NAME + ")"); @@ -137,4 +138,4 @@ public final class StartupWindow extends JDialog implements StartupWindowInterfa break; } } -} +} \ No newline at end of file diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties index 9fa4b48338..5d5b0cd16d 100644 --- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties +++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties @@ -8,4 +8,4 @@ SplashRunningTextBounds=0,289,538,18 SplashRunningTextColor=0x0 SplashRunningTextFontSize=19 -currentVersion=Autopsy 4.4.1 +currentVersion=Autopsy 4.4.1 \ No newline at end of file diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index 9207917601..ed34d34298 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,4 +1,4 @@ #Updated by build script #Thu, 22 Jun 2017 08:50:21 -0400 CTL_MainWindow_Title=Autopsy 4.4.1 -CTL_MainWindow_Title_No_Project=Autopsy 4.4.1 +CTL_MainWindow_Title_No_Project=Autopsy 4.4.1 \ No newline at end of file From e8d369deec55c32be85f1c039fda5ddf723b9690 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 25 Aug 2017 13:17:44 -0400 Subject: [PATCH 2/2] Revised class to get rid of unused code. --- .../AutoIngestDashboardOpenAction.java | 51 ++----------------- 1 file changed, 3 insertions(+), 48 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java index 5c9c95b71a..7e1b1907af 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java @@ -18,20 +18,12 @@ */ package org.sleuthkit.autopsy.experimental.autoingest; -import java.awt.Component; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import javax.swing.ImageIcon; -import javax.swing.JButton; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; import org.openide.awt.ActionRegistration; import org.openide.util.HelpCtx; import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; -import org.openide.util.actions.Presenter; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.core.UserPreferences; import static org.sleuthkit.autopsy.core.UserPreferences.SelectedMode.REVIEW; import org.sleuthkit.autopsy.coreutils.Logger; @@ -40,25 +32,10 @@ import org.sleuthkit.autopsy.coreutils.Logger; @ActionReference(path = "Menu/Tools", position = 104) @ActionRegistration(displayName = "#CTL_AutoIngestDashboardOpenAction", lazy = false) @Messages({"CTL_AutoIngestDashboardOpenAction=Auto Ingest Dashboard"}) -public final class AutoIngestDashboardOpenAction extends CallableSystemAction implements Presenter.Toolbar { +public final class AutoIngestDashboardOpenAction extends CallableSystemAction { private static final Logger LOGGER = Logger.getLogger(AutoIngestDashboardOpenAction.class.getName()); - private static final String VIEW_IMAGES_VIDEOS = Bundle.CTL_AutoIngestDashboardOpenAction(); - - private final JButton toolbarButton = new JButton(); - private final PropertyChangeListener pcl; - - public AutoIngestDashboardOpenAction() { - super(); - toolbarButton.addActionListener(actionEvent -> performAction()); - pcl = (PropertyChangeEvent evt) -> { - if (evt.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) { - setEnabled(RuntimeProperties.runningWithGUI() && evt.getNewValue() != null); - } - }; - Case.addPropertyChangeListener(pcl); - this.setEnabled(false); - } + private static final String DISPLAY_NAME = Bundle.CTL_AutoIngestDashboardOpenAction(); @Override public boolean isEnabled() { @@ -66,28 +43,6 @@ public final class AutoIngestDashboardOpenAction extends CallableSystemAction im return (mode == REVIEW); } - /** Returns the toolbar component of this action - * - * @return component the toolbar button */ - @Override - public Component getToolbarPresenter() { - ImageIcon icon = new ImageIcon(getClass().getResource("btn_icon_image_gallery_26.png")); //NON-NLS - toolbarButton.setIcon(icon); - toolbarButton.setText(this.getName()); - return toolbarButton; - } - - /** - * Set this action to be enabled/disabled - * - * @param value whether to enable this action or not - */ - @Override - public void setEnabled(boolean value) { - super.setEnabled(value); - toolbarButton.setEnabled(value); - } - @Override @SuppressWarnings("fallthrough") public void performAction() { @@ -96,7 +51,7 @@ public final class AutoIngestDashboardOpenAction extends CallableSystemAction im @Override public String getName() { - return VIEW_IMAGES_VIDEOS; + return DISPLAY_NAME; } @Override