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;
79 if (null == instance) {
88 @NbBundle.Messages({
"ExportCSV.title.text=Export selected rows to CSV"})
90 super(Bundle.ExportCSV_title_text());
102 Collection<? extends Node> selectedNodes = Utilities.actionsGlobalContext().lookupAll(Node.class);
113 "# {0} - Output file",
114 "ExportCSV.saveNodesToCSV.fileExists=File {0} already exists",
115 "ExportCSV.saveNodesToCSV.noCurrentCase=No open case available",
116 "ExportCSV.saveNodesToCSV.empty=No data to export"})
117 public static void saveNodesToCSV(Collection<? extends Node> nodesToExport, Component component) {
119 if (nodesToExport.isEmpty()) {
128 JFileChooser fileChooser =
new JFileChooser();
130 fileChooser.setSelectedFile(
new File(fileName));
131 fileChooser.setFileFilter(
new FileNameExtensionFilter(
"csv file",
"csv"));
133 int returnVal = fileChooser.showSaveDialog(component);
134 if (returnVal == JFileChooser.APPROVE_OPTION) {
137 File selectedFile = fileChooser.getSelectedFile();
138 if (!selectedFile.getName().endsWith(
".csv")) {
139 selectedFile =
new File(selectedFile.toString() +
".csv");
145 if (selectedFile.exists()) {
146 logger.log(Level.SEVERE,
"File {0} already exists", selectedFile.getAbsolutePath());
155 JOptionPane.showMessageDialog(component, Bundle.ExportCSV_saveNodesToCSV_noCurrentCase());
156 logger.log(Level.INFO,
"Exception while getting open case.", ex);
168 String dateStr = String.format(
"%1$tY%1$tm%1$te%1$tI%1$tM%1$tS", Calendar.getInstance());
170 if (parent != null) {
172 for (PropertySet set : parent.getPropertySets()) {
173 for (Property<?> prop : set.getProperties()) {
175 String parentName = prop.getValue().toString();
178 parentName = parentName.replaceAll(
"\\([0-9]+\\)$",
"");
181 parentName = parentName.replaceAll(
"[\\\\/:*?\"<>|]",
"_");
183 return parentName +
" " + dateStr;
184 }
catch (IllegalAccessException | InvocationTargetException ex) {
185 logger.log(Level.WARNING,
"Failed to get property set value as string", ex);
190 return DEFAULT_FILENAME +
" " + dateStr;
203 if (userDefinedExportPath == null) {
204 return caseExportPath;
207 File file =
new File(userDefinedExportPath);
208 if (file.exists() ==
false || file.isDirectory() ==
false) {
209 return caseExportPath;
226 userDefinedExportPath = null;
228 userDefinedExportPath = exportPath;
236 private static class CSVWriter extends SwingWorker<Object, Void> {
249 CSVWriter(Collection<? extends Node> nodesToExport, File outputFile) {
254 @NbBundle.Messages({
"CSVWriter.progress.extracting=Exporting to CSV file",
255 "CSVWriter.progress.cancelling=Cancelling"})
258 if (nodesToExport.isEmpty()) {
263 final String displayName = Bundle.CSVWriter_progress_extracting();
264 progress = ProgressHandle.createHandle(displayName,
new Cancellable() {
266 public boolean cancel() {
267 if (progress != null) {
268 progress.setDisplayName(Bundle.CSVWriter_progress_cancelling());
274 progress.switchToIndeterminate();
276 try (BufferedWriter br =
new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(outputFile), StandardCharsets.UTF_8))) {
281 List<String> headers =
new ArrayList<>();
282 PropertySet[] sets = nodesToExport.iterator().next().getPropertySets();
283 for(PropertySet set : sets) {
284 for (Property<?> prop : set.getProperties()) {
285 if ( ! columnsToSkip.contains(prop.getDisplayName())) {
286 headers.add(prop.getDisplayName());
293 Iterator<?> nodeIterator = nodesToExport.iterator();
294 while (nodeIterator.hasNext()) {
295 if (this.isCancelled()) {
299 Node node = (Node)nodeIterator.next();
300 List<String> values =
new ArrayList<>();
301 sets = node.getPropertySets();
302 for(PropertySet set : sets) {
303 for (Property<?> prop : set.getProperties()) {
304 if ( ! columnsToSkip.contains(prop.getDisplayName())) {
324 return original.replaceAll(
"\"",
"\\\\\"");
335 return "\"" + String.join(
"\",\"", values) +
"\"\n";
338 @NbBundle.Messages({
"CSVWriter.done.notifyMsg.error=Error exporting to CSV file",
339 "# {0} - Output file",
340 "CSVWriter.done.notifyMsg.success=Wrote to {0}"})
343 boolean msgDisplayed =
false;
346 }
catch (InterruptedException | ExecutionException ex) {
347 logger.log(Level.SEVERE,
"Fatal error during file extraction", ex);
350 }
catch (java.util.concurrent.CancellationException ex) {
354 if (!this.isCancelled() && !msgDisplayed) {
static ExportCSVAction instance
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)
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)