diff --git a/CHANGELOG.md b/CHANGELOG.md index 74bf6b69565..a71afa63a38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,13 +11,16 @@ 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 fetcher based on RFC-IDs. [#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) - +We fixed an issue with the migration of invalid Look and Feels [#3995, comment](https://github.com/JabRef/jabref/issues/3995#issuecomment-385649448) +We fixed an issue where JabRef would no longer start, when the option "Override default font settings" was activated [#3986](https://github.com/JabRef/jabref/issues/3986) ### Removed - - +We removed the GTK Look and Feel from the Options, as it leads to freezes in JabRef on MacOSX and Linux [#3995](https://github.com/JabRef/jabref/issues/3995) +The GTK Look and Feel is now replaced with the "Nimbus" style as default. diff --git a/src/main/java/org/jabref/JabRefGUI.java b/src/main/java/org/jabref/JabRefGUI.java index 7208b11be72..d357d786c3b 100644 --- a/src/main/java/org/jabref/JabRefGUI.java +++ b/src/main/java/org/jabref/JabRefGUI.java @@ -1,5 +1,7 @@ package org.jabref; +import java.awt.Font; +import java.awt.Frame; import java.io.File; import java.sql.SQLException; import java.util.ArrayList; @@ -42,7 +44,10 @@ public class JabRefGUI { + private static final String NIMBUS_LOOK_AND_FEEL = "javax.swing.plaf.nimbus.NimbusLookAndFeel"; private static final Logger LOGGER = LoggerFactory.getLogger(JabRefGUI.class); + private static final String GTK_LF_CLASSNAME = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel"; + private static JabRefFrame mainFrame; private final List bibDatabases; @@ -59,7 +64,10 @@ public JabRefGUI(Stage mainStage, List argsDatabases, boolean isBl this.dialogService = new FXDialogService(mainStage); // passed file (we take the first one) should be focused - focusedFile = argsDatabases.stream().findFirst().flatMap(ParserResult::getFile).map(File::getAbsolutePath) + focusedFile = argsDatabases.stream() + .findFirst() + .flatMap(ParserResult::getFile) + .map(File::getAbsolutePath) .orElse(Globals.prefs.get(JabRefPreferences.LAST_FOCUSED)); openWindow(mainStage); @@ -237,13 +245,10 @@ private void setLookAndFeel() { String systemLookFeel = UIManager.getSystemLookAndFeelClassName(); if (Globals.prefs.getBoolean(JabRefPreferences.USE_DEFAULT_LOOK_AND_FEEL)) { - // FIXME: Problems with OpenJDK and GTK L&F - // See https://github.com/JabRef/jabref/issues/393, https://github.com/JabRef/jabref/issues/638 - if (System.getProperty("java.runtime.name").contains("OpenJDK")) { - // Metal L&F - lookFeel = UIManager.getCrossPlatformLookAndFeelClassName(); - LOGGER.warn( - "There seem to be problems with OpenJDK and the default GTK Look&Feel. Using Metal L&F instead. Change to another L&F with caution."); + // FIXME: Problems with GTK L&F on Linux and Mac. Needs reevaluation for Java9 + if (GTK_LF_CLASSNAME.equals(systemLookFeel)) { + lookFeel = NIMBUS_LOOK_AND_FEEL; + LOGGER.warn("There seems to be problems with GTK Look&Feel. Using Nimbus L&F instead. Change to another L&F with caution."); } else { lookFeel = systemLookFeel; } @@ -251,11 +256,9 @@ private void setLookAndFeel() { lookFeel = Globals.prefs.get(JabRefPreferences.WIN_LOOK_AND_FEEL); } - // FIXME: Open JDK problem - if (UIManager.getCrossPlatformLookAndFeelClassName().equals(lookFeel) - && !System.getProperty("java.runtime.name").contains("OpenJDK")) { - // try to avoid ending up with the ugly Metal L&F - UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel"); + //Prevent metal l&f + if (UIManager.getCrossPlatformLookAndFeelClassName().equals(lookFeel)) { + UIManager.setLookAndFeel(NIMBUS_LOOK_AND_FEEL); } else { try { UIManager.setLookAndFeel(lookFeel); @@ -292,7 +295,7 @@ private void setLookAndFeel() { Enumeration keys = defaults.keys(); for (Object key : Collections.list(keys)) { if ((key instanceof String) && ((String) key).endsWith(".font")) { - FontUIResource font = (FontUIResource) UIManager.get(key); + Font font = (Font) UIManager.get(key); font = new FontUIResource(font.getName(), font.getStyle(), fontSize); defaults.put(key, font); } diff --git a/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java b/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java index a8ebe7dbdc8..7d2a77b38bf 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; @@ -114,6 +118,7 @@ public class FindUnlinkedFilesDialog extends JabRefDialog { private JPanel panelImportArea; private JButton buttonBrowse; private JButton buttonScan; + private JButton buttonExport; private JButton buttonApply; private JButton buttonClose; @@ -132,6 +137,7 @@ public class FindUnlinkedFilesDialog extends JabRefDialog { private JLabel labelSearchingDirectoryInfo; private JLabel labelImportingInfo; + private JLabel labelExportingInfo; private JTree tree; private JScrollPane scrollpaneTree; private JComboBox comboBoxFileTypeSelection; @@ -167,6 +173,7 @@ public FindUnlinkedFilesDialog(Frame owner, JabRefFrame frame) { initialize(); buttonApply.setEnabled(false); + buttonExport.setEnabled(false); } /** @@ -485,6 +492,7 @@ private void startImport() { progressBarImporting.setVisible(true); labelImportingInfo.setVisible(true); + buttonExport.setVisible(false); buttonApply.setVisible(false); buttonClose.setVisible(false); disOrEnableDialog(false); @@ -519,6 +527,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 @@ -540,6 +614,7 @@ private void importFinishedHandler(List errors) { progressBarImporting.setVisible(false); labelImportingInfo.setVisible(false); + buttonExport.setVisible(true); buttonApply.setVisible(true); buttonClose.setVisible(true); disOrEnableDialog(true); @@ -570,6 +645,7 @@ private void searchFinishedHandler(CheckableTreeNode rootNode) { disOrEnableDialog(true); buttonApply.setEnabled(true); + buttonExport.setEnabled(true); } /** @@ -600,8 +676,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()); } @@ -683,6 +759,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.")); @@ -725,6 +804,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(); @@ -807,6 +889,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, @@ -824,6 +908,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/java/org/jabref/gui/preftabs/AppearancePrefsTab.java b/src/main/java/org/jabref/gui/preftabs/AppearancePrefsTab.java index 59e10e24011..a860c1907ad 100644 --- a/src/main/java/org/jabref/gui/preftabs/AppearancePrefsTab.java +++ b/src/main/java/org/jabref/gui/preftabs/AppearancePrefsTab.java @@ -20,7 +20,6 @@ import org.jabref.gui.GUIGlobals; import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.util.OS; import org.jabref.preferences.JabRefPreferences; import com.jgoodies.forms.builder.DefaultFormBuilder; @@ -32,6 +31,7 @@ class AppearancePrefsTab extends JPanel implements PrefsTab { private static final Logger LOGGER = LoggerFactory.getLogger(AppearancePrefsTab.class); + private static final String GTK_LF_CLASSNAME = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel"; private final JabRefPreferences prefs; @@ -56,7 +56,10 @@ class AppearancePrefsTab extends JPanel implements PrefsTab { static class LookAndFeel { public static Set getAvailableLookAndFeels() { - return Arrays.stream(UIManager.getInstalledLookAndFeels()).map(LookAndFeelInfo::getClassName).collect(Collectors.toSet()); + return Arrays.stream(UIManager.getInstalledLookAndFeels()) + .map(LookAndFeelInfo::getClassName) + .filter(style -> !GTK_LF_CLASSNAME.equals(style)) + .collect(Collectors.toSet()); } } @@ -86,44 +89,46 @@ public AppearancePrefsTab(DialogService dialogService, JabRefPreferences prefs) fxFontTweaksLAF = new JCheckBox(Localization.lang("Tweak font rendering for entry editor on Linux")); // Only list L&F which are available Set lookAndFeels = LookAndFeel.getAvailableLookAndFeels(); + classNamesLAF = new JComboBox<>(lookAndFeels.toArray(new String[lookAndFeels.size()])); classNamesLAF.setEditable(true); customLAF.addChangeListener(e -> classNamesLAF.setEnabled(((JCheckBox) e.getSource()).isSelected())); - // only the default L&F shows the OSX specific first drop-down menu - if (!OS.OS_X) { - JPanel pan = new JPanel(); - builder.appendSeparator(Localization.lang("Look and feel")); - JLabel lab = new JLabel( - Localization.lang("Default look and feel") + ": " + UIManager.getSystemLookAndFeelClassName()); - builder.nextLine(); - builder.append(pan); - builder.append(lab); - builder.nextLine(); - builder.append(pan); - builder.append(customLAF); - builder.nextLine(); - builder.append(pan); - JPanel pan2 = new JPanel(); - lab = new JLabel(Localization.lang("Class name") + ':'); - pan2.add(lab); - pan2.add(classNamesLAF); - builder.append(pan2); - builder.nextLine(); - builder.append(pan); - lab = new JLabel(Localization - .lang("Note that you must specify the fully qualified class name for the look and feel,")); - builder.append(lab); - builder.nextLine(); - builder.append(pan); - lab = new JLabel( - Localization.lang("and the class must be available in your classpath next time you start JabRef.")); - builder.append(lab); - builder.nextLine(); - builder.append(pan); - builder.append(fxFontTweaksLAF); - builder.nextLine(); - } + colorPanel = new ColorSetupPanel(colorCodes, resolvedColorCodes, showGrid); + + + JPanel pan = new JPanel(); + builder.appendSeparator(Localization.lang("Look and feel")); + JLabel lab = new JLabel( + Localization.lang("Default look and feel") + ": " + UIManager.getSystemLookAndFeelClassName()); + builder.nextLine(); + builder.append(pan); + builder.append(lab); + builder.nextLine(); + builder.append(pan); + builder.append(customLAF); + builder.nextLine(); + builder.append(pan); + JPanel pan2 = new JPanel(); + lab = new JLabel(Localization.lang("Class name") + ':'); + pan2.add(lab); + pan2.add(classNamesLAF); + builder.append(pan2); + builder.nextLine(); + builder.append(pan); + lab = new JLabel(Localization + .lang("Note that you must specify the fully qualified class name for the look and feel,")); + builder.append(lab); + builder.nextLine(); + builder.append(pan); + lab = new JLabel( + Localization.lang("and the class must be available in your classpath next time you start JabRef.")); + builder.append(lab); + builder.nextLine(); + builder.append(pan); + builder.append(fxFontTweaksLAF); + builder.nextLine(); + builder.leadingColumnOffset(2); @@ -162,9 +167,12 @@ public AppearancePrefsTab(DialogService dialogService, JabRefPreferences prefs) overrideFonts.addActionListener(e -> largeIconsTextField.setEnabled(overrideFonts.isSelected())); overrideFonts.addActionListener(e -> smallIconsTextField.setEnabled(overrideFonts.isSelected())); - JPanel pan = builder.getPanel(); - pan.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - add(pan, BorderLayout.CENTER); + fontButton.addActionListener( + e -> new FontSelectorDialog(null, usedFont).getSelectedFont().ifPresent(x -> usedFont = x)); + + JPanel panel = builder.getPanel(); + panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + add(panel, BorderLayout.CENTER); } @Override diff --git a/src/main/java/org/jabref/migrations/PreferencesMigrations.java b/src/main/java/org/jabref/migrations/PreferencesMigrations.java index 30c6a8066f9..8b5b6a984dc 100644 --- a/src/main/java/org/jabref/migrations/PreferencesMigrations.java +++ b/src/main/java/org/jabref/migrations/PreferencesMigrations.java @@ -9,6 +9,7 @@ import java.util.function.UnaryOperator; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; +import java.util.stream.Stream; import org.jabref.Globals; import org.jabref.JabRefMain; @@ -198,7 +199,7 @@ private static void migrateFileImportPattern(String oldStylePattern, String newS JabRefPreferences prefs, Preferences mainPrefsNode) { String preferenceFileNamePattern = mainPrefsNode.get(JabRefPreferences.IMPORT_FILENAMEPATTERN, null); - if (preferenceFileNamePattern != null && + if ((preferenceFileNamePattern != null) && oldStylePattern.equals(preferenceFileNamePattern)) { // Upgrade the old-style File Name pattern to new one: mainPrefsNode.put(JabRefPreferences.IMPORT_FILENAMEPATTERN, newStylePattern); @@ -281,17 +282,22 @@ private static void migrateTypedKeyPrefs(JabRefPreferences prefs, Preferences ol public static void upgradeObsoleteLookAndFeels() { JabRefPreferences prefs = Globals.prefs; String currentLandF = prefs.get(JabRefPreferences.WIN_LOOK_AND_FEEL); - if ("com.jgoodies.looks.windows.WindowsLookAndFeel".equals(currentLandF) || - "com.jgoodies.plaf.plastic.Plastic3DLookAndFeel".equals(currentLandF)) { - if (OS.WINDOWS) { - String windowsLandF = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"; - prefs.put(JabRefPreferences.WIN_LOOK_AND_FEEL, windowsLandF); - LOGGER.info("Switched from obsolete look and feel " + currentLandF + " to " + windowsLandF); - } else { - String nimbusLandF = "javax.swing.plaf.nimbus.NimbusLookAndFeel"; - prefs.put(JabRefPreferences.WIN_LOOK_AND_FEEL, nimbusLandF); - LOGGER.info("Switched from obsolete look and feel " + currentLandF + " to " + nimbusLandF); - } - } + + Stream.of("com.jgoodies.looks.windows.WindowsLookAndFeel", "com.jgoodies.looks.plastic.PlasticLookAndFeel", + "com.jgoodies.looks.plastic.Plastic3DLookAndFeel", "com.jgoodies.looks.plastic.PlasticXPLookAndFeel", + "com.sun.java.swing.plaf.gtk.GTKLookAndFeel") + .filter(style -> style.equals(currentLandF)) + .findAny() + .ifPresent(loolAndFeel -> { + if (OS.WINDOWS) { + String windowsLandF = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"; + prefs.put(JabRefPreferences.WIN_LOOK_AND_FEEL, windowsLandF); + LOGGER.info("Switched from obsolete look and feel " + currentLandF + " to " + windowsLandF); + } else { + String nimbusLandF = "javax.swing.plaf.nimbus.NimbusLookAndFeel"; + prefs.put(JabRefPreferences.WIN_LOOK_AND_FEEL, nimbusLandF); + LOGGER.info("Switched from obsolete look and feel " + currentLandF + " to " + nimbusLandF); + } + }); } } diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 99fe13d20a9..35f45b3680d 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -430,6 +430,8 @@ Export\ properties=Export properties Export\ to\ clipboard=Export to clipboard +Export\ to\ text\ file.=Export to text file. + Exporting=Exporting Extension=Extension @@ -1563,6 +1565,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 diff --git a/src/main/resources/l10n/JabRef_fr.properties b/src/main/resources/l10n/JabRef_fr.properties index bcc9efa1fc9..2dbfab36e87 100644 --- a/src/main/resources/l10n/JabRef_fr.properties +++ b/src/main/resources/l10n/JabRef_fr.properties @@ -448,6 +448,8 @@ Export\ properties=Propriétés de l'exportation Export\ to\ clipboard=Exporter vers le presse-papiers +Export\ to\ text\ file.=Exporter vers un fichier texte. + Exporting=Exportation en cours Extension=Extension @@ -1585,6 +1587,7 @@ These\ files\ are\ not\ linked\ in\ the\ active\ library.=Ces fichiers ne sont p Entry\ type\ to\ be\ created\:=Type d'entrée à créer \: Searching\ file\ system...=Recherche dans le système de fichiers... Importing\ into\ Library...=Importation dans un fichier... +Exporting\ into\ file...=Exportation vers un fichier... Select\ directory=Sélectionner un répertoire Select\ files=Sélectionner des fichiers BibTeX\ entry\ creation=Création d'un entrée BibTeX