Merge pull request #3362 from APriestman/3165_liveTriageButton

3165 Added menu item to create live triage drive
This commit is contained in:
Richard Cordovano 2018-01-16 07:14:06 -05:00 committed by GitHub
commit 519d1b84d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 842 additions and 0 deletions

View File

@ -0,0 +1,7 @@
SelectDriveDialog.bnOk.text=Ok
SelectDriveDialog.bnRefresh.text=Refresh
SelectDriveDialog.lbSelectDrive.text=Select the drive to copy the application and script to:
SelectDriveDialog.jLabel1.text=Select drive to use for live triage (may take time to load):
SelectDriveDialog.errorLabel.text=jLabel2
SelectDriveDialog.bnCancel.text=Cancel
SelectDriveDialog.jTextArea1.text=This feature copies the application and a batch file to a removable drive,\nallowing systems to be analyzed without installing the software or\nimaging the drives.\n\nTo analyze a system, insert the drive and run "RunFromUSB.bat" as\nadministrator, then select the "Local Disk" option on the Add Data Source\npanel.

View File

@ -0,0 +1,284 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.livetriage;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.InvalidPathException;
import java.util.logging.Level;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import javax.swing.JOptionPane;
import java.awt.Frame;
import javax.swing.SwingWorker;
import org.apache.commons.io.FileUtils;
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;
import org.openide.util.actions.CallableSystemAction;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.progress.ModalDialogProgressIndicator;
@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.livetriage.CreateLiveTriageDriveAction")
@ActionReference(path = "Menu/Tools", position = 1401)
@ActionRegistration(displayName = "#CTL_CreateLiveTriageDriveAction", lazy = false)
@NbBundle.Messages({"CTL_CreateLiveTriageDriveAction=Make Live Triage Drive"})
public final class CreateLiveTriageDriveAction extends CallableSystemAction implements PropertyChangeListener {
private static final String DISPLAY_NAME = Bundle.CTL_CreateLiveTriageDriveAction();
private ModalDialogProgressIndicator progressIndicator = null;
private String drivePath = "";
private CopyFilesWorker worker;
@Override
public boolean isEnabled() {
return true;
}
@NbBundle.Messages({"CreateLiveTriageDriveAction.error.title=Error creating live triage disk",
"CreateLiveTriageDriveAction.exenotfound.message=Executable could not be found",
"CreateLiveTriageDriveAction.batchFileError.message=Error creating batch file",
"CreateLiveTriageDriveAction.appPathError.message=Could not location application directory",
"CreateLiveTriageDriveAction.copyError.message=Could not copy application. Only works on installed version.",
"CreateLiveTriageDriveAction.success.title=Success",
"CreateLiveTriageDriveAction.success.message=Live triage drive created. Use RunFromUSB.bat to run the application"
})
@Override
@SuppressWarnings("fallthrough")
public void performAction() {
Frame mainWindow = WindowManager.getDefault().getMainWindow();
// If this is an installed version, there should be an <appName>64.exe file in the bin folder
String appName = UserPreferences.getAppName();
String exeName = appName + "64.exe";
String installPath = PlatformUtil.getInstallPath();
Path exePath = Paths.get(installPath, "bin", exeName);
if (!exePath.toFile().exists()) {
JOptionPane.showMessageDialog(mainWindow,
Bundle.CreateLiveTriageDriveAction_exenotfound_message(),
Bundle.CreateLiveTriageDriveAction_error_title(),
JOptionPane.ERROR_MESSAGE);
return;
}
Path applicationBasePath;
try {
applicationBasePath = exePath.getParent().getParent();
} catch (InvalidPathException ex) {
JOptionPane.showMessageDialog(mainWindow,
Bundle.CreateLiveTriageDriveAction_appPathError_message(),
Bundle.CreateLiveTriageDriveAction_error_title(),
JOptionPane.ERROR_MESSAGE);
return;
}
SelectDriveDialog driveDialog = new SelectDriveDialog(mainWindow, true);
driveDialog.display();
if (!driveDialog.getSelectedDrive().isEmpty()) {
drivePath = driveDialog.getSelectedDrive();
if (drivePath.startsWith("\\\\.\\")) {
drivePath = drivePath.substring(4);
}
worker = new CopyFilesWorker(applicationBasePath, drivePath, appName);
worker.addPropertyChangeListener(this);
worker.execute();
}
}
@NbBundle.Messages({"# {0} - drivePath",
"CreateLiveTriageDriveAction.progressBar.text=Copying live triage files to {0}",
"CreateLiveTriageDriveAction.progressBar.title=Please wait"})
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("state".equals(evt.getPropertyName())
&& (SwingWorker.StateValue.STARTED.equals(evt.getNewValue()))) {
// Setup progress bar.
String displayStr = NbBundle.getMessage(this.getClass(), "CreateLiveTriageDriveAction.progressBar.text",
drivePath);
progressIndicator = new ModalDialogProgressIndicator(WindowManager.getDefault().getMainWindow(),
NbBundle.getMessage(this.getClass(), "CreateLiveTriageDriveAction.progressBar.title"));
progressIndicator.start(displayStr);
} else if ("state".equals(evt.getPropertyName())
&& (SwingWorker.StateValue.DONE.equals(evt.getNewValue()))) {
if (progressIndicator != null) {
progressIndicator.finish();
}
if (worker.hadError()) {
MessageNotifyUtil.Message.error(NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.error.text"));
} else {
MessageNotifyUtil.Message.info(NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.done.text"));
}
}
}
private class CopyFilesWorker extends SwingWorker<Void, Void> {
private final Path sourceFolder;
private final String drivePath;
private final String appName;
private boolean error = false;
CopyFilesWorker(Path sourceFolder, String drivePath, String appName) {
this.sourceFolder = sourceFolder;
this.drivePath = drivePath;
this.appName = appName;
}
boolean hadError() {
return error;
}
@Override
protected Void doInBackground() throws Exception {
copyBatchFile(drivePath, appName);
copyApplication(sourceFolder, drivePath, appName);
return null;
}
@NbBundle.Messages({"CopyFilesWorker.error.text=Error copying live triage files",
"CopyFilesWorker.done.text=Finished creating live triage disk"})
@Override
protected void done() {
try {
super.get();
} catch (Exception ex) {
error = true;
Logger.getLogger(CreateLiveTriageDriveAction.class.getName()).log(Level.SEVERE, "Fatal error during live triage drive creation", ex); //NON-NLS
}
}
}
private void copyApplication(Path sourceFolder, String destBaseFolder, String appName) throws IOException {
// Create an appName folder in the destination
Path destAppFolder = Paths.get(destBaseFolder, appName);
if (!destAppFolder.toFile().exists()) {
if (!destAppFolder.toFile().mkdirs()) {
throw new IOException("Failed to create directory " + destAppFolder.toString());
}
}
// Now copy the files
FileUtils.copyDirectory(sourceFolder.toFile(), destAppFolder.toFile());
}
private void copyBatchFile(String destPath, String appName) throws IOException, InvalidPathException {
Path batchFilePath = Paths.get(destPath, "RunFromUSB.bat");
FileUtils.writeStringToFile(batchFilePath.toFile(), getBatchFileContents(appName), "UTF-8");
}
private String getBatchFileContents(String appName) {
String batchFile
= "@echo off\n"
+ "\n"
+ "REM This restores the working directory when using 'Run as administrator'"
+ "@setlocal enableextensions\n"
+ "@cd /d \"%~dp0\""
+ "\n"
+ "SET appName=\"" + appName + "\"\n"
+ "\n"
+ "REM Create the configData directory. Exit if it does not exist after attempting to create it\n"
+ "if not exist configData mkdir configData\n"
+ "if not exist configData (\n"
+ " echo Error creating directory configData\n"
+ " goto end\n"
+ ")\n"
+ "\n"
+ "REM Create the userdir sub directory. Exit if it does not exist after attempting to create it\n"
+ "if not exist configData\\userdir mkdir configData\\userdir\n"
+ "if not exist configData\\userdir (\n"
+ " echo Error creating directory configData\\userdir\n"
+ " goto end\n"
+ ")\n"
+ "\n"
+ "REM Create the cachedir sub directory. Exit if it does not exist after attempting to create it\n"
+ "REM If it exists to start with, delete it to clear out old data\n"
+ "if exist configData\\cachedir rd /s /q configData\\cachedir\n"
+ "mkdir configData\\cachedir\n"
+ "if not exist configData\\cachedir (\n"
+ " echo Error creating directory configData\\cachedir\n"
+ " goto end\n"
+ ")\n"
+ "\n"
+ "REM Create the temp sub directory. Exit if it does not exist after attempting to create it\n"
+ "REM If it exists to start with, delete it to clear out old data\n"
+ "if exist configData\\temp rd /s /q configData\\temp\n"
+ "mkdir configData\\temp\n"
+ "if not exist configData\\temp (\n"
+ " echo Error creating directory configData\\temp\n"
+ " goto end\n"
+ ")\n"
+ "\n"
+ "REM Create the cases directory. It's ok if this fails.\n"
+ "if not exist cases mkdir cases\n"
+ "\n"
+ "if exist %appName% (\n"
+ " if not exist %appName%\\bin\\%appName%64.exe (\n"
+ " echo %appName%\\bin\\%appName%64.exe does not exist\n"
+ " goto end\n"
+ " )\n"
+ " %appName%\\bin\\%appName%64.exe --userdir ..\\configData\\userdir --cachedir ..\\configData\\cachedir -J-Djava.io.tmpdir=..\\configData\\temp\n"
+ ") else (\n"
+ " echo Could not find %appName% directory\n"
+ " goto end\n"
+ ")\n"
+ "\n"
+ ":end\n"
+ "\n"
+ "REM Keep the cmd window open in case there was an error\n"
+ "@pause\n";
return batchFile;
}
@Override
public String getName() {
return DISPLAY_NAME;
}
@Override
public HelpCtx getHelpCtx() {
return HelpCtx.DEFAULT_HELP;
}
@Override
public boolean asynchronous() {
return false; // run on edt
}
}

View File

@ -0,0 +1,163 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="bnRefresh" pref="112" max="32767" attributes="0"/>
<EmptySpace pref="48" max="32767" attributes="0"/>
<Component id="bnOk" min="-2" pref="101" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="bnCancel" min="-2" pref="101" max="-2" attributes="0"/>
</Group>
<Component id="jScrollPane1" alignment="0" pref="0" max="32767" attributes="0"/>
<Component id="jLabel1" alignment="0" max="32767" attributes="0"/>
<Component id="jSeparator1" alignment="0" max="32767" attributes="0"/>
<Component id="errorLabel" alignment="0" max="32767" attributes="0"/>
<Component id="jScrollPane2" max="32767" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane2" min="-2" pref="107" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jSeparator1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="jScrollPane1" min="-2" pref="112" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="bnRefresh" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="bnCancel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="bnOk" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="errorLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTable" name="diskTable">
<Properties>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="model" type="code"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="jLabel1">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/livetriage/Bundle.properties" key="SelectDriveDialog.jLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="bnRefresh">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/livetriage/Bundle.properties" key="SelectDriveDialog.bnRefresh.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnRefreshActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="bnOk">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/livetriage/Bundle.properties" key="SelectDriveDialog.bnOk.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnOkActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="errorLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/livetriage/Bundle.properties" key="SelectDriveDialog.errorLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JSeparator" name="jSeparator1">
</Component>
<Component class="javax.swing.JButton" name="bnCancel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/livetriage/Bundle.properties" key="SelectDriveDialog.bnCancel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnCancelActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane2">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextArea" name="jTextArea1">
<Properties>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="f0" green="f0" red="f0" type="rgb"/>
</Property>
<Property name="columns" type="int" value="20"/>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="11" style="0"/>
</Property>
<Property name="rows" type="int" value="5"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/livetriage/Bundle.properties" key="SelectDriveDialog.jTextArea1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,388 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.sleuthkit.autopsy.livetriage;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.logging.Level;
import java.awt.Dimension;
import java.awt.Point;
import javax.swing.SwingWorker;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.LocalDisk;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
/**
*
*/
class SelectDriveDialog extends javax.swing.JDialog {
private List<LocalDisk> disks = new ArrayList<>();
private final LocalDiskModel model = new LocalDiskModel();
private final java.awt.Frame parent;
private String drivePath = "";
/**
* Creates new form SelectDriveDialog
*/
@NbBundle.Messages({"SelectDriveDialog.title=Create Live Triage Drive"})
SelectDriveDialog(java.awt.Frame parent, boolean modal) {
super(parent, modal);
initComponents();
this.parent = parent;
model.loadDisks();
bnOk.setEnabled(false);
diskTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
if (diskTable.getSelectedRow() >= 0 && diskTable.getSelectedRow() < disks.size()) {
bnOk.setEnabled(true);
} else { //The selection changed to nothing valid being selected, such as with ctrl+click
bnOk.setEnabled(false);
}
}
});
}
void display() {
this.setTitle(Bundle.SelectDriveDialog_title());
final Dimension parentSize = parent.getSize();
final Point parentLocationOnScreen = parent.getLocationOnScreen();
final Dimension childSize = this.getSize();
int x;
int y;
x = (parentSize.width - childSize.width) / 2;
y = (parentSize.height - childSize.height) / 2;
x += parentLocationOnScreen.x;
y += parentLocationOnScreen.y;
setLocation(x, y);
setVisible(true);
}
String getSelectedDrive() {
return this.drivePath;
}
/**
* 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")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
diskTable = new javax.swing.JTable();
jLabel1 = new javax.swing.JLabel();
bnRefresh = new javax.swing.JButton();
bnOk = new javax.swing.JButton();
errorLabel = new javax.swing.JLabel();
jSeparator1 = new javax.swing.JSeparator();
bnCancel = new javax.swing.JButton();
jScrollPane2 = new javax.swing.JScrollPane();
jTextArea1 = new javax.swing.JTextArea();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
diskTable.setModel(model);
jScrollPane1.setViewportView(diskTable);
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.jLabel1.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(bnRefresh, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.bnRefresh.text")); // NOI18N
bnRefresh.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
bnRefreshActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(bnOk, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.bnOk.text")); // NOI18N
bnOk.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
bnOkActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.errorLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(bnCancel, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.bnCancel.text")); // NOI18N
bnCancel.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
bnCancelActionPerformed(evt);
}
});
jScrollPane2.setBorder(null);
jTextArea1.setBackground(new java.awt.Color(240, 240, 240));
jTextArea1.setColumns(20);
jTextArea1.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N
jTextArea1.setRows(5);
jTextArea1.setText(org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.jTextArea1.text")); // NOI18N
jTextArea1.setBorder(null);
jScrollPane2.setViewportView(jTextArea1);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addGroup(layout.createSequentialGroup()
.addComponent(bnRefresh, javax.swing.GroupLayout.DEFAULT_SIZE, 112, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 48, Short.MAX_VALUE)
.addComponent(bnOk, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(bnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
.addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jSeparator1)
.addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jScrollPane2))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 107, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 112, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(bnRefresh)
.addComponent(bnCancel)
.addComponent(bnOk))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(errorLabel)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void bnRefreshActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnRefreshActionPerformed
model.loadDisks();
}//GEN-LAST:event_bnRefreshActionPerformed
private void bnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOkActionPerformed
if (diskTable.getSelectedRow() >= 0 && diskTable.getSelectedRow() < disks.size()) {
LocalDisk selectedDisk = disks.get(diskTable.getSelectedRow());
drivePath = selectedDisk.getPath();
} else {
drivePath = "";
}
dispose();
}//GEN-LAST:event_bnOkActionPerformed
private void bnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnCancelActionPerformed
dispose();
}//GEN-LAST:event_bnCancelActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton bnCancel;
private javax.swing.JButton bnOk;
private javax.swing.JButton bnRefresh;
private javax.swing.JTable diskTable;
private javax.swing.JLabel errorLabel;
private javax.swing.JLabel jLabel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JSeparator jSeparator1;
private javax.swing.JTextArea jTextArea1;
// End of variables declaration//GEN-END:variables
/**
* Table model for displaying information from LocalDisk Objects in a table.
*/
@NbBundle.Messages({"SelectDriveDialog.localDiskModel.loading.msg=",
"SelectDriveDialog.localDiskModel.nodrives.msg=Executable could not be found",
"SelectDriveDialog.diskTable.column1.title=Disk Name",
"SelectDriveDialog.diskTable.column2.title=Disk Size",
"SelectDriveDialog.errLabel.disksNotDetected.text=Disks were not detected. On some systems it requires admin privileges",
"SelectDriveDialog.errLabel.disksNotDetected.toolTipText=Disks were not detected."
})
private class LocalDiskModel implements TableModel {
private LocalDiskThread worker = null;
private boolean ready = false;
private volatile boolean loadingDisks = false;
//private String SELECT = "Select a local disk:";
private final String LOADING = NbBundle.getMessage(this.getClass(), "SelectDriveDialog.localDiskModel.loading.msg");
private final String NO_DRIVES = NbBundle.getMessage(this.getClass(), "SelectDriveDialog.localDiskModel.nodrives.msg");
private void loadDisks() {
// if there is a worker already building the lists, then cancel it first.
if (loadingDisks && worker != null) {
worker.cancel(false);
}
// Clear the lists
errorLabel.setText("");
diskTable.setEnabled(false);
ready = false;
loadingDisks = true;
worker = new LocalDiskThread();
worker.execute();
}
@Override
public int getRowCount() {
if (disks.isEmpty()) {
return 0;
}
return disks.size();
}
@Override
public int getColumnCount() {
return 2;
}
@Override
public String getColumnName(int columnIndex) {
switch (columnIndex) {
case 0:
return NbBundle.getMessage(this.getClass(), "SelectDriveDialog.diskTable.column1.title");
case 1:
return NbBundle.getMessage(this.getClass(), "SelectDriveDialog.diskTable.column2.title");
default:
return "Unnamed"; //NON-NLS
}
}
@Override
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
if (ready) {
if (disks.isEmpty()) {
return NO_DRIVES;
}
switch (columnIndex) {
case 0:
return disks.get(rowIndex).getName();
case 1:
return disks.get(rowIndex).getReadableSize();
default:
return disks.get(rowIndex).getPath();
}
} else {
return LOADING;
}
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
//setter does nothing they should not be able to modify table
}
@Override
public void addTableModelListener(TableModelListener l) {
}
@Override
public void removeTableModelListener(TableModelListener l) {
}
/**
* Gets the lists of physical drives and partitions and combines them
* into a list of disks.
*/
class LocalDiskThread extends SwingWorker<Object, Void> {
private final Logger logger = Logger.getLogger(LocalDiskThread.class.getName());
private List<LocalDisk> partitions = new ArrayList<>();
@Override
protected Object doInBackground() throws Exception {
// Populate the lists
partitions = new ArrayList<>();
partitions = PlatformUtil.getPartitions();
return null;
}
/**
* Display any error messages that might of occurred when getting
* the lists of physical drives or partitions.
*/
private void displayErrors() {
if (partitions.isEmpty()) {
if (PlatformUtil.isWindowsOS()) {
errorLabel.setText(
NbBundle.getMessage(this.getClass(), "SelectDriveDialog.errLabel.disksNotDetected.text"));
errorLabel.setToolTipText(NbBundle.getMessage(this.getClass(),
"SelectDriveDialog.errLabel.disksNotDetected.toolTipText"));
} else {
errorLabel.setText(
NbBundle.getMessage(this.getClass(), "SelectDriveDialog.errLabel.drivesNotDetected.text"));
errorLabel.setToolTipText(NbBundle.getMessage(this.getClass(),
"SelectDriveDialog.errLabel.drivesNotDetected.toolTipText"));
}
errorLabel.setVisible(true);
diskTable.setEnabled(false);
}
}
@Override
protected void done() {
try {
super.get(); //block and get all exceptions thrown while doInBackground()
} catch (CancellationException ex) {
logger.log(Level.INFO, "Loading local disks was canceled."); //NON-NLS
} catch (InterruptedException ex) {
logger.log(Level.INFO, "Loading local disks was interrupted."); //NON-NLS
} catch (Exception ex) {
logger.log(Level.SEVERE, "Fatal error when loading local disks", ex); //NON-NLS
} finally {
if (!this.isCancelled()) {
displayErrors();
worker = null;
loadingDisks = false;
disks = new ArrayList<>();
disks.addAll(partitions);
if (disks.size() > 0) {
diskTable.setEnabled(true);
diskTable.clearSelection();
}
ready = true;
}
}
diskTable.revalidate();
}
}
}
}