19 package org.sleuthkit.autopsy.directorytree;
 
   21 import java.awt.Component;
 
   22 import java.awt.event.ActionEvent;
 
   24 import java.io.BufferedWriter;
 
   25 import java.io.FileOutputStream;
 
   26 import java.io.OutputStreamWriter;
 
   27 import java.lang.reflect.InvocationTargetException;
 
   28 import java.nio.charset.StandardCharsets;
 
   29 import java.util.ArrayList;
 
   30 import java.util.Arrays;
 
   31 import java.util.Calendar;
 
   32 import java.util.Collection;
 
   33 import java.util.Iterator;
 
   34 import java.util.List;
 
   35 import java.util.concurrent.ExecutionException;
 
   36 import java.util.logging.Level;
 
   37 import javax.swing.AbstractAction;
 
   38 import javax.swing.JFileChooser;
 
   39 import javax.swing.JOptionPane;
 
   40 import javax.swing.SwingWorker;
 
   41 import javax.swing.filechooser.FileNameExtensionFilter;
 
   42 import org.netbeans.api.progress.ProgressHandle;
 
   43 import org.openide.util.Cancellable;
 
   44 import org.openide.util.NbBundle;
 
   45 import org.openide.util.Utilities;
 
   51 import org.openide.nodes.Node;
 
   52 import org.openide.nodes.Node.PropertySet;
 
   53 import org.openide.nodes.Node.Property;
 
   82         if (null == instance) {
 
   91     @NbBundle.Messages({
"ExportCSV.title.text=Export Selected Rows to CSV"})
 
   93         super(Bundle.ExportCSV_title_text());
 
  105         Collection<? extends Node> selectedNodes = Utilities.actionsGlobalContext().lookupAll(Node.class);
 
  116         "# {0} - Output file",
 
  117         "ExportCSV.saveNodesToCSV.fileExists=File {0} already exists",
 
  118         "ExportCSV.saveNodesToCSV.noCurrentCase=No open case available",
 
  119         "ExportCSV.saveNodesToCSV.empty=No data to export"})
 
  120     public static void saveNodesToCSV(Collection<? extends Node> nodesToExport, Component component) {
 
  122         if (nodesToExport.isEmpty()) {
 
  131             JFileChooser fileChooser = chooserHelper.
getChooser();
 
  133             fileChooser.setSelectedFile(
new File(fileName));
 
  134             fileChooser.setFileFilter(
new FileNameExtensionFilter(
"csv file", 
"csv"));
 
  136             int returnVal = fileChooser.showSaveDialog(component);
 
  137             if (returnVal == JFileChooser.APPROVE_OPTION) {
 
  140                 File selectedFile = fileChooser.getSelectedFile();
 
  141                 if (!selectedFile.getName().endsWith(
".csv")) { 
 
  142                     selectedFile = 
new File(selectedFile.toString() + 
".csv"); 
 
  148                 if (selectedFile.exists()) {
 
  149                     logger.log(Level.SEVERE, 
"File {0} already exists", selectedFile.getAbsolutePath()); 
 
  158             JOptionPane.showMessageDialog(component, Bundle.ExportCSV_saveNodesToCSV_noCurrentCase());
 
  159             logger.log(Level.INFO, 
"Exception while getting open case.", ex); 
 
  171         String dateStr = String.format(
"%1$tY%1$tm%1$te%1$tI%1$tM%1$tS", Calendar.getInstance());
 
  173         if (parent != null) {
 
  175             for (PropertySet set : parent.getPropertySets()) {
 
  176                 for (Property<?> prop : set.getProperties()) {
 
  178                         String parentName = prop.getValue().toString();
 
  181                         parentName = parentName.replaceAll(
"\\([0-9]+\\)$", 
"");
 
  184                         parentName = parentName.replaceAll(
"[\\\\/:*?\"<>|]", 
"_");
 
  186                         return parentName + 
" " + dateStr;
 
  187                     } 
catch (IllegalAccessException | InvocationTargetException ex) {
 
  188                         logger.log(Level.WARNING, 
"Failed to get property set value as string", ex);
 
  193         return DEFAULT_FILENAME + 
" " + dateStr;
 
  206         if (userDefinedExportPath == null) {
 
  207             return caseExportPath;
 
  210         File file = 
new File(userDefinedExportPath);
 
  211         if (file.exists() == 
false || file.isDirectory() == 
false) {
 
  212             return caseExportPath;
 
  229             userDefinedExportPath = null;
 
  231             userDefinedExportPath = exportPath;
 
  239     private static class CSVWriter extends SwingWorker<Object, Void> {
 
  252         CSVWriter(Collection<? extends Node> nodesToExport, File outputFile) {
 
  257         @NbBundle.Messages({
"CSVWriter.progress.extracting=Exporting to CSV file",
 
  258             "CSVWriter.progress.cancelling=Cancelling"})
 
  261             if (nodesToExport.isEmpty()) {
 
  266             final String displayName = Bundle.CSVWriter_progress_extracting();
 
  267             progress = ProgressHandle.createHandle(displayName, 
new Cancellable() {
 
  269                 public boolean cancel() {
 
  270                     if (progress != null) {
 
  271                         progress.setDisplayName(Bundle.CSVWriter_progress_cancelling());
 
  277             progress.switchToIndeterminate();
 
  279             try (BufferedWriter br = 
new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(outputFile), StandardCharsets.UTF_8))) {
 
  284                 List<String> headers = 
new ArrayList<>();
 
  285                 PropertySet[] sets = nodesToExport.iterator().next().getPropertySets();
 
  286                 for(PropertySet set : sets) {
 
  287                     for (Property<?> prop : set.getProperties()) {
 
  288                         if ( ! columnsToSkip.contains(prop.getDisplayName())) {
 
  289                             headers.add(prop.getDisplayName());
 
  296                 Iterator<?> nodeIterator = nodesToExport.iterator();
 
  297                 while (nodeIterator.hasNext()) {
 
  298                     if (this.isCancelled()) {
 
  302                     Node node = (Node)nodeIterator.next();
 
  303                     List<String> values = 
new ArrayList<>();
 
  304                     sets = node.getPropertySets();
 
  305                     for(PropertySet set : sets) {
 
  306                         for (Property<?> prop : set.getProperties()) {
 
  307                             if ( ! columnsToSkip.contains(prop.getDisplayName())) {
 
  327             return original.replaceAll(
"\"", 
"\\\\\"");
 
  338             return "\"" + String.join(
"\",\"", values) + 
"\"\n";
 
  341         @NbBundle.Messages({
"CSVWriter.done.notifyMsg.error=Error exporting to CSV file",
 
  342             "# {0} - Output file",
 
  343             "CSVWriter.done.notifyMsg.success=Wrote to {0}"})
 
  346             boolean msgDisplayed = 
false;
 
  349             } 
catch (InterruptedException | ExecutionException ex) {
 
  350                 logger.log(Level.SEVERE, 
"Fatal error during file extraction", ex); 
 
  353             } 
catch (java.util.concurrent.CancellationException ex) {
 
  357                 if (!this.isCancelled() && !msgDisplayed) {
 
static ExportCSVAction instance
 
static final JFileChooserFactory chooserHelper
 
static String getDefaultOutputFileName(Node parent)
 
static final String DEFAULT_FILENAME
 
static final Logger logger
 
static synchronized ExportCSVAction getInstance()
 
final Collection<?extends Node > nodesToExport
 
static void updateExportDirectory(String exportPath, Case openCase)
 
static String userDefinedExportPath
 
static String getExportDirectory(Case openCase)
 
JFileChooser getChooser()
 
String escapeQuotes(String original)
 
void actionPerformed(ActionEvent e)
 
static final List< String > columnsToSkip
 
synchronized static Logger getLogger(String name)
 
static Case getCurrentCaseThrows()
 
String getExportDirectory()
 
String listToCSV(List< String > values)
 
static void info(String message)
 
static void saveNodesToCSV(Collection<?extends Node > nodesToExport, Component component)