diff --git a/CHANGELOG.md b/CHANGELOG.md index 74bf6b69565..aecdbc770d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,9 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# ## [Unreleased] ### Changed -We added RFC, a new entry generator ID type. [#3971](https://github.com/JabRef/jabref/issues/3971) +- We added a text file export for 'Find Unlinked Files'. [#3341](https://github.com/JabRef/jabref/issues/3341) +- We added a new entry generator ID type. [#3971](https://github.com/JabRef/jabref/issues/3971) + ### Fixed We fixed an issue where the export to clipboard functionality could not be invoked [#3994](https://github.com/JabRef/jabref/issues/3994) diff --git a/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java b/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java index cdab1ab29c8..aea7055cf98 100644 --- a/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java +++ b/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java @@ -18,12 +18,15 @@ import java.awt.event.MouseListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; +import java.io.BufferedWriter; import java.io.File; import java.io.FileFilter; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; @@ -74,6 +77,7 @@ import org.jabref.gui.importer.UnlinkedPDFFileFilter; import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.gui.util.DirectoryDialogConfiguration; +import org.jabref.gui.util.FileDialogConfiguration; import org.jabref.logic.l10n.Localization; import org.jabref.model.EntryTypes; import org.jabref.model.database.BibDatabaseContext; @@ -123,6 +127,7 @@ public class FindUnlinkedFilesDialog extends JabRefDialog { private JPanel panelImportArea; private JButton buttonBrowse; private JButton buttonScan; + private JButton buttonExport; private JButton buttonApply; private JButton buttonClose; @@ -141,6 +146,7 @@ public class FindUnlinkedFilesDialog extends JabRefDialog { private JLabel labelSearchingDirectoryInfo; private JLabel labelImportingInfo; + private JLabel labelExportingInfo; private JTree tree; private JScrollPane scrollpaneTree; private JComboBox comboBoxFileTypeSelection; @@ -175,6 +181,7 @@ public FindUnlinkedFilesDialog(Frame owner, JabRefFrame frame, BasePanel panel) initialize(); buttonApply.setEnabled(false); + buttonExport.setEnabled(false); } /** @@ -493,6 +500,7 @@ private void startImport() { progressBarImporting.setVisible(true); labelImportingInfo.setVisible(true); + buttonExport.setVisible(false); buttonApply.setVisible(false); buttonClose.setVisible(false); disOrEnableDialog(false); @@ -527,6 +535,72 @@ public void stateChanged(ChangeEvent e) { }); } + /** + * This starts the export of all files of all selected nodes in this + * dialogs tree view.
+ *
+ * The export itself will run in a seperate thread, whilst this dialog will + * be showing a progress bar, until the thread has finished its work.
+ *
+ * When the export has finished, the {@link #exportFinishedHandler()} is + * invoked. + */ + private void startExport() { + if (treeModel == null) { + return; + } + setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + + CheckableTreeNode root = (CheckableTreeNode) treeModel.getRoot(); + + final List fileList = getFileListFromNode(root); + if ((fileList == null) || fileList.isEmpty()) { + return; + } + + buttonExport.setVisible(false); + buttonApply.setVisible(false); + buttonClose.setVisible(false); + disOrEnableDialog(false); + + FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder() + .withInitialDirectory(Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY)).build(); + DialogService ds = new FXDialogService(); + + Optional exportPath = DefaultTaskExecutor + .runInJavaFXThread(() -> ds.showFileSaveDialog(fileDialogConfiguration)); + + if (!exportPath.isPresent()) { + exportFinishedHandler(); + return; + } + + threadState.set(true); + JabRefExecutorService.INSTANCE.execute(() -> { + try (BufferedWriter writer = + Files.newBufferedWriter(exportPath.get(), StandardCharsets.UTF_8, + StandardOpenOption.CREATE)) { + for (File file : fileList) { + writer.write(file.toString() + "\n"); + } + + } catch (IOException e) { + LOGGER.warn("IO Error.", e); + } + }); + + exportFinishedHandler(); + } + + private void exportFinishedHandler() { + buttonExport.setVisible(true); + buttonApply.setVisible(true); + buttonClose.setVisible(true); + disOrEnableDialog(true); + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frame.getCurrentBasePanel().markBaseChanged(); + } + /** * * @param errors @@ -548,6 +622,7 @@ private void importFinishedHandler(List errors) { progressBarImporting.setVisible(false); labelImportingInfo.setVisible(false); + buttonExport.setVisible(true); buttonApply.setVisible(true); buttonClose.setVisible(true); disOrEnableDialog(true); @@ -578,6 +653,7 @@ private void searchFinishedHandler(CheckableTreeNode rootNode) { disOrEnableDialog(true); buttonApply.setEnabled(true); + buttonExport.setEnabled(true); } /** @@ -608,8 +684,8 @@ private void setupActions() { * Actions on this button will start the import of all file of all * selected nodes in this dialogs tree view.
*/ - ActionListener actionListenerImportEntrys = e -> startImport(); - buttonApply.addActionListener(actionListenerImportEntrys); + buttonExport.addActionListener(e -> startExport()); + buttonApply.addActionListener(e -> startImport()); buttonClose.addActionListener(e -> dispose()); } @@ -691,6 +767,9 @@ public void windowClosing(WindowEvent e) { buttonScan = new JButton(Localization.lang("Scan directory")); buttonScan.setMnemonic('S'); buttonScan.setToolTipText(Localization.lang("Searches the selected directory for unlinked files.")); + buttonExport = new JButton(Localization.lang("Export")); + buttonExport.setMnemonic('E'); + buttonExport.setToolTipText(Localization.lang("Export to text file.")); buttonApply = new JButton(Localization.lang("Apply")); buttonApply.setMnemonic('I'); buttonApply.setToolTipText(Localization.lang("Starts the import of BibTeX entries.")); @@ -733,6 +812,9 @@ public void windowClosing(WindowEvent e) { labelImportingInfo = new JLabel(Localization.lang("Importing into Library...")); labelImportingInfo.setHorizontalAlignment(SwingConstants.CENTER); labelImportingInfo.setVisible(false); + labelExportingInfo = new JLabel(Localization.lang("Exporting into file...")); + labelExportingInfo.setHorizontalAlignment(SwingConstants.CENTER); + labelExportingInfo.setVisible(false); tree = new JTree(); @@ -815,6 +897,8 @@ GridBagConstraints.HORIZONTAL, GridBagConstraints.WEST, new Insets(18, 3, 18, 6) GridBagConstraints.HORIZONTAL, GridBagConstraints.WEST, basicInsets, 0, 1, 2, 1, 0, 0, 0, 0); FindUnlinkedFilesDialog.addComponent(gbl, panelImportArea, labelImportingInfo, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(6, 6, 0, 6), 0, 1, 1, 1, 1, 0, 0, 0); + FindUnlinkedFilesDialog.addComponent(gbl, panelImportArea, labelExportingInfo, GridBagConstraints.HORIZONTAL, + GridBagConstraints.CENTER, new Insets(6, 6, 0, 6), 0, 1, 1, 1, 1, 0, 0, 0); FindUnlinkedFilesDialog.addComponent(gbl, panelImportArea, progressBarImporting, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(0, 6, 6, 6), 0, 2, 1, 1, 1, 0, 0, 0); FindUnlinkedFilesDialog.addComponent(gbl, panelButtons, panelImportArea, GridBagConstraints.NONE, @@ -832,6 +916,7 @@ GridBagConstraints.HORIZONTAL, GridBagConstraints.SOUTHWEST, new Insets(12, 6, 2 ButtonBarBuilder bb = new ButtonBarBuilder(); bb.addGlue(); + bb.addButton(buttonExport); bb.addButton(buttonApply); bb.addButton(buttonClose); bb.addGlue(); diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 0c9ef2f7893..a374292660b 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -447,6 +447,8 @@ Export\ properties=Export properties Export\ to\ clipboard=Export to clipboard +Export\ to\ text\ file.=Export to text file. + Exporting=Exporting Extension=Extension @@ -1584,6 +1586,7 @@ These\ files\ are\ not\ linked\ in\ the\ active\ library.=These files are not li Entry\ type\ to\ be\ created\:=Entry type to be created: Searching\ file\ system...=Searching file system... Importing\ into\ Library...=Importing into Library... +Exporting\ into\ file...=Exporting into file... Select\ directory=Select directory Select\ files=Select files BibTeX\ entry\ creation=BibTeX entry creation