From ba40f57297dfe2d64b24841a1878cede81d315dd Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Fri, 16 Mar 2018 17:46:59 +0100 Subject: [PATCH 01/48] fix keybinding of entry editor add missing keybinding of search --- src/main/java/org/jabref/gui/keyboard/KeyBinding.java | 5 +++-- .../java/org/jabref/gui/search/GlobalSearchBar.java | 10 +++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jabref/gui/keyboard/KeyBinding.java b/src/main/java/org/jabref/gui/keyboard/KeyBinding.java index 38cc8ac78a6..7d43191a679 100644 --- a/src/main/java/org/jabref/gui/keyboard/KeyBinding.java +++ b/src/main/java/org/jabref/gui/keyboard/KeyBinding.java @@ -12,7 +12,7 @@ public enum KeyBinding { CLEANUP("Cleanup", Localization.lang("Cleanup entries"), "alt+F8", KeyBindingCategory.QUALITY), CLOSE_DATABASE("Close library", Localization.lang("Close library"), "ctrl+W", KeyBindingCategory.FILE), CLOSE_DIALOG("Close dialog", Localization.lang("Close dialog"), "ESCAPE", KeyBindingCategory.FILE), - CLOSE_ENTRY_EDITOR("Close entry editor", Localization.lang("Close entry editor"), "ESCAPE", KeyBindingCategory.VIEW), + CLOSE_ENTRY_EDITOR("Close entry editor", Localization.lang("Close entry editor"), "ESC", KeyBindingCategory.VIEW), COPY("Copy", Localization.lang("Copy"), "ctrl+C", KeyBindingCategory.EDIT), COPY_TITLE("Copy title", Localization.lang("Copy title"), "ctrl+shift+alt+T", KeyBindingCategory.EDIT), COPY_CITE_BIBTEX_KEY("Copy \\cite{BibTeX key}", Localization.lang("Copy \\cite{BibTeX key}"), "ctrl+K", KeyBindingCategory.EDIT), @@ -87,7 +87,8 @@ public enum KeyBinding { UNABBREVIATE("Unabbreviate", Localization.lang("Unabbreviate"), "ctrl+alt+shift+A", KeyBindingCategory.TOOLS), UNDO("Undo", Localization.lang("Undo"), "ctrl+Z", KeyBindingCategory.EDIT), WEB_SEARCH("Web search", Localization.lang("Web search"), "alt+4", KeyBindingCategory.SEARCH), - WRITE_XMP("Write XMP", Localization.lang("Write XMP"), "F6", KeyBindingCategory.TOOLS); + WRITE_XMP("Write XMP", Localization.lang("Write XMP"), "F6", KeyBindingCategory.TOOLS), + CLEAR_SEARCH("Clear search", Localization.lang("Clear search"), "ESC", KeyBindingCategory.SEARCH); private final String constant; private final String localization; diff --git a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java index a6839a1e975..a42b2fe82ea 100644 --- a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java +++ b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java @@ -27,7 +27,6 @@ import javafx.scene.control.ToolBar; import javafx.scene.control.Tooltip; import javafx.scene.control.cell.TextFieldListCell; -import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import javafx.scene.input.MouseButton; import javafx.scene.layout.BorderPane; @@ -135,7 +134,7 @@ public void actionPerformed(ActionEvent e) { */ KeyBindingRepository keyBindingRepository = Globals.getKeyPrefs(); - addEventFilter(KeyEvent.KEY_PRESSED, event -> { + searchField.addEventFilter(KeyEvent.KEY_PRESSED, event -> { Optional keyBinding = keyBindingRepository.mapToKeyBinding(event); if (keyBinding.isPresent()) { if (keyBinding.get().equals(KeyBinding.GLOBAL_SEARCH)) { @@ -143,10 +142,12 @@ public void actionPerformed(ActionEvent e) { searchPreferences.setGlobalSearch(globalSearch.isSelected()); updateOpenCurrentResultsTooltip(globalSearch.isSelected()); focus(); + event.consume(); } else if (keyBinding.get().equals(KeyBinding.CLEAR_SEARCH)) { // Clear search and select first entry, if available clearSearch(); frame.getCurrentBasePanel().getMainTable().getSelectionModel().selectFirst(); + event.consume(); } } }); @@ -211,7 +212,7 @@ public void actionPerformed(ActionEvent e) { searchField, currentResults ); - + this.setAlignment(Pos.CENTER_LEFT); } @@ -509,14 +510,17 @@ private void onSuggestionChosen(T suggestion) { } } + @Override public Node getNode() { return this.container; } + @Override public AutoCompletePopup getSkinnable() { return this.control; } + @Override public void dispose() { } } From 2c2a302a56f6b1842537ca634521e6195ad7bd16 Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Fri, 16 Mar 2018 18:02:56 +0100 Subject: [PATCH 02/48] add missing localization --- src/main/resources/l10n/JabRef_en.properties | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index f4425058d57..3c25eb0b009 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2361,3 +2361,8 @@ Undefined\ paragraph\ format=Undefined paragraph format Any\ file=Any file No\ linked\ files\ found\ for\ export.=No linked files found for export. + +Clear\ search=Clear search +Edit\ Preamble=Edit Preamble +Markings=Markings +Use\ selected\ instance=Use selected instance From db96f55c4109353928f1dd0f1e3de103e44bcc2a Mon Sep 17 00:00:00 2001 From: Stefan Kolb Date: Sat, 17 Mar 2018 00:06:12 +0100 Subject: [PATCH 03/48] Minor refactoring --- .../jabref/logic/importer/fetcher/IsbnViaEbookDeFetcher.java | 3 ++- .../org/jabref/logic/importer/fileformat/BibtexParser.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/logic/importer/fetcher/IsbnViaEbookDeFetcher.java b/src/main/java/org/jabref/logic/importer/fetcher/IsbnViaEbookDeFetcher.java index 724339724f7..f4781e2665c 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/IsbnViaEbookDeFetcher.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/IsbnViaEbookDeFetcher.java @@ -18,6 +18,7 @@ * Fetcher for ISBN using http://www.ebook.de. */ public class IsbnViaEbookDeFetcher extends AbstractIsbnFetcher { + private static final String BASE_URL = "http://www.ebook.de/de/tools/isbn2bibtex"; public IsbnViaEbookDeFetcher(ImportFormatPreferences importFormatPreferences) { super(importFormatPreferences); @@ -31,7 +32,7 @@ public String getName() { @Override public URL getURLForID(String identifier) throws URISyntaxException, MalformedURLException, FetcherException { this.ensureThatIsbnIsValid(identifier); - URIBuilder uriBuilder = new URIBuilder("http://www.ebook.de/de/tools/isbn2bibtex"); + URIBuilder uriBuilder = new URIBuilder(BASE_URL); uriBuilder.addParameter("isbn", identifier); return uriBuilder.build().toURL(); } diff --git a/src/main/java/org/jabref/logic/importer/fileformat/BibtexParser.java b/src/main/java/org/jabref/logic/importer/fileformat/BibtexParser.java index c21c37ddc8c..d9e3f5d4e83 100644 --- a/src/main/java/org/jabref/logic/importer/fileformat/BibtexParser.java +++ b/src/main/java/org/jabref/logic/importer/fileformat/BibtexParser.java @@ -58,8 +58,8 @@ * Can be used stand-alone. */ public class BibtexParser implements Parser { - private static final Logger LOGGER = LoggerFactory.getLogger(BibtexParser.class); + private static final Integer LOOKAHEAD = 64; private final FieldContentParser fieldContentParser; private final Deque pureTextFromFile = new LinkedList<>(); From 2cdf085ca094e640073774764551296ff03d1f8f Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sat, 17 Mar 2018 11:18:24 +0100 Subject: [PATCH 04/48] Provides download option in context menu and fixes #3614 (#3824) * Provides download option in context menu and fixes #3614 * Code cleanup * Fix checkstyle * Fix tests * Add java doc * Fix tests --- CHANGELOG.md | 2 + .../gui/externalfiles/FileDownloadTask.java | 4 + .../jabref/gui/fieldeditors/FieldEditors.java | 2 +- .../gui/fieldeditors/LinkedFileViewModel.java | 154 +++++++++++++++--- .../gui/fieldeditors/LinkedFilesEditor.java | 17 +- .../LinkedFilesEditorViewModel.java | 131 ++------------- .../org/jabref/gui/util/BackgroundTask.java | 21 ++- .../jabref/logic/importer/fetcher/ArXiv.java | 2 +- .../org/jabref/logic/util/io/FileUtil.java | 10 +- .../org/jabref/model/entry/LinkedFile.java | 12 ++ .../architecture/TestArchitectureTests.java | 2 + .../fieldeditors/LinkedFileViewModelTest.java | 14 +- 12 files changed, 212 insertions(+), 159 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11b9d9757dc..227667bea99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ For more details refer to the [field mapping help page](http://help.jabref.org/e - We added Facebook and Twitter icons in the toolbar to link to our [Facebook](https://www.facebook.com/JabRef/) and [Twitter](https://twitter.com/jabref_org) pages. - Renamed the _Review_ Tab into _Comments_ Tab - We no longer print empty lines when exporting an entry in RIS format [#3634](https://github.com/JabRef/jabref/issues/3634) +- We added the option to download linked URLs in the context menu in the entry editor. - We improved file saving so that hard links are now preserved when a save is performed [#2633](https://github.com/JabRef/jabref/issues/2633) - We changed the default dialog option when removing a [file link](http://help.jabref.org/en/FileLinks#adding-external-links-to-an-entry) from an entry. The new default removes the linked file from the entry instead of deleting the file from disk. [#3679](https://github.com/JabRef/jabref/issues/3679) @@ -45,6 +46,7 @@ The new default removes the linked file from the entry instead of deleting the f - We fixed an issue where pressing space caused the cursor to jump to the start of the text field. [#3471](https://github.com/JabRef/jabref/issues/3471) - We fixed the missing dot in the name of an exported file. [#3576](https://github.com/JabRef/jabref/issues/3576) - Autocompletion in the search bar can now be disabled via the preferences. [#3598](https://github.com/JabRef/jabref/issues/3598) +- We fixed an issue where the progress of an ongoing file download was not shown correctly. [#3614](https://github.com/JabRef/jabref/issues/3614) - We fixed an issue where odd linked files could not be selected in the entry editor. [#3639](https://github.com/JabRef/jabref/issues/3639) - We fixed and extended the RIS import functionality to cover more fields. [#3634](https://github.com/JabRef/jabref/issues/3634) [#2607](https://github.com/JabRef/jabref/issues/2607) - Chaining modifiers in BibTeX key pattern now works as described in the documentation. [#3648](https://github.com/JabRef/jabref/issues/3648) diff --git a/src/main/java/org/jabref/gui/externalfiles/FileDownloadTask.java b/src/main/java/org/jabref/gui/externalfiles/FileDownloadTask.java index 518d52c016f..890cd232f16 100644 --- a/src/main/java/org/jabref/gui/externalfiles/FileDownloadTask.java +++ b/src/main/java/org/jabref/gui/externalfiles/FileDownloadTask.java @@ -28,6 +28,10 @@ protected Void call() throws Exception { EasyBind.subscribe( inputStream.totalNumBytesReadProperty(), bytesRead -> updateProgress(bytesRead.longValue(), inputStream.getMaxNumBytes())); + + // Make sure directory exists since otherwise copy fails + Files.createDirectories(destination.getParent()); + Files.copy(inputStream, destination, StandardCopyOption.REPLACE_EXISTING); } diff --git a/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java b/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java index c292a009ffa..cc2b1fd32ac 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java +++ b/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java @@ -51,7 +51,7 @@ public static FieldEditorFX getForField(String fieldName, TaskExecutor taskExecu } else if (fieldExtras.contains(FieldProperty.OWNER)) { return new OwnerEditor(fieldName, preferences, suggestionProvider, fieldCheckers); } else if (fieldExtras.contains(FieldProperty.FILE_EDITOR)) { - return new LinkedFilesEditor(fieldName, dialogService, databaseContext, taskExecutor, suggestionProvider, fieldCheckers); + return new LinkedFilesEditor(fieldName, dialogService, databaseContext, taskExecutor, suggestionProvider, fieldCheckers, preferences); } else if (fieldExtras.contains(FieldProperty.YES_NO)) { return new OptionEditor<>(new YesNoEditorViewModel(fieldName, suggestionProvider, fieldCheckers)); } else if (fieldExtras.contains(FieldProperty.MONTH)) { diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java index 6f44cec1c8b..5e52fec8ccb 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java @@ -1,6 +1,7 @@ package org.jabref.gui.fieldeditors; import java.io.IOException; +import java.net.MalformedURLException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -17,6 +18,7 @@ import javafx.beans.property.DoubleProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleDoubleProperty; +import javafx.beans.property.StringProperty; import javafx.scene.control.Alert.AlertType; import javafx.scene.control.ButtonType; @@ -25,20 +27,28 @@ import org.jabref.gui.DialogService; import org.jabref.gui.FXDialogService; import org.jabref.gui.desktop.JabRefDesktop; +import org.jabref.gui.externalfiles.DownloadExternalFile; +import org.jabref.gui.externalfiles.FileDownloadTask; import org.jabref.gui.externalfiletype.ExternalFileType; import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.filelist.FileListEntryEditor; import org.jabref.gui.util.BackgroundTask; import org.jabref.gui.util.TaskExecutor; +import org.jabref.logic.cleanup.CleanupPreferences; import org.jabref.logic.cleanup.MoveFilesCleanup; import org.jabref.logic.cleanup.RenamePdfCleanup; +import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.logic.l10n.Localization; +import org.jabref.logic.layout.LayoutFormatterPreferences; +import org.jabref.logic.net.URLDownload; import org.jabref.logic.util.io.FileUtil; +import org.jabref.logic.xmp.XmpPreferences; import org.jabref.logic.xmp.XmpUtilWriter; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.LinkedFile; import org.jabref.model.metadata.FileDirectoryPreferences; +import org.jabref.preferences.JabRefPreferences; import de.jensd.fx.glyphs.GlyphIcons; import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon; @@ -60,20 +70,35 @@ public class LinkedFileViewModel extends AbstractViewModel { private final DialogService dialogService; private final BibEntry entry; private final TaskExecutor taskExecutor; + private final FileDirectoryPreferences fileDirectoryPreferences; + private final CleanupPreferences cleanupPreferences; + private final LayoutFormatterPreferences layoutFormatterPreferences; + private final XmpPreferences xmpPreferences; + private final String fileNamePattern; + /** + * @deprecated use {@link #LinkedFileViewModel(LinkedFile, BibEntry, BibDatabaseContext, TaskExecutor, DialogService, JabRefPreferences, JournalAbbreviationLoader)} instead + */ + @Deprecated public LinkedFileViewModel(LinkedFile linkedFile, BibEntry entry, BibDatabaseContext databaseContext, TaskExecutor taskExecutor) { - this(linkedFile, entry, databaseContext, taskExecutor, new FXDialogService()); + this(linkedFile, entry, databaseContext, taskExecutor, new FXDialogService(), Globals.prefs, Globals.journalAbbreviationLoader); } - protected LinkedFileViewModel(LinkedFile linkedFile, BibEntry entry, BibDatabaseContext databaseContext, - TaskExecutor taskExecutor, DialogService dialogService) { + public LinkedFileViewModel(LinkedFile linkedFile, BibEntry entry, BibDatabaseContext databaseContext, + TaskExecutor taskExecutor, DialogService dialogService, JabRefPreferences preferences, JournalAbbreviationLoader abbreviationLoader) { this.linkedFile = linkedFile; this.databaseContext = databaseContext; this.entry = entry; this.taskExecutor = taskExecutor; this.dialogService = dialogService; - downloadOngoing.bind(downloadProgress.greaterThanOrEqualTo(0).and(downloadProgress.lessThan(100))); + cleanupPreferences = preferences.getCleanupPreferences(abbreviationLoader); + layoutFormatterPreferences = preferences.getLayoutFormatterPreferences(abbreviationLoader); + xmpPreferences = preferences.getXMPPreferences(); + fileNamePattern = preferences.get(JabRefPreferences.IMPORT_FILENAMEPATTERN); + fileDirectoryPreferences = preferences.getFileDirectoryPreferences(); + + downloadOngoing.bind(downloadProgress.greaterThanOrEqualTo(0).and(downloadProgress.lessThan(1))); canWriteXMPMetadata.setValue(!linkedFile.isOnlineLink() && linkedFile.getFileType().equalsIgnoreCase("pdf")); } @@ -97,12 +122,12 @@ public DoubleProperty downloadProgressProperty() { return downloadProgress; } - public LinkedFile getFile() { - return linkedFile; + public StringProperty linkProperty() { + return linkedFile.linkProperty(); } - public String getLink() { - return linkedFile.getLink(); + public StringProperty descriptionProperty() { + return linkedFile.descriptionProperty(); } public String getDescription() { @@ -154,7 +179,7 @@ public void openFolder() { path = Paths.get(linkedFile.getLink()); } else { // relative to file folder - for (Path folder : databaseContext.getFileDirectoriesAsPaths(Globals.prefs.getFileDirectoryPreferences())) { + for (Path folder : databaseContext.getFileDirectoriesAsPaths(fileDirectoryPreferences)) { Path file = folder.resolve(linkedFile.getLink()); if (Files.exists(file)) { path = file; @@ -177,7 +202,7 @@ public void rename() { // Cannot rename remote links return; } - Optional fileDir = databaseContext.getFirstExistingFileDir(Globals.prefs.getFileDirectoryPreferences()); + Optional fileDir = databaseContext.getFirstExistingFileDir(fileDirectoryPreferences); if (!fileDir.isPresent()) { dialogService.showErrorDialogAndWait( Localization.lang("Rename file"), @@ -185,13 +210,13 @@ public void rename() { return; } - Optional file = linkedFile.findIn(databaseContext, Globals.prefs.getFileDirectoryPreferences()); + Optional file = linkedFile.findIn(databaseContext, fileDirectoryPreferences); if ((file.isPresent()) && Files.exists(file.get())) { RenamePdfCleanup pdfCleanup = new RenamePdfCleanup(false, databaseContext, - Globals.prefs.getCleanupPreferences(Globals.journalAbbreviationLoader).getFileNamePattern(), - Globals.prefs.getLayoutFormatterPreferences(Globals.journalAbbreviationLoader), - Globals.prefs.getFileDirectoryPreferences(), linkedFile); + cleanupPreferences.getFileNamePattern(), + layoutFormatterPreferences, + fileDirectoryPreferences, linkedFile); String targetFileName = pdfCleanup.getTargetFileName(linkedFile, entry); @@ -249,7 +274,7 @@ public void moveToDefaultDirectory() { } // Get target folder - Optional fileDir = databaseContext.getFirstExistingFileDir(Globals.prefs.getFileDirectoryPreferences()); + Optional fileDir = databaseContext.getFirstExistingFileDir(fileDirectoryPreferences); if (!fileDir.isPresent()) { dialogService.showErrorDialogAndWait( Localization.lang("Move file"), @@ -257,13 +282,13 @@ public void moveToDefaultDirectory() { return; } - Optional file = linkedFile.findIn(databaseContext, Globals.prefs.getFileDirectoryPreferences()); + Optional file = linkedFile.findIn(databaseContext, fileDirectoryPreferences); if ((file.isPresent()) && Files.exists(file.get())) { // Linked file exists, so move it MoveFilesCleanup moveFiles = new MoveFilesCleanup(databaseContext, - Globals.prefs.getCleanupPreferences(Globals.journalAbbreviationLoader).getFileDirPattern(), - Globals.prefs.getFileDirectoryPreferences(), - Globals.prefs.getLayoutFormatterPreferences(Globals.journalAbbreviationLoader), linkedFile); + cleanupPreferences.getFileDirPattern(), + fileDirectoryPreferences, + layoutFormatterPreferences, linkedFile); boolean confirm = dialogService.showConfirmationDialogAndWait( Localization.lang("Move file"), @@ -325,13 +350,13 @@ public void edit() { public void writeXMPMetadata() { // Localization.lang("Writing XMP-metadata...") BackgroundTask writeTask = BackgroundTask.wrap(() -> { - Optional file = linkedFile.findIn(databaseContext, Globals.prefs.getFileDirectoryPreferences()); + Optional file = linkedFile.findIn(databaseContext, fileDirectoryPreferences); if (!file.isPresent()) { // TODO: Print error message // Localization.lang("PDF does not exist"); } else { try { - XmpUtilWriter.writeXmp(file.get(), entry, databaseContext.getDatabase(), Globals.prefs.getXMPPreferences()); + XmpUtilWriter.writeXmp(file.get(), entry, databaseContext.getDatabase(), xmpPreferences); } catch (IOException | TransformerException ex) { // TODO: Print error message // Localization.lang("Error while writing") + " '" + file.toString() + "': " + ex; @@ -345,4 +370,91 @@ public void writeXMPMetadata() { // TODO: Show progress taskExecutor.execute(writeTask); } + + public void download() { + if (!linkedFile.isOnlineLink()) { + throw new UnsupportedOperationException("In order to download the file it has to be an online link"); + } + + try { + URLDownload urlDownload = new URLDownload(linkedFile.getLink()); + Optional suggestedType = inferFileType(urlDownload); + String suggestedTypeName = suggestedType.map(ExternalFileType::getName).orElse(""); + linkedFile.setFileType(suggestedTypeName); + + Optional targetDirectory = databaseContext.getFirstExistingFileDir(fileDirectoryPreferences); + if (!targetDirectory.isPresent()) { + dialogService.showErrorDialogAndWait( + Localization.lang("Download file"), + Localization.lang("File directory is not set or does not exist!")); + return; + } + String suffix = suggestedType.map(ExternalFileType::getExtension).orElse(""); + String suggestedName = getSuggestedFileName(suffix); + Path destination = targetDirectory.get().resolve(suggestedName); + + BackgroundTask downloadTask = new FileDownloadTask(urlDownload.getSource(), destination) + .onSuccess(event -> { + LinkedFile newLinkedFile = LinkedFilesEditorViewModel.fromFile(destination, databaseContext.getFileDirectoriesAsPaths(fileDirectoryPreferences)); + linkedFile.setLink(newLinkedFile.getLink()); + linkedFile.setFileType(newLinkedFile.getFileType()); + }) + .onFailure(ex -> dialogService.showErrorDialogAndWait("Download failed", ex)); + + downloadProgress.bind(downloadTask.workDonePercentageProperty()); + taskExecutor.execute(downloadTask); + } catch (MalformedURLException exception) { + dialogService.showErrorDialogAndWait( + Localization.lang("Invalid URL"), + exception); + } + } + + private Optional inferFileType(URLDownload urlDownload) { + Optional suggestedType = inferFileTypeFromMimeType(urlDownload); + + // If we did not find a file type from the MIME type, try based on extension: + if (!suggestedType.isPresent()) { + suggestedType = inferFileTypeFromURL(urlDownload.getSource().toExternalForm()); + } + return suggestedType; + } + + private Optional inferFileTypeFromMimeType(URLDownload urlDownload) { + try { + // TODO: what if this takes long time? + String mimeType = urlDownload.getMimeType(); // Read MIME type + if (mimeType != null) { + LOGGER.debug("MIME Type suggested: " + mimeType); + return ExternalFileTypes.getInstance().getExternalFileTypeByMimeType(mimeType); + } else { + return Optional.empty(); + } + } catch (IOException ex) { + LOGGER.debug("Error while inferring MIME type for URL " + urlDownload.getSource(), ex); + return Optional.empty(); + } + } + + private Optional inferFileTypeFromURL(String url) { + String extension = DownloadExternalFile.getSuffix(url); + if (extension != null) { + return ExternalFileTypes.getInstance().getExternalFileTypeByExt(extension); + } else { + return Optional.empty(); + } + } + + private String getSuggestedFileName(String suffix) { + String plannedName = FileUtil.createFileNameFromPattern(databaseContext.getDatabase(), entry, fileNamePattern); + + if (!suffix.isEmpty()) { + plannedName += "." + suffix; + } + return plannedName; + } + + public LinkedFile getFile() { + return linkedFile; + } } diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java index 306bb3b148c..5396bba3d4e 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java @@ -41,6 +41,7 @@ import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.LinkedFile; +import org.jabref.preferences.JabRefPreferences; import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon; import de.jensd.fx.glyphs.materialdesignicons.utils.MaterialDesignIconFactory; @@ -50,8 +51,8 @@ public class LinkedFilesEditor extends HBox implements FieldEditorFX { @FXML private final LinkedFilesEditorViewModel viewModel; @FXML private ListView listView; - public LinkedFilesEditor(String fieldName, DialogService dialogService, BibDatabaseContext databaseContext, TaskExecutor taskExecutor, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { - this.viewModel = new LinkedFilesEditorViewModel(fieldName, suggestionProvider, dialogService, databaseContext, taskExecutor, fieldCheckers); + public LinkedFilesEditor(String fieldName, DialogService dialogService, BibDatabaseContext databaseContext, TaskExecutor taskExecutor, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers, JabRefPreferences preferences) { + this.viewModel = new LinkedFilesEditorViewModel(fieldName, suggestionProvider, dialogService, databaseContext, taskExecutor, fieldCheckers, preferences); ControlHelper.loadFXMLForControl(this); @@ -150,8 +151,10 @@ private void handleOnDragDropped(LinkedFileViewModel originalItem, DragEvent eve private static Node createFileDisplay(LinkedFileViewModel linkedFile) { Text icon = MaterialDesignIconFactory.get().createIcon(linkedFile.getTypeIcon()); icon.setOnMouseClicked(event -> linkedFile.open()); - Text link = new Text(linkedFile.getLink()); - Text desc = new Text(linkedFile.getDescription()); + Text link = new Text(); + link.textProperty().bind(linkedFile.linkProperty()); + Text desc = new Text(); + desc.textProperty().bind(linkedFile.descriptionProperty()); ProgressBar progressIndicator = new ProgressBar(); progressIndicator.progressProperty().bind(linkedFile.downloadProgressProperty()); @@ -242,6 +245,9 @@ private ContextMenu createContextMenuForFile(LinkedFileViewModel linkedFile) { MenuItem openFolder = new MenuItem(Localization.lang("Open folder")); openFolder.setOnAction(event -> linkedFile.openFolder()); + MenuItem download = new MenuItem(Localization.lang("Download file")); + download.setOnAction(event -> linkedFile.download()); + MenuItem renameFile = new MenuItem(Localization.lang("Rename file")); renameFile.setOnAction(event -> linkedFile.rename()); renameFile.setDisable(linkedFile.getFile().isOnlineLink()); @@ -261,6 +267,9 @@ private ContextMenu createContextMenuForFile(LinkedFileViewModel linkedFile) { menu.getItems().add(new SeparatorMenuItem()); menu.getItems().addAll(openFile, openFolder); menu.getItems().add(new SeparatorMenuItem()); + if (linkedFile.getFile().isOnlineLink()) { + menu.getItems().add(download); + } menu.getItems().addAll(renameFile, moveFile, deleteLink, deleteFile); return menu; diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java index 6db271022c6..75844815286 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java @@ -17,12 +17,9 @@ import javafx.collections.FXCollections; import javafx.collections.ObservableList; -import org.jabref.Globals; import org.jabref.gui.DialogService; import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; import org.jabref.gui.externalfiles.AutoSetFileLinksUtil; -import org.jabref.gui.externalfiles.DownloadExternalFile; -import org.jabref.gui.externalfiles.FileDownloadTask; import org.jabref.gui.externalfiletype.ExternalFileType; import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.externalfiletype.UnknownExternalFileType; @@ -33,8 +30,6 @@ import org.jabref.logic.importer.FulltextFetchers; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.net.URLDownload; -import org.jabref.logic.util.OS; import org.jabref.logic.util.io.FileUtil; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; @@ -44,25 +39,23 @@ import org.jabref.model.util.FileHelper; import org.jabref.preferences.JabRefPreferences; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - public class LinkedFilesEditorViewModel extends AbstractEditorViewModel { - private static final Logger LOGGER = LoggerFactory.getLogger(LinkedFilesEditorViewModel.class); - private final ListProperty files = new SimpleListProperty<>(FXCollections.observableArrayList(LinkedFileViewModel::getObservables)); private final BooleanProperty fulltextLookupInProgress = new SimpleBooleanProperty(false); private final DialogService dialogService; private final BibDatabaseContext databaseContext; private final TaskExecutor taskExecutor; + private final JabRefPreferences preferences; - public LinkedFilesEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, DialogService dialogService, BibDatabaseContext databaseContext, TaskExecutor taskExecutor, FieldCheckers fieldCheckers) { + public LinkedFilesEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, DialogService dialogService, BibDatabaseContext databaseContext, TaskExecutor taskExecutor, FieldCheckers fieldCheckers, JabRefPreferences preferences) { super(fieldName, suggestionProvider, fieldCheckers); this.dialogService = dialogService; this.databaseContext = databaseContext; this.taskExecutor = taskExecutor; + this.preferences = preferences; + BindingsHelper.bindContentBidirectional( files, text, @@ -86,7 +79,7 @@ private static String getStringRepresentation(List files) { * * TODO: Move this method to {@link LinkedFile} as soon as {@link ExternalFileType} lives in model. */ - private static LinkedFile fromFile(Path file, List fileDirectories) { + public static LinkedFile fromFile(Path file, List fileDirectories) { String fileExtension = FileHelper.getFileExtension(file).orElse(""); ExternalFileType suggestedFileType = ExternalFileTypes.getInstance() .getExternalFileTypeByExt(fileExtension) @@ -96,7 +89,7 @@ private static LinkedFile fromFile(Path file, List fileDirectories) { } public LinkedFileViewModel fromFile(Path file) { - List fileDirectories = databaseContext.getFileDirectoriesAsPaths(Globals.prefs.getFileDirectoryPreferences()); + List fileDirectories = databaseContext.getFileDirectoriesAsPaths(preferences.getFileDirectoryPreferences()); LinkedFile linkedFile = fromFile(file, fileDirectories); return new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor); @@ -127,14 +120,14 @@ public ListProperty filesProperty() { } public void addNewFile() { - Path workingDirectory = databaseContext.getFirstExistingFileDir(Globals.prefs.getFileDirectoryPreferences()) - .orElse(Paths.get(Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY))); + Path workingDirectory = databaseContext.getFirstExistingFileDir(preferences.getFileDirectoryPreferences()) + .orElse(Paths.get(preferences.get(JabRefPreferences.WORKING_DIRECTORY))); FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder() .withInitialDirectory(workingDirectory) .build(); - List fileDirectories = databaseContext.getFileDirectoriesAsPaths(Globals.prefs.getFileDirectoryPreferences()); + List fileDirectories = databaseContext.getFileDirectoriesAsPaths(preferences.getFileDirectoryPreferences()); dialogService.showFileOpenDialog(fileDialogConfiguration).ifPresent( newFile -> { LinkedFile newLinkedFile = fromFile(newFile, fileDirectories); @@ -149,7 +142,7 @@ public void bindToEntry(BibEntry entry) { if (entry != null) { BackgroundTask> findAssociatedNotLinkedFiles = BackgroundTask .wrap(() -> findAssociatedNotLinkedFiles(entry)) - .onSuccess(newFiles -> files.addAll(newFiles)); + .onSuccess(files::addAll); taskExecutor.execute(findAssociatedNotLinkedFiles); } } @@ -160,7 +153,7 @@ public void bindToEntry(BibEntry entry) { private List findAssociatedNotLinkedFiles(BibEntry entry) { List result = new ArrayList<>(); - AutoSetFileLinksUtil util = new AutoSetFileLinksUtil(databaseContext, Globals.prefs.getFileDirectoryPreferences(), Globals.prefs.getAutoLinkPreferences(), ExternalFileTypes.getInstance()); + AutoSetFileLinksUtil util = new AutoSetFileLinksUtil(databaseContext, preferences.getFileDirectoryPreferences(), preferences.getAutoLinkPreferences(), ExternalFileTypes.getInstance()); try { List linkedFiles = util.findAssociatedNotLinkedFiles(entry); for (LinkedFile linkedFile : linkedFiles) { @@ -176,7 +169,7 @@ private List findAssociatedNotLinkedFiles(BibEntry entry) { } public void fetchFulltext() { - FulltextFetchers fetcher = new FulltextFetchers(Globals.prefs.getImportFormatPreferences()); + FulltextFetchers fetcher = new FulltextFetchers(preferences.getImportFormatPreferences()); BackgroundTask .wrap(() -> fetcher.findFullTextPDF(entry)) .onRunning(() -> fulltextLookupInProgress.setValue(true)) @@ -207,107 +200,17 @@ public void addFromURL() { } private void addFromURL(URL url) { - URLDownload urlDownload = new URLDownload(url); - - Optional suggestedType = inferFileType(urlDownload); - String suggestedTypeName = suggestedType.map(ExternalFileType::getName).orElse(""); - List fileDirectories = databaseContext.getFileDirectoriesAsPaths(Globals.prefs.getFileDirectoryPreferences()); - Path destination = constructSuggestedPath(suggestedType, fileDirectories); - - LinkedFileViewModel temporaryDownloadFile = new LinkedFileViewModel( - new LinkedFile("", url, suggestedTypeName), entry, databaseContext, taskExecutor); - files.add(temporaryDownloadFile); - BackgroundTask downloadTask = new FileDownloadTask(url, destination) - .onSuccess(event -> { - files.remove(temporaryDownloadFile); - LinkedFile newLinkedFile = fromFile(destination, fileDirectories); - files.add(new LinkedFileViewModel(newLinkedFile, entry, databaseContext, taskExecutor)); - }) - .onFailure(ex -> dialogService.showErrorDialogAndWait("", ex)); - - temporaryDownloadFile.downloadProgressProperty().bind(downloadTask.workDoneProperty()); - taskExecutor.execute(downloadTask); - } - - private Optional inferFileType(URLDownload urlDownload) { - Optional suggestedType = inferFileTypeFromMimeType(urlDownload); - - // If we did not find a file type from the MIME type, try based on extension: - if (!suggestedType.isPresent()) { - suggestedType = inferFileTypeFromURL(urlDownload.getSource().toExternalForm()); - } - return suggestedType; - } - - private Path constructSuggestedPath(Optional suggestedType, List fileDirectories) { - String suffix = suggestedType.map(ExternalFileType::getExtension).orElse(""); - String suggestedName = getSuggestedFileName(suffix); - Path directory; - if (fileDirectories.isEmpty()) { - directory = null; - } else { - directory = fileDirectories.get(0); - } - final Path suggestDir = directory == null ? Paths.get(System.getProperty("user.home")) : directory; - return suggestDir.resolve(suggestedName); - } - - private Optional inferFileTypeFromMimeType(URLDownload urlDownload) { - try { - // TODO: what if this takes long time? - String mimeType = urlDownload.getMimeType(); // Read MIME type - if (mimeType != null) { - LOGGER.debug("MIME Type suggested: " + mimeType); - return ExternalFileTypes.getInstance().getExternalFileTypeByMimeType(mimeType); - } else { - return Optional.empty(); - } - } catch (IOException ex) { - LOGGER.debug("Error while inferring MIME type for URL " + urlDownload.getSource(), ex); - return Optional.empty(); - } - } - - private Optional inferFileTypeFromURL(String url) { - String extension = DownloadExternalFile.getSuffix(url); - if (extension != null) { - return ExternalFileTypes.getInstance().getExternalFileTypeByExt(extension); - } else { - return Optional.empty(); - } - } - - private String getSuggestedFileName(String suffix) { - String plannedName = FileUtil.createFileNameFromPattern(databaseContext.getDatabase(), entry, - Globals.prefs.get(JabRefPreferences.IMPORT_FILENAMEPATTERN)); - - if (!suffix.isEmpty()) { - plannedName += "." + suffix; - } - - /* - * [ 1548875 ] download pdf produces unsupported filename - * - * http://sourceforge.net/tracker/index.php?func=detail&aid=1548875&group_id=92314&atid=600306 - * FIXME: rework this! just allow alphanumeric stuff or so? - * https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#naming_conventions - * http://superuser.com/questions/358855/what-characters-are-safe-in-cross-platform-file-names-for-linux-windows-and-os - * https://support.apple.com/en-us/HT202808 - */ - if (OS.WINDOWS) { - plannedName = plannedName.replaceAll("\\?|\\*|\\<|\\>|\\||\\\"|\\:|\\.$|\\[|\\]", ""); - } else if (OS.OS_X) { - plannedName = plannedName.replace(":", ""); - } - - return plannedName; + LinkedFileViewModel onlineFile = new LinkedFileViewModel( + new LinkedFile("", url, ""), entry, databaseContext, taskExecutor); + files.add(onlineFile); + onlineFile.download(); } public void deleteFile(LinkedFileViewModel file) { if (file.getFile().isOnlineLink()) { removeFileLink(file); } else { - boolean deleteSuccessful = file.delete(Globals.prefs.getFileDirectoryPreferences()); + boolean deleteSuccessful = file.delete(preferences.getFileDirectoryPreferences()); if (deleteSuccessful) { files.remove(file); } diff --git a/src/main/java/org/jabref/gui/util/BackgroundTask.java b/src/main/java/org/jabref/gui/util/BackgroundTask.java index 5a08cabed04..a0ba66966b4 100644 --- a/src/main/java/org/jabref/gui/util/BackgroundTask.java +++ b/src/main/java/org/jabref/gui/util/BackgroundTask.java @@ -26,10 +26,10 @@ public abstract class BackgroundTask { private Consumer onException; private Runnable onFinished; private ObjectProperty progress = new SimpleObjectProperty<>(new BackgroundProgress(0, 0)); - private DoubleProperty workDone = new SimpleDoubleProperty(0); + private DoubleProperty workDonePercentage = new SimpleDoubleProperty(0); public BackgroundTask() { - workDone.bind(EasyBind.map(progressProperty(), BackgroundTask.BackgroundProgress::getWorkDone)); + workDonePercentage.bind(EasyBind.map(progress, BackgroundTask.BackgroundProgress::getWorkDonePercentage)); } public static BackgroundTask wrap(Callable callable) { @@ -41,12 +41,12 @@ protected V call() throws Exception { }; } - public double getWorkDone() { - return workDone.get(); + public double getWorkDonePercentage() { + return workDonePercentage.get(); } - public DoubleProperty workDoneProperty() { - return workDone; + public DoubleProperty workDonePercentageProperty() { + return workDonePercentage; } public BackgroundProgress getProgress() { @@ -130,7 +130,6 @@ public class BackgroundProgress { private final double max; public BackgroundProgress(double workDone, double max) { - this.workDone = workDone; this.max = max; } @@ -142,5 +141,13 @@ public double getWorkDone() { public double getMax() { return max; } + + public double getWorkDonePercentage() { + if (max == 0) { + return 0; + } else { + return workDone / max; + } + } } } diff --git a/src/main/java/org/jabref/logic/importer/fetcher/ArXiv.java b/src/main/java/org/jabref/logic/importer/fetcher/ArXiv.java index 666b773c2e3..f91d3d7ec7a 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/ArXiv.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/ArXiv.java @@ -398,7 +398,7 @@ public BibEntry toBibEntry(Character keywordDelimiter) { primaryCategory.ifPresent(category -> bibEntry.setField(FieldName.EPRINTCLASS, category)); journalReferenceText.ifPresent(journal -> bibEntry.setField(FieldName.JOURNALTITLE, journal)); getPdfUrl().ifPresent(url -> bibEntry - .setFiles(Collections.singletonList(new LinkedFile("online", url, "PDF")))); + .setFiles(Collections.singletonList(new LinkedFile("", url, "PDF")))); return bibEntry; } } diff --git a/src/main/java/org/jabref/logic/util/io/FileUtil.java b/src/main/java/org/jabref/logic/util/io/FileUtil.java index 5c95b0565d2..8a9828a0b7b 100644 --- a/src/main/java/org/jabref/logic/util/io/FileUtil.java +++ b/src/main/java/org/jabref/logic/util/io/FileUtil.java @@ -258,7 +258,7 @@ public static List getListOfLinkedFiles(List bes, List fil * @param fileNamePattern the filename pattern * @param prefs the layout preferences * @return a suggested fileName - * @Deprecated use String createFileNameFromPattern(BibDatabase database, BibEntry entry, String fileNamePattern ) instead. + * @deprecated use String createFileNameFromPattern(BibDatabase database, BibEntry entry, String fileNamePattern ) instead. */ @Deprecated public static String createFileNameFromPattern(BibDatabase database, BibEntry entry, String fileNamePattern, @@ -295,7 +295,7 @@ public static String createFileNameFromPattern(BibDatabase database, BibEntry en public static String createFileNameFromPattern(BibDatabase database, BibEntry entry, String fileNamePattern) { String targetName = BracketedPattern.expandBrackets(fileNamePattern, ';', entry, database); - if ((targetName == null) || targetName.isEmpty()) { + if (targetName.isEmpty()) { targetName = entry.getCiteKeyOptional().orElse("default"); } @@ -313,11 +313,9 @@ public static String createFileNameFromPattern(BibDatabase database, BibEntry en * @return a suggested fileName */ public static String createDirNameFromPattern(BibDatabase database, BibEntry entry, String fileNamePattern) { - String targetName = null; - - targetName = BracketedPattern.expandBrackets(fileNamePattern, ';', entry, database); + String targetName = BracketedPattern.expandBrackets(fileNamePattern, ';', entry, database); - if ((targetName == null) || targetName.isEmpty()) { + if (targetName.isEmpty()) { targetName = entry.getCiteKeyOptional().orElse("default"); } diff --git a/src/main/java/org/jabref/model/entry/LinkedFile.java b/src/main/java/org/jabref/model/entry/LinkedFile.java index b5532b024a0..0d361eaca2d 100644 --- a/src/main/java/org/jabref/model/entry/LinkedFile.java +++ b/src/main/java/org/jabref/model/entry/LinkedFile.java @@ -41,6 +41,18 @@ public LinkedFile(String description, URL link, String fileType) { this(description, Objects.requireNonNull(link).toString(), fileType); } + public StringProperty descriptionProperty() { + return description; + } + + public StringProperty linkProperty() { + return link; + } + + public StringProperty fileTypeProperty() { + return fileType; + } + public String getFileType() { return fileType.get(); } diff --git a/src/test/java/org/jabref/architecture/TestArchitectureTests.java b/src/test/java/org/jabref/architecture/TestArchitectureTests.java index 04d5b0e8cf0..ae520b6fee9 100644 --- a/src/test/java/org/jabref/architecture/TestArchitectureTests.java +++ b/src/test/java/org/jabref/architecture/TestArchitectureTests.java @@ -28,6 +28,7 @@ public class TestArchitectureTests { private static final String CLASS_ORG_JABREF_PREFERENCES_MIGRATIONS_TEST = "PreferencesMigrationsTest"; private static final String CLASS_ORG_JABREF_UPDATE_TIMESTAMP_LISTENER_TEST = "UpdateTimestampListenerTest"; private static final String CLASS_ORG_JABREF_ENTRY_EDITOR_TEST = "EntryEditorTest"; + private static final String CLASS_ORG_JABREF_LINKED_FILE_VIEW_MODEL_TEST = "LinkedFileViewModelTest"; private final String forbiddenPackage; @@ -43,6 +44,7 @@ public TestArchitectureTests(String forbiddenPackage) { exceptions.add(CLASS_ORG_JABREF_PREFERENCES_MIGRATIONS_TEST); exceptions.add(CLASS_ORG_JABREF_UPDATE_TIMESTAMP_LISTENER_TEST); exceptions.add(CLASS_ORG_JABREF_ENTRY_EDITOR_TEST); + exceptions.add(CLASS_ORG_JABREF_LINKED_FILE_VIEW_MODEL_TEST); } @Parameterized.Parameters(name = "tests independent of {0}?") diff --git a/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java b/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java index fd6d832c671..672fc8612e7 100644 --- a/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java +++ b/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java @@ -9,10 +9,12 @@ import org.jabref.gui.DialogService; import org.jabref.gui.util.TaskExecutor; +import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.LinkedFile; import org.jabref.model.metadata.FileDirectoryPreferences; +import org.jabref.preferences.JabRefPreferences; import org.junit.Before; import org.junit.Rule; @@ -33,6 +35,8 @@ public class LinkedFileViewModelTest { @Rule public TemporaryFolder tempFolder = new TemporaryFolder(); + private final JabRefPreferences preferences = mock(JabRefPreferences.class); + private final JournalAbbreviationLoader abbreviationLoader = mock(JournalAbbreviationLoader.class); private LinkedFile linkedFile; private BibEntry entry; private BibDatabaseContext databaseContext; @@ -55,7 +59,7 @@ public void deleteWhenFilePathNotPresentReturnsTrue() { linkedFile = spy(new LinkedFile("", "nonexistent file", "")); doReturn(Optional.empty()).when(linkedFile).findIn(any(BibDatabaseContext.class), any(FileDirectoryPreferences.class)); - LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService); + LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, abbreviationLoader); boolean removed = viewModel.delete(fileDirectoryPreferences); assertTrue(removed); @@ -74,7 +78,7 @@ public void deleteWhenRemoveChosenReturnsTrue() throws IOException { any(ButtonType.class), any(ButtonType.class))).thenAnswer(invocation -> Optional.of(invocation.getArgument(3))); // first vararg - remove button - LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService); + LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, abbreviationLoader); boolean removed = viewModel.delete(fileDirectoryPreferences); assertTrue(removed); @@ -93,7 +97,7 @@ public void deleteWhenDeleteChosenReturnsTrueAndDeletesFile() throws IOException any(ButtonType.class), any(ButtonType.class))).thenAnswer(invocation -> Optional.of(invocation.getArgument(4))); // second vararg - delete button - LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService); + LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, abbreviationLoader); boolean removed = viewModel.delete(fileDirectoryPreferences); assertTrue(removed); @@ -111,7 +115,7 @@ public void deleteWhenDeleteChosenAndFileMissingReturnsFalse() throws IOExceptio any(ButtonType.class), any(ButtonType.class))).thenAnswer(invocation -> Optional.of(invocation.getArgument(4))); // second vararg - delete button - LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService); + LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, abbreviationLoader); boolean removed = viewModel.delete(fileDirectoryPreferences); verify(dialogService).showErrorDialogAndWait(anyString(), anyString()); @@ -130,7 +134,7 @@ public void deleteWhenDialogCancelledReturnsFalse() throws IOException { any(ButtonType.class), any(ButtonType.class))).thenAnswer(invocation -> Optional.of(invocation.getArgument(5))); // third vararg - cancel button - LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService); + LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, abbreviationLoader); boolean removed = viewModel.delete(fileDirectoryPreferences); assertFalse(removed); From 41c66f4104e9a8222d828c7f5a516c2dba1ff55e Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sun, 18 Mar 2018 15:46:31 +0100 Subject: [PATCH 05/48] Watch main css file for change and reapply automatically (#3847) * Watch main css file for change and reapply automatically * Code cleanup * Code cleanup, this time right * Hide thrown exception * Don't monitor css files bundled in jar * Add java property to make location of Main.css customizable The "live reloading" has now to be turned on by defining -Djabref.main.css Additionally, the location of the Main.css file can be given as parameter to this property. This makes it way more convenient when working on the code, because usually the location of the Main.css is in the build folder. Now, you can use the Main.css from the source directly. * rename constants to correct format Co-authored-by: Tobias Diez Co-authored-by: Patrick Scheibe --- src/main/java/org/jabref/Globals.java | 8 ++ src/main/java/org/jabref/JabRefGUI.java | 3 +- .../java/org/jabref/gui/AbstractView.java | 3 +- .../jabref/gui/customjfx/CustomJFXPanel.java | 4 +- .../org/jabref/gui/util/ControlHelper.java | 6 +- .../java/org/jabref/gui/util/ThemeLoader.java | 87 +++++++++++++++++++ 6 files changed, 102 insertions(+), 9 deletions(-) create mode 100644 src/main/java/org/jabref/gui/util/ThemeLoader.java diff --git a/src/main/java/org/jabref/Globals.java b/src/main/java/org/jabref/Globals.java index 652a79ef828..69476160034 100644 --- a/src/main/java/org/jabref/Globals.java +++ b/src/main/java/org/jabref/Globals.java @@ -12,6 +12,7 @@ import org.jabref.gui.util.DefaultFileUpdateMonitor; import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.gui.util.TaskExecutor; +import org.jabref.gui.util.ThemeLoader; import org.jabref.logic.exporter.ExporterFactory; import org.jabref.logic.importer.ImportFormatReader; import org.jabref.logic.journals.JournalAbbreviationLoader; @@ -61,6 +62,7 @@ public class Globals { // Background tasks private static GlobalFocusListener focusListener; private static DefaultFileUpdateMonitor fileUpdateMonitor; + private static ThemeLoader themeLoader; private static TelemetryClient telemetryClient; private Globals() { @@ -81,6 +83,8 @@ public static void startBackgroundTasks() { Globals.fileUpdateMonitor = new DefaultFileUpdateMonitor(); JabRefExecutorService.INSTANCE.executeInterruptableTask(Globals.fileUpdateMonitor, "FileUpdateMonitor"); + themeLoader = new ThemeLoader(fileUpdateMonitor); + if (Globals.prefs.shouldCollectTelemetry() && !GraphicsEnvironment.isHeadless()) { startTelemetryClient(); } @@ -130,4 +134,8 @@ public static void stopBackgroundTasks() { public static Optional getTelemetryClient() { return Optional.ofNullable(telemetryClient); } + + public static ThemeLoader getThemeLoader() { + return themeLoader; + } } diff --git a/src/main/java/org/jabref/JabRefGUI.java b/src/main/java/org/jabref/JabRefGUI.java index 7a3acdedecf..82c0b47e62c 100644 --- a/src/main/java/org/jabref/JabRefGUI.java +++ b/src/main/java/org/jabref/JabRefGUI.java @@ -18,7 +18,6 @@ import javafx.scene.Scene; import javafx.stage.Stage; -import org.jabref.gui.AbstractView; import org.jabref.gui.BasePanel; import org.jabref.gui.DialogService; import org.jabref.gui.FXDialogService; @@ -150,7 +149,7 @@ private void openWindow(Stage mainStage) { } Scene scene = new Scene(JabRefGUI.mainFrame, 800, 800); - scene.getStylesheets().add(AbstractView.class.getResource("Main.css").toExternalForm()); + Globals.getThemeLoader().installBaseCss(scene); mainStage.setTitle(JabRefFrame.FRAME_TITLE); mainStage.getIcons().addAll(IconTheme.getLogoSetFX()); mainStage.setScene(scene); diff --git a/src/main/java/org/jabref/gui/AbstractView.java b/src/main/java/org/jabref/gui/AbstractView.java index 055d5a69d0e..266ddedb429 100644 --- a/src/main/java/org/jabref/gui/AbstractView.java +++ b/src/main/java/org/jabref/gui/AbstractView.java @@ -6,6 +6,7 @@ import javafx.scene.Parent; import javafx.stage.Stage; +import org.jabref.Globals; import org.jabref.logic.l10n.Localization; import com.airhacks.afterburner.views.FXMLView; @@ -28,7 +29,7 @@ public Parent getView() { Parent view = super.getView(); // Add our base css file - view.getStylesheets().add(0, AbstractDialogView.class.getResource("Main.css").toExternalForm()); + Globals.getThemeLoader().installBaseCss(view); // Notify controller about the stage, where it is displayed view.sceneProperty().addListener((observable, oldValue, newValue) -> { diff --git a/src/main/java/org/jabref/gui/customjfx/CustomJFXPanel.java b/src/main/java/org/jabref/gui/customjfx/CustomJFXPanel.java index 07279a55d91..b9dfaf7e58b 100644 --- a/src/main/java/org/jabref/gui/customjfx/CustomJFXPanel.java +++ b/src/main/java/org/jabref/gui/customjfx/CustomJFXPanel.java @@ -3,7 +3,7 @@ import javafx.embed.swing.JFXPanel; import javafx.scene.Scene; -import org.jabref.gui.AbstractView; +import org.jabref.Globals; import org.jabref.gui.util.DefaultTaskExecutor; /** @@ -13,7 +13,7 @@ public class CustomJFXPanel { public static JFXPanel wrap(Scene scene) { JFXPanel container = new JFXPanel(); - scene.getStylesheets().add(AbstractView.class.getResource("Main.css").toExternalForm()); + Globals.getThemeLoader().installBaseCss(scene); DefaultTaskExecutor.runInJavaFXThread(() -> container.setScene(scene)); return container; } diff --git a/src/main/java/org/jabref/gui/util/ControlHelper.java b/src/main/java/org/jabref/gui/util/ControlHelper.java index 04c1d8f05fd..72bad6ead3d 100644 --- a/src/main/java/org/jabref/gui/util/ControlHelper.java +++ b/src/main/java/org/jabref/gui/util/ControlHelper.java @@ -5,7 +5,7 @@ import javafx.fxml.FXMLLoader; import javafx.scene.Parent; -import org.jabref.gui.AbstractView; +import org.jabref.Globals; import org.jabref.logic.l10n.Localization; import org.slf4j.Logger; @@ -29,9 +29,7 @@ public static void loadFXMLForControl(Parent control) { fxmlLoader.load(); // Add our base css file - control.getStylesheets().add(0, AbstractView.class.getResource("Main.css").toExternalForm()); - - // Add language resource + Globals.getThemeLoader().installBaseCss(control); } catch (IOException exception) { LOGGER.error("Problem loading fxml for control", exception); diff --git a/src/main/java/org/jabref/gui/util/ThemeLoader.java b/src/main/java/org/jabref/gui/util/ThemeLoader.java new file mode 100644 index 00000000000..ac5f461d4d9 --- /dev/null +++ b/src/main/java/org/jabref/gui/util/ThemeLoader.java @@ -0,0 +1,87 @@ +package org.jabref.gui.util; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Objects; + +import javafx.scene.Parent; +import javafx.scene.Scene; + +import org.jabref.gui.AbstractView; +import org.jabref.model.util.FileUpdateMonitor; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Installs the Main.css style file and provides live reloading. The live reloading has to be turned on by setting + * the -Djabref.main.css property. There two possible modes: (1) When only -Djabref.main.css + * is specified, then the standard Main.css that is found will be watched and on changes in that file, + * the style-sheet will be reloaded and changes are immediately visible. + *

+ * When working from an IDE, this usually means that the Main.css is located in the build folder. To use + * the css-file that is located in the sources directly, the full path can be given as value: + *

+ * -Djabref.main.css="/path/to/src/Main.css" + */ +public class ThemeLoader { + + private static final String DEFAULT_PATH_MAIN_CSS = AbstractView.class.getResource("Main.css").toExternalForm(); + private static final String CSS_SYSTEM_PROPERTY = System.getProperty("jabref.main.css"); + private static final Logger LOGGER = LoggerFactory.getLogger(ThemeLoader.class); + private final FileUpdateMonitor fileUpdateMonitor; + + public ThemeLoader(FileUpdateMonitor fileUpdateMonitor) { + this.fileUpdateMonitor = Objects.requireNonNull(fileUpdateMonitor); + } + + /** + * Installs the base css file as a stylesheet in the given scene. + * Changes in the css file lead to a redraw of the scene using the new css file. + */ + public void installBaseCss(Scene scene) { + String pathToMainCss = DEFAULT_PATH_MAIN_CSS; + if (CSS_SYSTEM_PROPERTY != null) { + final Path path = Paths.get(CSS_SYSTEM_PROPERTY); + if ("Main.css".matches(path.getFileName().toString()) && Files.isReadable(path)) { + pathToMainCss = path.toUri().toString(); + } + } + installCss(scene, pathToMainCss); + } + + private void installCss(Scene scene, String cssUrl) { + scene.getStylesheets().add(0, cssUrl); + try { + // If -Djabref.main.css is defined and the resources are not part of a .jar bundle, + // we watch the file for changes and turn on live reloading + if (!cssUrl.startsWith("jar:") && CSS_SYSTEM_PROPERTY != null) { + Path cssFile = Paths.get(new URL(cssUrl).toURI()); + LOGGER.info("Enabling live reloading of " + cssFile); + fileUpdateMonitor.addListenerForFile(cssFile, () -> { + LOGGER.info("Reload css file " + cssFile); + + DefaultTaskExecutor.runInJavaFXThread(() -> { + scene.getStylesheets().remove(cssUrl); + scene.getStylesheets().add(0, cssUrl); + } + ); + }); + } + } catch (URISyntaxException | IOException e) { + LOGGER.error("Could not watch css file for changes " + cssUrl, e); + } + } + + /** + * @deprecated you should never need to add css to a control, add it to the scene containing the control + */ + @Deprecated + public void installBaseCss(Parent control) { + control.getStylesheets().add(0, DEFAULT_PATH_MAIN_CSS); + } +} From a93ed9b757c287629ff809b8d49ee0863e4073d4 Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Sun, 18 Mar 2018 16:19:51 +0100 Subject: [PATCH 06/48] fix build, remove layout prefs, pass journal abbrev loader and prefs where necessary --- .../jabref/gui/fieldeditors/FieldEditors.java | 2 +- .../gui/fieldeditors/LinkedFileViewModel.java | 129 +++++++++--------- .../gui/fieldeditors/LinkedFilesEditor.java | 7 +- .../LinkedFilesEditorViewModel.java | 30 ++-- .../gui/maintable/MainTableColumnFactory.java | 6 +- .../jabref/logic/cleanup/CleanupWorker.java | 4 +- .../logic/cleanup/MoveFilesCleanup.java | 9 +- .../logic/cleanup/RenamePdfCleanup.java | 9 +- .../architecture/TestArchitectureTests.java | 3 +- .../logic/cleanup/MoveFilesCleanupTest.java | 19 ++- .../logic/cleanup/RenamePdfCleanupTest.java | 15 +- 11 files changed, 110 insertions(+), 123 deletions(-) diff --git a/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java b/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java index cc2b1fd32ac..ab916bf926a 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java +++ b/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java @@ -51,7 +51,7 @@ public static FieldEditorFX getForField(String fieldName, TaskExecutor taskExecu } else if (fieldExtras.contains(FieldProperty.OWNER)) { return new OwnerEditor(fieldName, preferences, suggestionProvider, fieldCheckers); } else if (fieldExtras.contains(FieldProperty.FILE_EDITOR)) { - return new LinkedFilesEditor(fieldName, dialogService, databaseContext, taskExecutor, suggestionProvider, fieldCheckers, preferences); + return new LinkedFilesEditor(fieldName, dialogService, databaseContext, taskExecutor, suggestionProvider, fieldCheckers, preferences, journalAbbreviationLoader); } else if (fieldExtras.contains(FieldProperty.YES_NO)) { return new OptionEditor<>(new YesNoEditorViewModel(fieldName, suggestionProvider, fieldCheckers)); } else if (fieldExtras.contains(FieldProperty.MONTH)) { diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java index f3d3ba6a425..cb358e48e7d 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java @@ -20,9 +20,9 @@ import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.property.StringProperty; import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.ButtonBar.ButtonData; import javafx.scene.control.ButtonType; -import org.jabref.Globals; import org.jabref.gui.AbstractViewModel; import org.jabref.gui.DialogService; import org.jabref.gui.IconTheme; @@ -35,12 +35,10 @@ import org.jabref.gui.filelist.FileListEntryEditor; import org.jabref.gui.util.BackgroundTask; import org.jabref.gui.util.TaskExecutor; -import org.jabref.logic.cleanup.CleanupPreferences; import org.jabref.logic.cleanup.MoveFilesCleanup; import org.jabref.logic.cleanup.RenamePdfCleanup; import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.layout.LayoutFormatterPreferences; import org.jabref.logic.net.URLDownload; import org.jabref.logic.util.io.FileUtil; import org.jabref.logic.xmp.XmpPreferences; @@ -49,13 +47,12 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.LinkedFile; import org.jabref.model.metadata.FileDirectoryPreferences; +import org.jabref.model.strings.StringUtil; import org.jabref.preferences.JabRefPreferences; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static javafx.scene.control.ButtonBar.ButtonData; - public class LinkedFileViewModel extends AbstractViewModel { private static final Logger LOGGER = LoggerFactory.getLogger(LinkedFileViewModel.class); @@ -70,33 +67,28 @@ public class LinkedFileViewModel extends AbstractViewModel { private final BibEntry entry; private final TaskExecutor taskExecutor; private final FileDirectoryPreferences fileDirectoryPreferences; - private final CleanupPreferences cleanupPreferences; - private final LayoutFormatterPreferences layoutFormatterPreferences; + private final String fileDirPattern; private final XmpPreferences xmpPreferences; private final String fileNamePattern; - /** - * @deprecated use {@link #LinkedFileViewModel(LinkedFile, BibEntry, BibDatabaseContext, TaskExecutor, DialogService, JabRefPreferences, JournalAbbreviationLoader)} instead - */ - @Deprecated - public LinkedFileViewModel(LinkedFile linkedFile, BibEntry entry, BibDatabaseContext databaseContext, TaskExecutor taskExecutor) { - this(linkedFile, entry, databaseContext, taskExecutor, new FXDialogService(), Globals.prefs, Globals.journalAbbreviationLoader); - } + public LinkedFileViewModel(LinkedFile linkedFile, + BibEntry entry, + BibDatabaseContext databaseContext, + TaskExecutor taskExecutor, + DialogService dialogService, + JabRefPreferences preferences, + JournalAbbreviationLoader abbreviationLoader) { - public LinkedFileViewModel(LinkedFile linkedFile, BibEntry entry, BibDatabaseContext databaseContext, - TaskExecutor taskExecutor, DialogService dialogService, JabRefPreferences preferences, JournalAbbreviationLoader abbreviationLoader) { this.linkedFile = linkedFile; this.databaseContext = databaseContext; this.entry = entry; this.dialogService = dialogService; this.taskExecutor = taskExecutor; - cleanupPreferences = preferences.getCleanupPreferences(abbreviationLoader); - layoutFormatterPreferences = preferences.getLayoutFormatterPreferences(abbreviationLoader); xmpPreferences = preferences.getXMPPreferences(); fileNamePattern = preferences.get(JabRefPreferences.IMPORT_FILENAMEPATTERN); fileDirectoryPreferences = preferences.getFileDirectoryPreferences(); - + fileDirPattern = preferences.getCleanupPreferences(abbreviationLoader).getFileDirPattern(); downloadOngoing.bind(downloadProgress.greaterThanOrEqualTo(0).and(downloadProgress.lessThan(1))); canWriteXMPMetadata.setValue(!linkedFile.isOnlineLink() && linkedFile.getFileType().equalsIgnoreCase("pdf")); } @@ -175,11 +167,11 @@ public void open() { boolean successful = JabRefDesktop.openExternalFileAnyFormat(databaseContext, linkedFile.getLink(), type); if (!successful) { dialogService.showErrorDialogAndWait( - Localization.lang("File not found"), - Localization.lang("Could not find file '%0'.", linkedFile.getLink())); + Localization.lang("File not found"), + Localization.lang("Could not find file '%0'.", linkedFile.getLink())); } } catch (IOException e) { - dialogService.showErrorDialogAndWait(Localization.lang("Error opening file '%0'.", getLink()), e); + dialogService.showErrorDialogAndWait(Localization.lang("Error opening file '%0'.", linkedFile.getLink()), e); } } @@ -217,26 +209,25 @@ public void rename() { Optional fileDir = databaseContext.getFirstExistingFileDir(fileDirectoryPreferences); if (!fileDir.isPresent()) { dialogService.showErrorDialogAndWait( - Localization.lang("Rename file"), - Localization.lang("File directory is not set or does not exist!")); + Localization.lang("Rename file"), + Localization.lang("File directory is not set or does not exist!")); return; } Optional file = linkedFile.findIn(databaseContext, fileDirectoryPreferences); if ((file.isPresent()) && Files.exists(file.get())) { RenamePdfCleanup pdfCleanup = new RenamePdfCleanup(false, - databaseContext, - cleanupPreferences.getFileNamePattern(), - layoutFormatterPreferences, - fileDirectoryPreferences, linkedFile); + databaseContext, + fileDirPattern, + fileDirectoryPreferences, linkedFile); String targetFileName = pdfCleanup.getTargetFileName(linkedFile, entry); boolean confirm = dialogService.showConfirmationDialogAndWait( - Localization.lang("Rename file"), - Localization.lang("Rename file to") + " " + targetFileName, - Localization.lang("Rename file"), - Localization.lang("Cancel")); + Localization.lang("Rename file"), + Localization.lang("Rename file to") + " " + targetFileName, + Localization.lang("Rename file"), + Localization.lang("Cancel")); if (confirm) { Optional fileConflictCheck = pdfCleanup.findExistingFile(linkedFile, entry); @@ -245,8 +236,8 @@ public void rename() { } } else { dialogService.showErrorDialogAndWait( - Localization.lang("File not found"), - Localization.lang("Could not find file '%0'.", linkedFile.getLink())); + Localization.lang("File not found"), + Localization.lang("Could not find file '%0'.", linkedFile.getLink())); } } @@ -257,23 +248,23 @@ private void performRenameWithConflictCheck(Optional file, RenamePdfCleanu pdfCleanup.cleanupWithException(entry); } catch (IOException e) { dialogService.showErrorDialogAndWait( - Localization.lang("Rename failed"), - Localization.lang("JabRef cannot access the file because it is being used by another process.")); + Localization.lang("Rename failed"), + Localization.lang("JabRef cannot access the file because it is being used by another process.")); } } else { confirm = dialogService.showConfirmationDialogAndWait( - Localization.lang("File exists"), - Localization.lang("'%0' exists. Overwrite file?", targetFileName), - Localization.lang("Overwrite"), - Localization.lang("Cancel")); + Localization.lang("File exists"), + Localization.lang("'%0' exists. Overwrite file?", targetFileName), + Localization.lang("Overwrite"), + Localization.lang("Cancel")); if (confirm) { try { FileUtil.renameFileWithException(fileConflictCheck.get(), file.get(), true); pdfCleanup.cleanupWithException(entry); } catch (IOException e) { dialogService.showErrorDialogAndWait( - Localization.lang("Rename failed"), - Localization.lang("JabRef cannot access the file because it is being used by another process.")); + Localization.lang("Rename failed"), + Localization.lang("JabRef cannot access the file because it is being used by another process.")); } } } @@ -289,8 +280,8 @@ public void moveToDefaultDirectory() { Optional fileDir = databaseContext.getFirstExistingFileDir(fileDirectoryPreferences); if (!fileDir.isPresent()) { dialogService.showErrorDialogAndWait( - Localization.lang("Move file"), - Localization.lang("File directory is not set or does not exist!")); + Localization.lang("Move file"), + Localization.lang("File directory is not set or does not exist!")); return; } @@ -298,23 +289,23 @@ public void moveToDefaultDirectory() { if ((file.isPresent()) && Files.exists(file.get())) { // Linked file exists, so move it MoveFilesCleanup moveFiles = new MoveFilesCleanup(databaseContext, - cleanupPreferences.getFileDirPattern(), - fileDirectoryPreferences, - layoutFormatterPreferences, linkedFile); + fileDirPattern, + fileDirectoryPreferences, + linkedFile); boolean confirm = dialogService.showConfirmationDialogAndWait( - Localization.lang("Move file"), - Localization.lang("Move file to file directory?") + " " + fileDir.get(), - Localization.lang("Move file"), - Localization.lang("Cancel")); + Localization.lang("Move file"), + Localization.lang("Move file to file directory?") + " " + fileDir.get(), + Localization.lang("Move file"), + Localization.lang("Cancel")); if (confirm) { moveFiles.cleanup(entry); } } else { // File doesn't exist, so we can't move it. dialogService.showErrorDialogAndWait( - Localization.lang("File not found"), - Localization.lang("Could not find file '%0'.", linkedFile.getLink())); + Localization.lang("File not found"), + Localization.lang("Could not find file '%0'.", linkedFile.getLink())); } } @@ -329,9 +320,11 @@ public boolean delete(FileDirectoryPreferences prefs) { ButtonType removeFromEntry = new ButtonType(Localization.lang("Remove from entry"), ButtonData.YES); ButtonType deleteFromEntry = new ButtonType(Localization.lang("Delete from disk")); Optional buttonType = dialogService.showCustomButtonDialogAndWait(AlertType.INFORMATION, - Localization.lang("Delete '%0'", file.get().toString()), - Localization.lang("Delete the selected file permanently from disk, or just remove the file from the entry? Pressing Delete will delete the file permanently from disk."), - removeFromEntry, deleteFromEntry, ButtonType.CANCEL); + Localization.lang("Delete '%0'", file.get().toString()), + Localization.lang("Delete the selected file permanently from disk, or just remove the file from the entry? Pressing Delete will delete the file permanently from disk."), + removeFromEntry, + deleteFromEntry, + ButtonType.CANCEL); if (buttonType.isPresent()) { if (buttonType.get().equals(removeFromEntry)) { @@ -345,8 +338,8 @@ public boolean delete(FileDirectoryPreferences prefs) { return true; } catch (IOException ex) { dialogService.showErrorDialogAndWait( - Localization.lang("Cannot delete file"), - Localization.lang("File permission error")); + Localization.lang("Cannot delete file"), + Localization.lang("File permission error")); LOGGER.warn("File permission error while deleting: " + linkedFile, ex); } } @@ -397,8 +390,8 @@ public void download() { Optional targetDirectory = databaseContext.getFirstExistingFileDir(fileDirectoryPreferences); if (!targetDirectory.isPresent()) { dialogService.showErrorDialogAndWait( - Localization.lang("Download file"), - Localization.lang("File directory is not set or does not exist!")); + Localization.lang("Download file"), + Localization.lang("File directory is not set or does not exist!")); return; } String suffix = suggestedType.map(ExternalFileType::getExtension).orElse(""); @@ -406,19 +399,19 @@ public void download() { Path destination = targetDirectory.get().resolve(suggestedName); BackgroundTask downloadTask = new FileDownloadTask(urlDownload.getSource(), destination) - .onSuccess(event -> { - LinkedFile newLinkedFile = LinkedFilesEditorViewModel.fromFile(destination, databaseContext.getFileDirectoriesAsPaths(fileDirectoryPreferences)); - linkedFile.setLink(newLinkedFile.getLink()); - linkedFile.setFileType(newLinkedFile.getFileType()); - }) - .onFailure(ex -> dialogService.showErrorDialogAndWait("Download failed", ex)); + .onSuccess(event -> { + LinkedFile newLinkedFile = LinkedFilesEditorViewModel.fromFile(destination, databaseContext.getFileDirectoriesAsPaths(fileDirectoryPreferences)); + linkedFile.setLink(newLinkedFile.getLink()); + linkedFile.setFileType(newLinkedFile.getFileType()); + }) + .onFailure(ex -> dialogService.showErrorDialogAndWait("Download failed", ex)); downloadProgress.bind(downloadTask.workDonePercentageProperty()); taskExecutor.execute(downloadTask); } catch (MalformedURLException exception) { dialogService.showErrorDialogAndWait( - Localization.lang("Invalid URL"), - exception); + Localization.lang("Invalid URL"), + exception); } } diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java index 53b437613ed..5ce3aa5d263 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java @@ -37,6 +37,7 @@ import org.jabref.gui.util.TaskExecutor; import org.jabref.gui.util.ViewModelListCellFactory; import org.jabref.logic.integrity.FieldCheckers; +import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; @@ -51,8 +52,10 @@ public class LinkedFilesEditor extends HBox implements FieldEditorFX { @FXML private final LinkedFilesEditorViewModel viewModel; @FXML private ListView listView; - public LinkedFilesEditor(String fieldName, DialogService dialogService, BibDatabaseContext databaseContext, TaskExecutor taskExecutor, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers, JabRefPreferences preferences) { - this.viewModel = new LinkedFilesEditorViewModel(fieldName, suggestionProvider, dialogService, databaseContext, taskExecutor, fieldCheckers, preferences); + public LinkedFilesEditor(String fieldName, DialogService dialogService, BibDatabaseContext databaseContext, TaskExecutor taskExecutor, AutoCompleteSuggestionProvider suggestionProvider, + FieldCheckers fieldCheckers, + JabRefPreferences preferences, JournalAbbreviationLoader abbreviationLoader) { + this.viewModel = new LinkedFilesEditorViewModel(fieldName, suggestionProvider, dialogService, databaseContext, taskExecutor, fieldCheckers, preferences, abbreviationLoader); ControlHelper.loadFXMLForControl(this); diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java index 47bf5db615c..42c2a5d853b 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java @@ -29,6 +29,7 @@ import org.jabref.gui.util.TaskExecutor; import org.jabref.logic.importer.FulltextFetchers; import org.jabref.logic.integrity.FieldCheckers; +import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.logic.l10n.Localization; import org.jabref.logic.util.io.FileUtil; import org.jabref.model.database.BibDatabaseContext; @@ -47,14 +48,22 @@ public class LinkedFilesEditorViewModel extends AbstractEditorViewModel { private final BibDatabaseContext databaseContext; private final TaskExecutor taskExecutor; private final JabRefPreferences preferences; - - public LinkedFilesEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, DialogService dialogService, BibDatabaseContext databaseContext, TaskExecutor taskExecutor, FieldCheckers fieldCheckers, JabRefPreferences preferences) { + private final JournalAbbreviationLoader journalAbbreviationLoader; + + public LinkedFilesEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, + DialogService dialogService, + BibDatabaseContext databaseContext, + TaskExecutor taskExecutor, + FieldCheckers fieldCheckers, + JabRefPreferences preferences, + JournalAbbreviationLoader journalAbbreviationLoader) { super(fieldName, suggestionProvider, fieldCheckers); this.dialogService = dialogService; this.databaseContext = databaseContext; this.taskExecutor = taskExecutor; this.preferences = preferences; + this.journalAbbreviationLoader = journalAbbreviationLoader; BindingsHelper.bindContentBidirectional( files, @@ -92,7 +101,7 @@ public LinkedFileViewModel fromFile(Path file) { List fileDirectories = databaseContext.getFileDirectoriesAsPaths(preferences.getFileDirectoryPreferences()); LinkedFile linkedFile = fromFile(file, fileDirectories); - return new LinkedFileViewModel(linkedFile, entry, databaseContext, dialogService, taskExecutor); + return new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, journalAbbreviationLoader); } @@ -106,7 +115,7 @@ public BooleanProperty fulltextLookupInProgressProperty() { private List parseToFileViewModel(String stringValue) { return FileFieldParser.parse(stringValue).stream() - .map(linkedFile -> new LinkedFileViewModel(linkedFile, entry, databaseContext, dialogService, taskExecutor)) + .map(linkedFile -> new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, journalAbbreviationLoader)) .collect(Collectors.toList()); } @@ -127,10 +136,9 @@ public void addNewFile() { .build(); List fileDirectories = databaseContext.getFileDirectoriesAsPaths(preferences.getFileDirectoryPreferences()); - dialogService.showFileOpenDialog(fileDialogConfiguration).ifPresent( - newFile -> { - LinkedFile newLinkedFile = fromFile(newFile, fileDirectories); - files.add(new LinkedFileViewModel(newLinkedFile, entry, databaseContext, dialogService, taskExecutor)); + dialogService.showFileOpenDialog(fileDialogConfiguration).ifPresent(newFile -> { + LinkedFile newLinkedFile = fromFile(newFile, fileDirectories); + files.add(new LinkedFileViewModel(newLinkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, journalAbbreviationLoader)); }); } @@ -156,7 +164,7 @@ private List findAssociatedNotLinkedFiles(BibEntry entry) { try { List linkedFiles = util.findAssociatedNotLinkedFiles(entry); for (LinkedFile linkedFile : linkedFiles) { - LinkedFileViewModel newLinkedFile = new LinkedFileViewModel(linkedFile, entry, databaseContext, dialogService, taskExecutor); + LinkedFileViewModel newLinkedFile = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, journalAbbreviationLoader); newLinkedFile.markAsAutomaticallyFound(); result.add(newLinkedFile); } @@ -199,8 +207,8 @@ public void addFromURL() { } private void addFromURL(URL url) { - LinkedFileViewModel onlineFile = new LinkedFileViewModel( - new LinkedFile("", url, ""), entry, databaseContext, taskExecutor); + LinkedFileViewModel onlineFile = new LinkedFileViewModel(new LinkedFile("", url, ""), + entry, databaseContext, taskExecutor, dialogService, preferences, null); files.add(onlineFile); onlineFile.download(); } diff --git a/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java b/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java index 31090c1c512..0d365ca033c 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java +++ b/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java @@ -240,9 +240,9 @@ private TableColumn> createFileColumn() .withGraphic(this::createFileIcon) .withMenu(this::createFileMenu) .withOnMouseClickedEvent((entry, linkedFiles) -> event -> { - if (event.getButton() == MouseButton.PRIMARY && linkedFiles.size() == 1) { + if ((event.getButton() == MouseButton.PRIMARY) && (linkedFiles.size() == 1)) { // Only one linked file -> open directly - LinkedFileViewModel linkedFileViewModel = new LinkedFileViewModel(linkedFiles.get(0), entry.getEntry(), database, dialogService, Globals.TASK_EXECUTOR); + LinkedFileViewModel linkedFileViewModel = new LinkedFileViewModel(linkedFiles.get(0), entry.getEntry(), database, Globals.TASK_EXECUTOR, dialogService, Globals.prefs, Globals.journalAbbreviationLoader); linkedFileViewModel.open(); } }) @@ -258,7 +258,7 @@ private ContextMenu createFileMenu(BibEntryTableViewModel entry, List linkedFileViewModel.open()); diff --git a/src/main/java/org/jabref/logic/cleanup/CleanupWorker.java b/src/main/java/org/jabref/logic/cleanup/CleanupWorker.java index 9ed2c3dd5a3..1c7e651182b 100644 --- a/src/main/java/org/jabref/logic/cleanup/CleanupWorker.java +++ b/src/main/java/org/jabref/logic/cleanup/CleanupWorker.java @@ -72,14 +72,14 @@ private List determineCleanupActions(CleanupPreset preset) { jobs.add(new FileLinksCleanup()); } if (preset.isMovePDF()) { - jobs.add(new MoveFilesCleanup(databaseContext, fileDirPattern, fileDirectoryPreferences, layoutPrefs)); + jobs.add(new MoveFilesCleanup(databaseContext, fileDirPattern, fileDirectoryPreferences)); } if (preset.isMakePathsRelative()) { jobs.add(new RelativePathsCleanup(databaseContext, fileDirectoryPreferences)); } if (preset.isRenamePDF()) { RenamePdfCleanup cleaner = new RenamePdfCleanup(preset.isRenamePdfOnlyRelativePaths(), databaseContext, - fileNamePattern, layoutPrefs, fileDirectoryPreferences); + fileNamePattern, fileDirectoryPreferences); jobs.add(cleaner); unsuccessfulRenames += cleaner.getUnsuccessfulRenames(); } diff --git a/src/main/java/org/jabref/logic/cleanup/MoveFilesCleanup.java b/src/main/java/org/jabref/logic/cleanup/MoveFilesCleanup.java index 6ef4a5d46e9..b919576a0dd 100644 --- a/src/main/java/org/jabref/logic/cleanup/MoveFilesCleanup.java +++ b/src/main/java/org/jabref/logic/cleanup/MoveFilesCleanup.java @@ -12,7 +12,6 @@ import java.util.Optional; import java.util.stream.Collectors; -import org.jabref.logic.layout.LayoutFormatterPreferences; import org.jabref.logic.util.io.FileUtil; import org.jabref.model.FieldChange; import org.jabref.model.cleanup.CleanupJob; @@ -35,19 +34,17 @@ public class MoveFilesCleanup implements CleanupJob { private LinkedFile singleFileFieldCleanup; - // FIXME: remove unused parameter 'layoutPrefs' later S.G. public MoveFilesCleanup(BibDatabaseContext databaseContext, String fileDirPattern, - FileDirectoryPreferences fileDirectoryPreferences, LayoutFormatterPreferences layoutPrefs) { + FileDirectoryPreferences fileDirectoryPreferences) { this.databaseContext = Objects.requireNonNull(databaseContext); this.fileDirPattern = Objects.requireNonNull(fileDirPattern); this.fileDirectoryPreferences = Objects.requireNonNull(fileDirectoryPreferences); } public MoveFilesCleanup(BibDatabaseContext databaseContext, String fileDirPattern, - FileDirectoryPreferences fileDirectoryPreferences, LayoutFormatterPreferences prefs, - LinkedFile field) { + FileDirectoryPreferences fileDirectoryPreferences, LinkedFile field) { - this(databaseContext, fileDirPattern, fileDirectoryPreferences, prefs); + this(databaseContext, fileDirPattern, fileDirectoryPreferences); this.singleFileFieldCleanup = field; } diff --git a/src/main/java/org/jabref/logic/cleanup/RenamePdfCleanup.java b/src/main/java/org/jabref/logic/cleanup/RenamePdfCleanup.java index 3c69a6800f8..71093ba032e 100644 --- a/src/main/java/org/jabref/logic/cleanup/RenamePdfCleanup.java +++ b/src/main/java/org/jabref/logic/cleanup/RenamePdfCleanup.java @@ -12,7 +12,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import org.jabref.logic.layout.LayoutFormatterPreferences; import org.jabref.logic.util.io.FileUtil; import org.jabref.model.FieldChange; import org.jabref.model.cleanup.CleanupJob; @@ -37,10 +36,8 @@ public class RenamePdfCleanup implements CleanupJob { private int unsuccessfulRenames; private LinkedFile singleFieldCleanup; - // FIXME: (S.G.) remove unused constructor argument 'layoutPreferences' later; for now, - // however, the argument is retained in order not to change the class interface: + public RenamePdfCleanup(boolean onlyRelativePaths, BibDatabaseContext databaseContext, String fileNamePattern, - LayoutFormatterPreferences layoutPreferences, FileDirectoryPreferences fileDirectoryPreferences) { this.databaseContext = Objects.requireNonNull(databaseContext); this.onlyRelativePaths = onlyRelativePaths; @@ -49,11 +46,9 @@ public RenamePdfCleanup(boolean onlyRelativePaths, BibDatabaseContext databaseCo } public RenamePdfCleanup(boolean onlyRelativePaths, BibDatabaseContext databaseContext, String fileNamePattern, - LayoutFormatterPreferences layoutPreferences, FileDirectoryPreferences fileDirectoryPreferences, LinkedFile singleField) { - this(onlyRelativePaths, databaseContext, fileNamePattern, layoutPreferences, - fileDirectoryPreferences); + this(onlyRelativePaths, databaseContext, fileNamePattern, fileDirectoryPreferences); this.singleFieldCleanup = singleField; } diff --git a/src/test/java/org/jabref/architecture/TestArchitectureTests.java b/src/test/java/org/jabref/architecture/TestArchitectureTests.java index bf36680e4a7..c867d36b96d 100644 --- a/src/test/java/org/jabref/architecture/TestArchitectureTests.java +++ b/src/test/java/org/jabref/architecture/TestArchitectureTests.java @@ -27,13 +27,12 @@ public class TestArchitectureTests { private static final String CLASS_ORG_JABREF_PREFERENCES_TEST = "JabRefPreferencesTest"; private static final String CLASS_ORG_JABREF_PREFERENCES_MIGRATIONS_TEST = "PreferencesMigrationsTest"; private static final String CLASS_ORG_JABREF_UPDATE_TIMESTAMP_LISTENER_TEST = "UpdateTimestampListenerTest"; - private static final String CLASS_ORG_JABREF_ENTRY_EDITOR_TEST = "SourceTabTest"; private static final String CLASS_ORG_JABREF_ENTRY_EDITOR_TEST = "EntryEditorTest"; private static final String CLASS_ORG_JABREF_LINKED_FILE_VIEW_MODEL_TEST = "LinkedFileViewModelTest"; private final String forbiddenPackage; - private List exceptions; + private final List exceptions; public TestArchitectureTests(String forbiddenPackage) { this.forbiddenPackage = forbiddenPackage; diff --git a/src/test/java/org/jabref/logic/cleanup/MoveFilesCleanupTest.java b/src/test/java/org/jabref/logic/cleanup/MoveFilesCleanupTest.java index eff70c4b427..7dcb8e77167 100644 --- a/src/test/java/org/jabref/logic/cleanup/MoveFilesCleanupTest.java +++ b/src/test/java/org/jabref/logic/cleanup/MoveFilesCleanupTest.java @@ -7,7 +7,6 @@ import java.util.Arrays; import java.util.Optional; -import org.jabref.logic.layout.LayoutFormatterPreferences; import org.jabref.model.Defaults; import org.jabref.model.database.BibDatabase; import org.jabref.model.database.BibDatabaseContext; @@ -62,8 +61,8 @@ public void movesFileFromSubfolder() throws IOException { LinkedFile fileField = new LinkedFile("", fileBefore.getAbsolutePath(), ""); entry.setField("file", FileFieldWriter.getStringRepresentation(fileField)); - cleanup = new MoveFilesCleanup(databaseContext, "", fileDirPrefs, - mock(LayoutFormatterPreferences.class)); + cleanup = new MoveFilesCleanup(databaseContext, "", fileDirPrefs); + cleanup.cleanup(entry); assertFalse(fileBefore.exists()); @@ -85,8 +84,7 @@ public void movesFileFromSubfolderMultiple() throws IOException { entry.setField("file", FileFieldWriter.getStringRepresentation( Arrays.asList(new LinkedFile("", "", ""), fileField, new LinkedFile("", "", "")))); - cleanup = new MoveFilesCleanup(databaseContext, "", fileDirPrefs, - mock(LayoutFormatterPreferences.class)); + cleanup = new MoveFilesCleanup(databaseContext, "", fileDirPrefs); cleanup.cleanup(entry); assertFalse(fileBefore.exists()); @@ -109,8 +107,8 @@ public void movesFileFromSubfolderWithFileDirPattern() throws IOException { LinkedFile fileField = new LinkedFile("", fileBefore.getAbsolutePath(), ""); entry.setField("file", FileFieldWriter.getStringRepresentation(fileField)); - cleanup = new MoveFilesCleanup(databaseContext, "[entrytype]", fileDirPrefs, - mock(LayoutFormatterPreferences.class)); + cleanup = new MoveFilesCleanup(databaseContext, "[entrytype]", fileDirPrefs); + cleanup.cleanup(entry); assertFalse(fileBefore.exists()); @@ -136,8 +134,7 @@ public void movesFileFromSubfolderWithSubdirPattern() throws IOException { LinkedFile fileField = new LinkedFile("", fileBefore.getAbsolutePath(), ""); local_entry.setField("file", FileFieldWriter.getStringRepresentation(fileField)); - cleanup = new MoveFilesCleanup(databaseContext, "[year]", fileDirPrefs, - mock(LayoutFormatterPreferences.class)); + cleanup = new MoveFilesCleanup(databaseContext, "[year]", fileDirPrefs); cleanup.cleanup(local_entry); assertFalse(fileBefore.exists()); @@ -164,8 +161,8 @@ public void movesFileFromSubfolderWithDeepSubdirPattern() throws IOException { LinkedFile fileField = new LinkedFile("", fileBefore.getAbsolutePath(), ""); local_entry.setField("file", FileFieldWriter.getStringRepresentation(fileField)); - cleanup = new MoveFilesCleanup(databaseContext, "[entrytype]/[year]/[auth]", fileDirPrefs, - mock(LayoutFormatterPreferences.class)); + cleanup = new MoveFilesCleanup(databaseContext, "[entrytype]/[year]/[auth]", fileDirPrefs); + cleanup.cleanup(local_entry); assertFalse(fileBefore.exists()); diff --git a/src/test/java/org/jabref/logic/cleanup/RenamePdfCleanupTest.java b/src/test/java/org/jabref/logic/cleanup/RenamePdfCleanupTest.java index c5be556f6d8..e169ef43c0f 100644 --- a/src/test/java/org/jabref/logic/cleanup/RenamePdfCleanupTest.java +++ b/src/test/java/org/jabref/logic/cleanup/RenamePdfCleanupTest.java @@ -58,7 +58,7 @@ public void cleanupRenamePdfRenamesFileEvenIfOnlyDifferenceIsCase() throws IOExc entry.setField("file", FileFieldWriter.getStringRepresentation(fileField)); RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, - mock(LayoutFormatterPreferences.class), fileDirPrefs); + fileDirPrefs); cleanup.cleanup(entry); LinkedFile newFileField = new LinkedFile("", "Toot.tmp", ""); @@ -75,7 +75,7 @@ public void cleanupRenamePdfRenamesWithMultipleFiles() throws IOException { new LinkedFile("", tempFile.getAbsolutePath(), ""), new LinkedFile("", "", "")))); RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, - mock(LayoutFormatterPreferences.class), fileDirPrefs); + fileDirPrefs); cleanup.cleanup(entry); assertEquals( @@ -93,7 +93,7 @@ public void cleanupRenamePdfRenamesFileStartingWithBibtexKey() throws IOExceptio entry.setField("title", "test title"); RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, - mock(LayoutFormatterPreferences.class), fileDirPrefs); + fileDirPrefs); cleanup.cleanup(entry); LinkedFile newFileField = new LinkedFile("", "Toot - test title.tmp", ""); @@ -108,9 +108,7 @@ public void cleanupRenamePdfRenamesFileInSameFolder() throws IOException { entry.setField("file", FileFieldWriter.getStringRepresentation(fileField)); entry.setField("title", "test title"); - RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, - layoutFormatterPreferences, - fileDirPrefs); + RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, fileDirPrefs); cleanup.cleanup(entry); LinkedFile newFileField = new LinkedFile("", "Toot - test title.pdf", "PDF"); @@ -125,7 +123,6 @@ public void cleanupSingleField() throws IOException { entry.setField("file", FileFieldWriter.getStringRepresentation(fileField)); entry.setField("title", "test title"); RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, - layoutFormatterPreferences, fileDirPrefs, fileField); cleanup.cleanup(entry); @@ -140,9 +137,7 @@ public void cleanupGetTargetFilename() throws IOException { String fileNamePattern = "[bibtexkey] - [fulltitle]"; testFolder.newFile("Toot.pdf"); LinkedFile fileField = new LinkedFile("", "Toot.pdf", "PDF"); - RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, - layoutFormatterPreferences, - fileDirPrefs); + RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, fileDirPrefs); entry.setField("file", FileFieldWriter.getStringRepresentation(fileField)); entry.setField("title", "test title"); From 4b7698923e6a72f1a0e7c987e9b3a411e3fd3ba7 Mon Sep 17 00:00:00 2001 From: Christoph Date: Sun, 18 Mar 2018 16:34:34 +0100 Subject: [PATCH 07/48] Get rid of journal abbrev loader in linkedFiles (#3862) --- .../jabref/gui/fieldeditors/FieldEditors.java | 2 +- .../gui/fieldeditors/LinkedFileViewModel.java | 6 ++---- .../gui/fieldeditors/LinkedFilesEditor.java | 5 ++--- .../LinkedFilesEditorViewModel.java | 18 +++++++----------- .../gui/maintable/MainTableColumnFactory.java | 4 ++-- .../fieldeditors/LinkedFileViewModelTest.java | 10 +++++----- 6 files changed, 19 insertions(+), 26 deletions(-) diff --git a/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java b/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java index ab916bf926a..cc2b1fd32ac 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java +++ b/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java @@ -51,7 +51,7 @@ public static FieldEditorFX getForField(String fieldName, TaskExecutor taskExecu } else if (fieldExtras.contains(FieldProperty.OWNER)) { return new OwnerEditor(fieldName, preferences, suggestionProvider, fieldCheckers); } else if (fieldExtras.contains(FieldProperty.FILE_EDITOR)) { - return new LinkedFilesEditor(fieldName, dialogService, databaseContext, taskExecutor, suggestionProvider, fieldCheckers, preferences, journalAbbreviationLoader); + return new LinkedFilesEditor(fieldName, dialogService, databaseContext, taskExecutor, suggestionProvider, fieldCheckers, preferences); } else if (fieldExtras.contains(FieldProperty.YES_NO)) { return new OptionEditor<>(new YesNoEditorViewModel(fieldName, suggestionProvider, fieldCheckers)); } else if (fieldExtras.contains(FieldProperty.MONTH)) { diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java index cb358e48e7d..0575fd4af05 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java @@ -37,7 +37,6 @@ import org.jabref.gui.util.TaskExecutor; import org.jabref.logic.cleanup.MoveFilesCleanup; import org.jabref.logic.cleanup.RenamePdfCleanup; -import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.logic.l10n.Localization; import org.jabref.logic.net.URLDownload; import org.jabref.logic.util.io.FileUtil; @@ -76,8 +75,7 @@ public LinkedFileViewModel(LinkedFile linkedFile, BibDatabaseContext databaseContext, TaskExecutor taskExecutor, DialogService dialogService, - JabRefPreferences preferences, - JournalAbbreviationLoader abbreviationLoader) { + JabRefPreferences preferences) { this.linkedFile = linkedFile; this.databaseContext = databaseContext; @@ -88,7 +86,7 @@ public LinkedFileViewModel(LinkedFile linkedFile, xmpPreferences = preferences.getXMPPreferences(); fileNamePattern = preferences.get(JabRefPreferences.IMPORT_FILENAMEPATTERN); fileDirectoryPreferences = preferences.getFileDirectoryPreferences(); - fileDirPattern = preferences.getCleanupPreferences(abbreviationLoader).getFileDirPattern(); + fileDirPattern = preferences.get(JabRefPreferences.IMPORT_FILEDIRPATTERN); downloadOngoing.bind(downloadProgress.greaterThanOrEqualTo(0).and(downloadProgress.lessThan(1))); canWriteXMPMetadata.setValue(!linkedFile.isOnlineLink() && linkedFile.getFileType().equalsIgnoreCase("pdf")); } diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java index 5ce3aa5d263..8f64b779543 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java @@ -37,7 +37,6 @@ import org.jabref.gui.util.TaskExecutor; import org.jabref.gui.util.ViewModelListCellFactory; import org.jabref.logic.integrity.FieldCheckers; -import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; @@ -54,8 +53,8 @@ public class LinkedFilesEditor extends HBox implements FieldEditorFX { public LinkedFilesEditor(String fieldName, DialogService dialogService, BibDatabaseContext databaseContext, TaskExecutor taskExecutor, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers, - JabRefPreferences preferences, JournalAbbreviationLoader abbreviationLoader) { - this.viewModel = new LinkedFilesEditorViewModel(fieldName, suggestionProvider, dialogService, databaseContext, taskExecutor, fieldCheckers, preferences, abbreviationLoader); + JabRefPreferences preferences) { + this.viewModel = new LinkedFilesEditorViewModel(fieldName, suggestionProvider, dialogService, databaseContext, taskExecutor, fieldCheckers, preferences); ControlHelper.loadFXMLForControl(this); diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java index 42c2a5d853b..7981fc6e15f 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java @@ -29,7 +29,6 @@ import org.jabref.gui.util.TaskExecutor; import org.jabref.logic.importer.FulltextFetchers; import org.jabref.logic.integrity.FieldCheckers; -import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.logic.l10n.Localization; import org.jabref.logic.util.io.FileUtil; import org.jabref.model.database.BibDatabaseContext; @@ -48,22 +47,20 @@ public class LinkedFilesEditorViewModel extends AbstractEditorViewModel { private final BibDatabaseContext databaseContext; private final TaskExecutor taskExecutor; private final JabRefPreferences preferences; - private final JournalAbbreviationLoader journalAbbreviationLoader; public LinkedFilesEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, DialogService dialogService, BibDatabaseContext databaseContext, TaskExecutor taskExecutor, FieldCheckers fieldCheckers, - JabRefPreferences preferences, - JournalAbbreviationLoader journalAbbreviationLoader) { + JabRefPreferences preferences) { super(fieldName, suggestionProvider, fieldCheckers); this.dialogService = dialogService; this.databaseContext = databaseContext; this.taskExecutor = taskExecutor; this.preferences = preferences; - this.journalAbbreviationLoader = journalAbbreviationLoader; + BindingsHelper.bindContentBidirectional( files, @@ -101,7 +98,7 @@ public LinkedFileViewModel fromFile(Path file) { List fileDirectories = databaseContext.getFileDirectoriesAsPaths(preferences.getFileDirectoryPreferences()); LinkedFile linkedFile = fromFile(file, fileDirectories); - return new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, journalAbbreviationLoader); + return new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences); } @@ -115,7 +112,7 @@ public BooleanProperty fulltextLookupInProgressProperty() { private List parseToFileViewModel(String stringValue) { return FileFieldParser.parse(stringValue).stream() - .map(linkedFile -> new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, journalAbbreviationLoader)) + .map(linkedFile -> new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences)) .collect(Collectors.toList()); } @@ -138,7 +135,7 @@ public void addNewFile() { List fileDirectories = databaseContext.getFileDirectoriesAsPaths(preferences.getFileDirectoryPreferences()); dialogService.showFileOpenDialog(fileDialogConfiguration).ifPresent(newFile -> { LinkedFile newLinkedFile = fromFile(newFile, fileDirectories); - files.add(new LinkedFileViewModel(newLinkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, journalAbbreviationLoader)); + files.add(new LinkedFileViewModel(newLinkedFile, entry, databaseContext, taskExecutor, dialogService, preferences)); }); } @@ -164,7 +161,7 @@ private List findAssociatedNotLinkedFiles(BibEntry entry) { try { List linkedFiles = util.findAssociatedNotLinkedFiles(entry); for (LinkedFile linkedFile : linkedFiles) { - LinkedFileViewModel newLinkedFile = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, journalAbbreviationLoader); + LinkedFileViewModel newLinkedFile = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences); newLinkedFile.markAsAutomaticallyFound(); result.add(newLinkedFile); } @@ -207,8 +204,7 @@ public void addFromURL() { } private void addFromURL(URL url) { - LinkedFileViewModel onlineFile = new LinkedFileViewModel(new LinkedFile("", url, ""), - entry, databaseContext, taskExecutor, dialogService, preferences, null); + LinkedFileViewModel onlineFile = new LinkedFileViewModel(new LinkedFile("", url, ""), entry, databaseContext, taskExecutor, dialogService, preferences); files.add(onlineFile); onlineFile.download(); } diff --git a/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java b/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java index 0d365ca033c..95cfedaf088 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java +++ b/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java @@ -242,7 +242,7 @@ private TableColumn> createFileColumn() .withOnMouseClickedEvent((entry, linkedFiles) -> event -> { if ((event.getButton() == MouseButton.PRIMARY) && (linkedFiles.size() == 1)) { // Only one linked file -> open directly - LinkedFileViewModel linkedFileViewModel = new LinkedFileViewModel(linkedFiles.get(0), entry.getEntry(), database, Globals.TASK_EXECUTOR, dialogService, Globals.prefs, Globals.journalAbbreviationLoader); + LinkedFileViewModel linkedFileViewModel = new LinkedFileViewModel(linkedFiles.get(0), entry.getEntry(), database, Globals.TASK_EXECUTOR, dialogService, Globals.prefs); linkedFileViewModel.open(); } }) @@ -258,7 +258,7 @@ private ContextMenu createFileMenu(BibEntryTableViewModel entry, List linkedFileViewModel.open()); diff --git a/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java b/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java index 672fc8612e7..6708de3a842 100644 --- a/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java +++ b/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java @@ -59,7 +59,7 @@ public void deleteWhenFilePathNotPresentReturnsTrue() { linkedFile = spy(new LinkedFile("", "nonexistent file", "")); doReturn(Optional.empty()).when(linkedFile).findIn(any(BibDatabaseContext.class), any(FileDirectoryPreferences.class)); - LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, abbreviationLoader); + LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences); boolean removed = viewModel.delete(fileDirectoryPreferences); assertTrue(removed); @@ -78,7 +78,7 @@ public void deleteWhenRemoveChosenReturnsTrue() throws IOException { any(ButtonType.class), any(ButtonType.class))).thenAnswer(invocation -> Optional.of(invocation.getArgument(3))); // first vararg - remove button - LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, abbreviationLoader); + LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences); boolean removed = viewModel.delete(fileDirectoryPreferences); assertTrue(removed); @@ -97,7 +97,7 @@ public void deleteWhenDeleteChosenReturnsTrueAndDeletesFile() throws IOException any(ButtonType.class), any(ButtonType.class))).thenAnswer(invocation -> Optional.of(invocation.getArgument(4))); // second vararg - delete button - LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, abbreviationLoader); + LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences); boolean removed = viewModel.delete(fileDirectoryPreferences); assertTrue(removed); @@ -115,7 +115,7 @@ public void deleteWhenDeleteChosenAndFileMissingReturnsFalse() throws IOExceptio any(ButtonType.class), any(ButtonType.class))).thenAnswer(invocation -> Optional.of(invocation.getArgument(4))); // second vararg - delete button - LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, abbreviationLoader); + LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences); boolean removed = viewModel.delete(fileDirectoryPreferences); verify(dialogService).showErrorDialogAndWait(anyString(), anyString()); @@ -134,7 +134,7 @@ public void deleteWhenDialogCancelledReturnsFalse() throws IOException { any(ButtonType.class), any(ButtonType.class))).thenAnswer(invocation -> Optional.of(invocation.getArgument(5))); // third vararg - cancel button - LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, abbreviationLoader); + LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences); boolean removed = viewModel.delete(fileDirectoryPreferences); assertFalse(removed); From 06d6736cfa4c7c033418c1f16ebd7b8908c7df66 Mon Sep 17 00:00:00 2001 From: Christoph Date: Mon, 19 Mar 2018 20:30:07 +0100 Subject: [PATCH 08/48] fix failing tests in maintable beta (#3863) except L10n --- src/main/java/org/jabref/gui/BasePanel.java | 2 +- .../externalfiletype/ExternalFileType.java | 1 + .../org/jabref/gui/keyboard/KeyBinding.java | 2 +- .../org/jabref/gui/util/ControlHelper.java | 4 ++- .../java/org/jabref/gui/BasePanelTest.java | 2 ++ .../ExternalFileTypeTest.java | 27 ------------------- 6 files changed, 8 insertions(+), 30 deletions(-) delete mode 100644 src/test/java/org/jabref/gui/externalfiletype/ExternalFileTypeTest.java diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index e5e947cc9c6..fc74d5e4e46 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -1044,7 +1044,7 @@ public void updateTableFont() { private void createMainTable() { bibDatabaseContext.getDatabase().registerListener(SpecialFieldDatabaseChangeListener.INSTANCE); - mainTable = new MainTable(tableModel, frame, this, bibDatabaseContext, preferences.getTablePreferences(), externalFileTypes, Globals.getKeyPrefs()); + mainTable = new MainTable(tableModel, frame, this, bibDatabaseContext, preferences.getTablePreferences(), externalFileTypes, preferences.getKeyBindings()); mainTable.updateFont(); diff --git a/src/main/java/org/jabref/gui/externalfiletype/ExternalFileType.java b/src/main/java/org/jabref/gui/externalfiletype/ExternalFileType.java index 3a35e2f2b78..24ad50cb721 100644 --- a/src/main/java/org/jabref/gui/externalfiletype/ExternalFileType.java +++ b/src/main/java/org/jabref/gui/externalfiletype/ExternalFileType.java @@ -175,6 +175,7 @@ public JabRefIcon getIcon() { } public void setIcon(JabRefIcon icon) { + Objects.requireNonNull(icon); this.icon = icon; label.setIcon(this.icon.getSmallIcon()); } diff --git a/src/main/java/org/jabref/gui/keyboard/KeyBinding.java b/src/main/java/org/jabref/gui/keyboard/KeyBinding.java index 7d43191a679..e5adbad4de3 100644 --- a/src/main/java/org/jabref/gui/keyboard/KeyBinding.java +++ b/src/main/java/org/jabref/gui/keyboard/KeyBinding.java @@ -12,7 +12,7 @@ public enum KeyBinding { CLEANUP("Cleanup", Localization.lang("Cleanup entries"), "alt+F8", KeyBindingCategory.QUALITY), CLOSE_DATABASE("Close library", Localization.lang("Close library"), "ctrl+W", KeyBindingCategory.FILE), CLOSE_DIALOG("Close dialog", Localization.lang("Close dialog"), "ESCAPE", KeyBindingCategory.FILE), - CLOSE_ENTRY_EDITOR("Close entry editor", Localization.lang("Close entry editor"), "ESC", KeyBindingCategory.VIEW), + CLOSE_ENTRY_EDITOR("Close entry editor", Localization.lang("Close entry editor"), "Esc", KeyBindingCategory.VIEW), COPY("Copy", Localization.lang("Copy"), "ctrl+C", KeyBindingCategory.EDIT), COPY_TITLE("Copy title", Localization.lang("Copy title"), "ctrl+shift+alt+T", KeyBindingCategory.EDIT), COPY_CITE_BIBTEX_KEY("Copy \\cite{BibTeX key}", Localization.lang("Copy \\cite{BibTeX key}"), "ctrl+K", KeyBindingCategory.EDIT), diff --git a/src/main/java/org/jabref/gui/util/ControlHelper.java b/src/main/java/org/jabref/gui/util/ControlHelper.java index 72bad6ead3d..971996085e7 100644 --- a/src/main/java/org/jabref/gui/util/ControlHelper.java +++ b/src/main/java/org/jabref/gui/util/ControlHelper.java @@ -29,7 +29,9 @@ public static void loadFXMLForControl(Parent control) { fxmlLoader.load(); // Add our base css file - Globals.getThemeLoader().installBaseCss(control); + if (Globals.getThemeLoader() != null) { + Globals.getThemeLoader().installBaseCss(control); + } } catch (IOException exception) { LOGGER.error("Problem loading fxml for control", exception); diff --git a/src/test/java/org/jabref/gui/BasePanelTest.java b/src/test/java/org/jabref/gui/BasePanelTest.java index 33969b7e6e8..e6f40bdc018 100644 --- a/src/test/java/org/jabref/gui/BasePanelTest.java +++ b/src/test/java/org/jabref/gui/BasePanelTest.java @@ -12,6 +12,7 @@ import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.preferences.PreviewPreferences; +import org.jabref.testutils.category.GUITest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -23,6 +24,7 @@ import static org.mockito.Mockito.RETURNS_MOCKS; import static org.mockito.Mockito.mock; +@GUITest @ExtendWith(ApplicationExtension.class) public class BasePanelTest { diff --git a/src/test/java/org/jabref/gui/externalfiletype/ExternalFileTypeTest.java b/src/test/java/org/jabref/gui/externalfiletype/ExternalFileTypeTest.java deleted file mode 100644 index 5ac0251c147..00000000000 --- a/src/test/java/org/jabref/gui/externalfiletype/ExternalFileTypeTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.jabref.gui.externalfiletype; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertNotNull; - -public class ExternalFileTypeTest { - - @Test - public void getOpenWithApplicationMustNotReturnNull() throws Exception { - ExternalFileType type = new ExternalFileType(null, null, null, null, null, null); - assertNotNull(type.getOpenWithApplication()); - } - - @Test - public void getExtensionMustNotReturnNull() throws Exception { - ExternalFileType type = new ExternalFileType(null, null, null, null, null, null); - assertNotNull(type.getExtension()); - } - - @Test - public void getMimeTypeMustNotReturnNull() throws Exception { - ExternalFileType type = new ExternalFileType(null, null, null, null, null, null); - assertNotNull(type.getMimeType()); - } - -} From b9f80040d8a9ce5046a111baa3f809ff5582b9f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Lenhard?= Date: Mon, 19 Mar 2018 21:49:27 +0100 Subject: [PATCH 09/48] Do no longer log InvalidFieldValueExceptions during autosave (#3865) --- CHANGELOG.md | 1 + .../logic/autosaveandbackup/BackupManager.java | 14 ++++++++++++++ .../org/jabref/logic/bibtex/BibEntryWriter.java | 2 +- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 227667bea99..4f2779ea27c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ The new default removes the linked file from the entry instead of deleting the f - Pressing ESC while searching will clear the search field and select the first entry, if available, in the table. [koppor#293](https://github.com/koppor/jabref/issues/293) - We changed the metadata reading and writing. DublinCore is now the only metadata format, JabRef supports. (https://github.com/JabRef/jabref/pull/3710) - We added another CLI functionality for reading and writing metadata to pdfs. (see https://github.com/JabRef/jabref/pull/3756 and see http://help.jabref.org/en/CommandLine) +- We no longer print errors in field values during autosave into the log [#3811](https://github.com/JabRef/jabref/issues/3811) ### Fixed - We fixed several performance problems with the management of journal abbreviations [#3323](https://github.com/JabRef/jabref/issues/3323) diff --git a/src/main/java/org/jabref/logic/autosaveandbackup/BackupManager.java b/src/main/java/org/jabref/logic/autosaveandbackup/BackupManager.java index f3e7e813352..6c423fc487c 100644 --- a/src/main/java/org/jabref/logic/autosaveandbackup/BackupManager.java +++ b/src/main/java/org/jabref/logic/autosaveandbackup/BackupManager.java @@ -15,6 +15,7 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.jabref.logic.bibtex.InvalidFieldValueException; import org.jabref.logic.exporter.BibtexDatabaseWriter; import org.jabref.logic.exporter.FileSaveSession; import org.jabref.logic.exporter.SaveException; @@ -123,6 +124,19 @@ private void performBackup(Path backupPath) { new BibtexDatabaseWriter<>(FileSaveSession::new).saveDatabase(bibDatabaseContext, savePreferences).commit (backupPath); } catch (SaveException e) { + logIfCritical(e); + } + } + + private void logIfCritical(SaveException e) { + Throwable innermostCause = e; + while (innermostCause.getCause() != null) { + innermostCause = innermostCause.getCause(); + } + boolean isErrorInField = innermostCause instanceof InvalidFieldValueException; + + // do not print errors in field values into the log during autosave + if (!isErrorInField) { LOGGER.error("Error while saving file.", e); } } diff --git a/src/main/java/org/jabref/logic/bibtex/BibEntryWriter.java b/src/main/java/org/jabref/logic/bibtex/BibEntryWriter.java index b3a4d0c6a69..775ebd0d842 100644 --- a/src/main/java/org/jabref/logic/bibtex/BibEntryWriter.java +++ b/src/main/java/org/jabref/logic/bibtex/BibEntryWriter.java @@ -153,7 +153,7 @@ private void writeField(BibEntry entry, Writer out, String name, int indentation out.write(fieldFormatter.format(field.get(), name)); out.write(',' + OS.NEWLINE); } catch (InvalidFieldValueException ex) { - throw new IOException("Error in field '" + name + "': " + ex.getMessage()); + throw new IOException("Error in field '" + name + "': " + ex.getMessage(), ex); } } } From 9ebbfecf48b9eee20a387868b75ec783475c18cc Mon Sep 17 00:00:00 2001 From: Stefan Kolb Date: Tue, 20 Mar 2018 22:19:07 +0100 Subject: [PATCH 10/48] IsiImporter code is a catastrophy #3830 --- .../logic/importer/fileformat/IsiImporter.java | 17 ++++++++++------- .../importer/fileformat/IsiImporterTest.java | 5 ++--- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/jabref/logic/importer/fileformat/IsiImporter.java b/src/main/java/org/jabref/logic/importer/fileformat/IsiImporter.java index 2fae91e67fa..3078d22ee51 100644 --- a/src/main/java/org/jabref/logic/importer/fileformat/IsiImporter.java +++ b/src/main/java/org/jabref/logic/importer/fileformat/IsiImporter.java @@ -41,6 +41,9 @@ public class IsiImporter extends Importer { // extra | at the end: private static final Pattern ISI_PATTERN = Pattern.compile("FN ISI Export Format|VR 1.|PY \\d{4}"); + private static final String EOL = "EOLEOL"; + private static final Pattern EOL_PATTERN = Pattern.compile(EOL); + @Override public String getName() { return "ISI"; @@ -160,7 +163,7 @@ public ParserResult importDatabase(BufferedReader reader) throws IOException { sb.append(" ## "); // mark the beginning of each field sb.append(str); } else { - sb.append("EOLEOL"); // mark the end of each line + sb.append(EOL); // mark the end of each line sb.append(str.trim()); // remove the initial spaces } } @@ -212,7 +215,7 @@ public ParserResult importDatabase(BufferedReader reader) throws IOException { } else if ("JO".equals(beg)) { hm.put(FieldName.BOOKTITLE, value); } else if ("AU".equals(beg)) { - String author = IsiImporter.isiAuthorsConvert(value.replace("EOLEOL", " and ")); + String author = IsiImporter.isiAuthorsConvert(EOL_PATTERN.matcher(value).replaceAll(" and ")); // if there is already someone there then append with "and" if (hm.get(FieldName.AUTHOR) != null) { @@ -221,12 +224,12 @@ public ParserResult importDatabase(BufferedReader reader) throws IOException { hm.put(FieldName.AUTHOR, author); } else if ("TI".equals(beg)) { - hm.put(FieldName.TITLE, value.replace("EOLEOL", " ")); + hm.put(FieldName.TITLE, EOL_PATTERN.matcher(value).replaceAll(" ")); } else if ("SO".equals(beg) || "JA".equals(beg)) { - hm.put(FieldName.JOURNAL, value.replace("EOLEOL", " ")); + hm.put(FieldName.JOURNAL, EOL_PATTERN.matcher(value).replaceAll(" ")); } else if ("ID".equals(beg) || "KW".equals(beg)) { - value = value.replace("EOLEOL", " "); + value = EOL_PATTERN.matcher(value).replaceAll(" "); String existingKeywords = hm.get(FieldName.KEYWORDS); if ((existingKeywords == null) || existingKeywords.contains(value)) { existingKeywords = value; @@ -236,7 +239,7 @@ public ParserResult importDatabase(BufferedReader reader) throws IOException { hm.put(FieldName.KEYWORDS, existingKeywords); } else if ("AB".equals(beg)) { - hm.put(FieldName.ABSTRACT, value.replace("EOLEOL", " ")); + hm.put(FieldName.ABSTRACT, EOL_PATTERN.matcher(value).replaceAll(" ")); } else if ("BP".equals(beg) || "BR".equals(beg) || "SP".equals(beg)) { pages = value; } else if ("EP".equals(beg)) { @@ -279,7 +282,7 @@ public ParserResult importDatabase(BufferedReader reader) throws IOException { Type = BibEntry.DEFAULT_TYPE; } } else if ("CR".equals(beg)) { - hm.put("CitedReferences", value.replace("EOLEOL", " ; ").trim()); + hm.put("CitedReferences", EOL_PATTERN.matcher(value).replaceAll(" ; ").trim()); } else { // Preserve all other entries except if ("ER".equals(beg) || "EF".equals(beg) || "VR".equals(beg) || "FN".equals(beg)) { diff --git a/src/test/java/org/jabref/logic/importer/fileformat/IsiImporterTest.java b/src/test/java/org/jabref/logic/importer/fileformat/IsiImporterTest.java index cc5e4c87bb7..ed81c732d4c 100644 --- a/src/test/java/org/jabref/logic/importer/fileformat/IsiImporterTest.java +++ b/src/test/java/org/jabref/logic/importer/fileformat/IsiImporterTest.java @@ -20,7 +20,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; - /** * Test cases for the IsiImporter */ @@ -70,13 +69,13 @@ public void testGetDescription() { @ParameterizedTest @MethodSource("fileNames") - public void testIsRecognizedFormatAccepted(String fileName) throws IOException, URISyntaxException { + public void testIsRecognizedFormatAccepted(String fileName) throws IOException { ImporterTestEngine.testIsRecognizedFormat(importer, fileName); } @ParameterizedTest @MethodSource("invalidFileNames") - public void testIsRecognizedFormatRejected(String fileName) throws IOException, URISyntaxException { + public void testIsRecognizedFormatRejected(String fileName) throws IOException { ImporterTestEngine.testIsNotRecognizedFormat(importer, fileName); } From 8b897a8444b7fc1f81d75d4523cca58fcee347e3 Mon Sep 17 00:00:00 2001 From: Stefan Kolb Date: Tue, 20 Mar 2018 22:37:28 +0100 Subject: [PATCH 11/48] Fix label values for database connection #3118 --- .../org/jabref/gui/shared/ConnectToSharedDatabaseDialog.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/gui/shared/ConnectToSharedDatabaseDialog.java b/src/main/java/org/jabref/gui/shared/ConnectToSharedDatabaseDialog.java index 4d6c3563120..7f076e232fa 100644 --- a/src/main/java/org/jabref/gui/shared/ConnectToSharedDatabaseDialog.java +++ b/src/main/java/org/jabref/gui/shared/ConnectToSharedDatabaseDialog.java @@ -72,9 +72,9 @@ public class ConnectToSharedDatabaseDialog extends JabRefDialog { private final JPanel filePanel = new JPanel(); private final JPanel buttonPanel = new JPanel(); - private final JLabel databaseTypeLabel = new JLabel(Localization.lang("Library type") + ":"); + private final JLabel databaseTypeLabel = new JLabel(Localization.lang("Database type") + ":"); private final JLabel hostPortLabel = new JLabel(Localization.lang("Host") + "/" + Localization.lang("Port") + ":"); - private final JLabel databaseLabel = new JLabel(Localization.lang("Library") + ":"); + private final JLabel databaseLabel = new JLabel(Localization.lang("Database") + ":"); private final JLabel userLabel = new JLabel(Localization.lang("User") + ":"); private final JLabel passwordLabel = new JLabel(Localization.lang("Password") + ":"); @@ -468,7 +468,6 @@ private boolean isSharedDatabaseAlreadyPresent() { } private void showFileChooser() { - FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder() .addExtensionFilter(FileType.BIBTEX_DB) .withDefaultExtension(FileType.BIBTEX_DB) From 9b454a3a65aaaf0912ee5f7057b826f5c651db1a Mon Sep 17 00:00:00 2001 From: Stefan Kolb Date: Wed, 21 Mar 2018 22:15:01 +0100 Subject: [PATCH 12/48] Fix l10n missing keys --- src/main/resources/l10n/JabRef_en.properties | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 785bfc0008d..e324a922065 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2352,3 +2352,5 @@ Group\ containing\ entries\ cited\ in\ a\ given\ TeX\ file=Group containing entr Any\ file=Any file No\ linked\ files\ found\ for\ export.=No linked files found for export. +Database=Database +Database\ type=Database type From 8c16322da7b248c741ede057dca385df2014fb53 Mon Sep 17 00:00:00 2001 From: Stefan Kolb Date: Thu, 22 Mar 2018 09:22:24 +0100 Subject: [PATCH 13/48] Obsolete language key --- src/main/resources/l10n/JabRef_en.properties | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index e324a922065..4fd19564f66 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -283,8 +283,6 @@ Library\ encoding=Library encoding Library\ properties=Library properties -Library\ type=Library type - Date\ format=Date format Default=Default From 05e1f35edb95ab83a51ac9300aa4999cb66d8fec Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 22 Mar 2018 10:05:23 +0100 Subject: [PATCH 14/48] Update to MADR 2.0.3 --- ...markdown-architectural-decision-records.md | 24 ++++++----- docs/adr/0001-use-crowdin-for-translations.md | 10 +++-- docs/adr/0002-use-slf4j-for-logging.md | 43 +++++++++++-------- docs/adr/index.md | 2 + docs/adr/template.md | 43 ++++++++----------- 5 files changed, 65 insertions(+), 57 deletions(-) diff --git a/docs/adr/0000-use-markdown-architectural-decision-records.md b/docs/adr/0000-use-markdown-architectural-decision-records.md index 3f3f2a283f4..be7d1ed5fa8 100644 --- a/docs/adr/0000-use-markdown-architectural-decision-records.md +++ b/docs/adr/0000-use-markdown-architectural-decision-records.md @@ -1,23 +1,25 @@ # Use Markdown Architectural Decision Records -Should we record the architectural decisions made in this project? -And if we do, wow to structure these recordings? +## Context and Problem Statement -## Considered Alternatives +We want to record architectural decisions made in this project. +Which format and structure should these records follow? -* [MADR](https://adr.github.io/madr/) - Markdown Architectural Decision Records -* [Michael Nygard's template](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions) - The first incarnation of the term "ADR". Maintainable by [adr-tools](https://github.com/npryce/adr-tools). +## Considered Options + +* [MADR](https://adr.github.io/madr/) 2.0.3 - The Markdown Architectural Decision Records +* [Michael Nygard's template](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions) - The first incarnation of the term "ADR" * [Sustainable Architectural Decisions](https://www.infoq.com/articles/sustainable-architectural-design-decisions) - The Y-Statements -* [DecisionRecord](https://github.com/schubmat/DecisionCapture) - Agile records by [@schubmat](https://github.com/schubmat/) * Other templates listed at -* No records +* Formless - No conventions for file format and structure ## Decision Outcome -* Chosen Alternative: MADR +Chosen option: "MADR 2.0.3", because * Implicit assumptions should be made explicit. Design documentation is important to enable people understanding the decisions later on. See also [A rational design process: How and why to fake it](https://doi.org/10.1109/TSE.1986.6312940). -* The MADR template is lean and fits our development style. - - +* The MADR format is lean and fits our development style. +* The MADR structure is comprehensible and facilitates usage & maintenance. +* The MADR project is vivid. +* Version 2.0.3 is the latest one available when starting to document ADRs. diff --git a/docs/adr/0001-use-crowdin-for-translations.md b/docs/adr/0001-use-crowdin-for-translations.md index c98ae57d733..0d8955782ab 100644 --- a/docs/adr/0001-use-crowdin-for-translations.md +++ b/docs/adr/0001-use-crowdin-for-translations.md @@ -1,14 +1,16 @@ -# Use Crowdin for tranlsations +# Use Crowdin for translations + +## Context and Problem Statement The JabRef UI is offered in multiple languages. It should be easy for translators to translate the strings. -## Considered Alternatives +## Considered Options * Use [Crowdin](http://crowdin.com/) * Use [popeye](https://github.com/JabRef/popeye) * Use [Lingohub](https://lingohub.com/) +* Keep current GitHub flow. See the [Step-by-step guide](https://github.com/JabRef/help.jabref.org/blob/d5569bebdb0e1de5c71401bbfba45311c19c80a8/en/TranslatingGUI.md#step-by-step-guide). ## Decision Outcome -* Chosen Alternative: Crowdin -* Crowdin is easy to use, integrates in our GitHub workflow, and is free for OSS projects. +Chosen option: "Use Crowdin", because Crowdin is easy to use, integrates in our GitHub workflow, and is free for OSS projects. diff --git a/docs/adr/0002-use-slf4j-for-logging.md b/docs/adr/0002-use-slf4j-for-logging.md index b9aabc823d0..b17996fe59d 100644 --- a/docs/adr/0002-use-slf4j-for-logging.md +++ b/docs/adr/0002-use-slf4j-for-logging.md @@ -1,7 +1,13 @@ # Use slf4j together with log4j2 for logging -* Up to version 4.1 JabRef uses apache-ommons-logging 1.2 for logging errors and messages. However, this is not compatible with java 9 and is superseded by log4j. -* SLF4J provides a facade for several logging frameworks, including log4j and supports already java 9 +## Context and Problem Statement + +Up to version 4.1 JabRef uses apache-commons-logging 1.2 for logging errors and messages. +However, this is not compatible with java 9 and is superseded by log4j. + +## Decision Drivers + +* SLF4J provides a façade for several logging frameworks, including log4j and supports already java 9 * Log4j is already defined as dependency and slf4j has already been required by a third party dependency ## Considered Alternatives @@ -11,33 +17,34 @@ * [SLF4J with Logback binding](https://logback.qos.ch/) ## Decision Outcome -* We chose slf4j with log4j2 binding, because it only requires minimal changes to our logging infrastructure and it is claimed that -> Apache Log4j 2 is an upgrade to Log4j that provides significant improvements over its predecessor, Log4j 1.x, and provides many of the improvements available in Logback while fixing some inherent problems in Logback’s architecture. -* Furthermore, as slf4j is a facade for several loggers, the underlying implementation can easily be changed in the future +Chosen option: "SLF4J with Log4j2 binding", because comes out best (see below). -## Pros and Cons of the Alternatives +## Pros and Cons of the Options ### Log4j2 -* `+` Dependency already exists -* `+` Java 9 support since version 2.10 -* `-` Direct dependency +* Good, because dependency already exists +* Good, because Java 9 support since version 2.10 +* Bad, because direct dependency ### SLF4J with log4j2 binding -* `+` Supports other loggers as well -* `+` Java 9 support -* `+` Already defined -* `+` Migration tool available -* `-` Logger statements require a slight different syntax +* Good, because it only requires minimal changes to our logging infrastructure +* Good, because Apache Log4j 2 is an upgrade to Log4j that provides significant improvements over its predecessor, Log4j 1.x, and provides many of the improvements available in Logback while fixing some inherent problems in Logback’s architecture. +* Good, because supports other loggers as well +* Good, because Java 9 support +* Good, because already defined +* Good, because migration tool available +* Good, because it is a façade for several loggers. Thus, the underlying implementation can easily be changed in the future. +* Bad, because logger statements require a slight different syntax ### SLF4J with Logback binding -* `+` Migration tool available -* `+` Native implementation of slf4j -* `-` Java 9 support only available in alpha -* `-` Different syntax than log4j/commons logging +* Good, because migration tool available +* Good, because native implementation of slf4j +* Bad, because Java 9 support only available in alpha +* Bad, because different syntax than log4j/commons logging diff --git a/docs/adr/index.md b/docs/adr/index.md index c622674a03b..98c4e216f4d 100644 --- a/docs/adr/index.md +++ b/docs/adr/index.md @@ -5,6 +5,8 @@ This log lists the architectural decisions for JabRef. - [ADR-0000](0000-use-markdown-architectural-decision-records.md) - Use Markdown Architectural Decision Records +- [ADR-0001](0001-use-crowdin-for-translations.md) - Use Crowdin for translations +- [ADR-0002](0002-use-slf4j-for-logging.md) - Use slf4j together with log4j2 for logging diff --git a/docs/adr/template.md b/docs/adr/template.md index 7402da4d20e..e4659b49b2b 100644 --- a/docs/adr/template.md +++ b/docs/adr/template.md @@ -1,75 +1,70 @@ # [short title of solved problem and solution] -* Status: [accepted | superseeded by [ADR-0005](0005-example.md) | deprecated | ...] +* Status: [accepted | superseeded by [ADR-0005](0005-example.md) | deprecated | …] * Deciders: [list everyone involved in the decision] -* Date: [when the decision was last updated] +* Date: [YYYY-MM-DD when the decision was last updated] Technical Story: [description | ticket/issue URL] - ## Context and Problem Statement -[Describe the context and problem statement, e.g., in free form using two to three sentences. You may want to articulate the problem in form of a question.] +[Describe the context and problem statement, e.g., in free form using two to three sentences. You may want to articulate the problem in form of a question.] ## Decision Drivers -* [driver 1, e.g., a force, facing concern, ...] -* [driver 2, e.g., a force, facing concern, ...] -* ... - +* [driver 1, e.g., a force, facing concern, …] +* [driver 2, e.g., a force, facing concern, …] +* … ## Considered Options * [option 1] * [option 2] * [option 3] -* ... - +* … ## Decision Outcome -Chosen option: "[option 1]", because [justification. e.g., only option, which meets k.o. criterion decision driver | which resolves force force | ... | comes out best (see below)]. +Chosen option: "[option 1]", because [justification. e.g., only option, which meets k.o. criterion decision driver | which resolves force force | … | comes out best (see below)]. Positive Consequences: -* [e.g., improvement of quality attribute satisfaction, follow-up decisions required, ...] -* ... +* [e.g., improvement of quality attribute satisfaction, follow-up decisions required, …] +* … Negative consequences: -* [e.g., compromising quality attribute, follow-up decisions required, ...] -* ... - +* [e.g., compromising quality attribute, follow-up decisions required, …] +* … ## Pros and Cons of the Options ### [option 1] -[example | description | pointer to more information | ...] +[example | description | pointer to more information | …] * Good, because [argument a] * Good, because [argument b] * Bad, because [argument c] -* ... +* … ### [option 2] -[example | description | pointer to more information | ...] +[example | description | pointer to more information | …] * Good, because [argument a] * Good, because [argument b] * Bad, because [argument c] -* ... +* … ### [option 3] -[example | description | pointer to more information | ...] +[example | description | pointer to more information | …] * Good, because [argument a] * Good, because [argument b] * Bad, because [argument c] -* ... - +* … ## Links * [Link type] [Link to ADR] -* ... +* … From 6a646f74bccaffd7ffbb3c21a87550172d2ac495 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 22 Mar 2018 10:27:46 +0100 Subject: [PATCH 15/48] New translations JabRef_en.properties (French) --- src/main/resources/l10n/JabRef_fr.properties | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/resources/l10n/JabRef_fr.properties b/src/main/resources/l10n/JabRef_fr.properties index cf10a0ae158..f15f67def42 100644 --- a/src/main/resources/l10n/JabRef_fr.properties +++ b/src/main/resources/l10n/JabRef_fr.properties @@ -284,8 +284,6 @@ Library\ encoding=Encodage du fichier Library\ properties=Propriétés du fichier -Library\ type=Type de fichier - Date\ format=Format de date Default=Défaut From 28c8f86903663edf7b957f2f984368985023e293 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 22 Mar 2018 10:27:50 +0100 Subject: [PATCH 16/48] New translations JabRef_en.properties (Spanish) --- src/main/resources/l10n/JabRef_es.properties | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/resources/l10n/JabRef_es.properties b/src/main/resources/l10n/JabRef_es.properties index 35f892b49ce..e5fab410d79 100644 --- a/src/main/resources/l10n/JabRef_es.properties +++ b/src/main/resources/l10n/JabRef_es.properties @@ -282,8 +282,6 @@ Library\ encoding=Codificación de la biblioteca Library\ properties=Propiedades de la biblioteca -Library\ type=Tipo de biblioteca - Date\ format=Formato de fecha Default=Por defecto From 27bc2aac7fa1c2526fb42e1770367b363cf4349f Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 22 Mar 2018 10:27:55 +0100 Subject: [PATCH 17/48] New translations JabRef_en.properties (Persian) --- src/main/resources/l10n/JabRef_fa.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/resources/l10n/JabRef_fa.properties b/src/main/resources/l10n/JabRef_fa.properties index d00d259998c..ae937055d15 100644 --- a/src/main/resources/l10n/JabRef_fa.properties +++ b/src/main/resources/l10n/JabRef_fa.properties @@ -139,7 +139,6 @@ - Delete\ entry=حذف مدخل From 6f7ff49d0c605a42ffbf22a5749b5463ad8026c3 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 22 Mar 2018 10:27:59 +0100 Subject: [PATCH 18/48] New translations JabRef_en.properties (Portuguese, Brazilian) --- src/main/resources/l10n/JabRef_pt_BR.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/resources/l10n/JabRef_pt_BR.properties b/src/main/resources/l10n/JabRef_pt_BR.properties index eab79f59392..2974df751bb 100644 --- a/src/main/resources/l10n/JabRef_pt_BR.properties +++ b/src/main/resources/l10n/JabRef_pt_BR.properties @@ -276,7 +276,6 @@ Library\ encoding=Codificação da base de dados Library\ properties=Propriedades da base de dados - Date\ format=Formato de data Default=Padrão From 937400e4428bc352e2b459dd7acbd455436a0507 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 22 Mar 2018 10:28:03 +0100 Subject: [PATCH 19/48] New translations JabRef_en.properties (Russian) --- src/main/resources/l10n/JabRef_ru.properties | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/resources/l10n/JabRef_ru.properties b/src/main/resources/l10n/JabRef_ru.properties index 6849d5abb89..edb0e508c7e 100644 --- a/src/main/resources/l10n/JabRef_ru.properties +++ b/src/main/resources/l10n/JabRef_ru.properties @@ -277,8 +277,6 @@ Library\ encoding=Кодировка БД Library\ properties=Свойства БД -Library\ type=Тип БД - Date\ format=Формат БД Default=По умолчанию From c34014e4c914a310ddb5d44f545d0daab70a1aa8 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 22 Mar 2018 10:28:07 +0100 Subject: [PATCH 20/48] New translations JabRef_en.properties (Norwegian) --- src/main/resources/l10n/JabRef_no.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/resources/l10n/JabRef_no.properties b/src/main/resources/l10n/JabRef_no.properties index 849e5ccd195..08e8fdaed18 100644 --- a/src/main/resources/l10n/JabRef_no.properties +++ b/src/main/resources/l10n/JabRef_no.properties @@ -272,7 +272,6 @@ Library\ encoding=Tegnkoding for library Library\ properties=Libraryegenskaper - Date\ format=Datoformat Default=Tilbakestill From 24ff412f6a83bee6a51d10de38a95f4d319a6ad5 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 22 Mar 2018 10:28:10 +0100 Subject: [PATCH 21/48] New translations JabRef_en.properties (Swedish) --- src/main/resources/l10n/JabRef_sv.properties | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/resources/l10n/JabRef_sv.properties b/src/main/resources/l10n/JabRef_sv.properties index 53aaf718655..e2e276ca5a3 100644 --- a/src/main/resources/l10n/JabRef_sv.properties +++ b/src/main/resources/l10n/JabRef_sv.properties @@ -271,8 +271,6 @@ Library\ encoding=Teckenkodning för databas Library\ properties=Librarygenskaper -Library\ type=Databastyp - Date\ format=Datumformat Default=Standard From 20f9c59dfe1f6e9e56c4bf553252d521c17f5b98 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 22 Mar 2018 10:28:14 +0100 Subject: [PATCH 22/48] New translations JabRef_en.properties (Turkish) --- src/main/resources/l10n/JabRef_tr.properties | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/resources/l10n/JabRef_tr.properties b/src/main/resources/l10n/JabRef_tr.properties index ae4ff81d14c..e05d3efb171 100644 --- a/src/main/resources/l10n/JabRef_tr.properties +++ b/src/main/resources/l10n/JabRef_tr.properties @@ -283,8 +283,6 @@ Library\ encoding=Veritabanı kodlaması Library\ properties=Veritabanı özellikleri -Library\ type=Veritabanı türü - Date\ format=Tarih biçemi Default=Öntanımlı From e32eb2b99529b37997b2e20f79018af4facc5fc7 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 22 Mar 2018 10:28:18 +0100 Subject: [PATCH 23/48] New translations JabRef_en.properties (Vietnamese) --- src/main/resources/l10n/JabRef_vi.properties | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/resources/l10n/JabRef_vi.properties b/src/main/resources/l10n/JabRef_vi.properties index d58875fe2b1..9d57b4a2f4d 100644 --- a/src/main/resources/l10n/JabRef_vi.properties +++ b/src/main/resources/l10n/JabRef_vi.properties @@ -276,8 +276,6 @@ Library\ encoding=Mã hóa CSDL Library\ properties=Tính chất của CSDL -Library\ type=Dạng CSDL - Date\ format=Định dạng ngày Default=Mặc định From 3dc2d2fed5a5bca9b74c80aec50a41bfa535a033 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 22 Mar 2018 10:28:22 +0100 Subject: [PATCH 24/48] New translations JabRef_en.properties (Chinese Simplified) --- src/main/resources/l10n/JabRef_zh.properties | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/resources/l10n/JabRef_zh.properties b/src/main/resources/l10n/JabRef_zh.properties index 166d0ca03c0..569571eaf24 100644 --- a/src/main/resources/l10n/JabRef_zh.properties +++ b/src/main/resources/l10n/JabRef_zh.properties @@ -282,8 +282,6 @@ Library\ encoding=文献库编码 Library\ properties=文献库属性 -Library\ type=文献库类型 - Date\ format=日期格式 Default=默认 From 0666b865b01dba41f4d814124a1a721294d564cd Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 22 Mar 2018 10:28:26 +0100 Subject: [PATCH 25/48] New translations JabRef_en.properties (Danish) --- src/main/resources/l10n/JabRef_da.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/resources/l10n/JabRef_da.properties b/src/main/resources/l10n/JabRef_da.properties index 3e969a02fa7..1ba46c9573d 100644 --- a/src/main/resources/l10n/JabRef_da.properties +++ b/src/main/resources/l10n/JabRef_da.properties @@ -274,7 +274,6 @@ Library\ encoding=Tegnkoding for library Library\ properties=Libraryegenskaber - Date\ format=Datoformat Default=Standard From 177cba16baca09c7ca0c0c6b759f0efdba6c7ff2 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 22 Mar 2018 10:28:30 +0100 Subject: [PATCH 26/48] New translations JabRef_en.properties (Dutch) --- src/main/resources/l10n/JabRef_nl.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/resources/l10n/JabRef_nl.properties b/src/main/resources/l10n/JabRef_nl.properties index 11659a4ae4e..b69aaa4a0d9 100644 --- a/src/main/resources/l10n/JabRef_nl.properties +++ b/src/main/resources/l10n/JabRef_nl.properties @@ -257,7 +257,6 @@ Library\ encoding=Library encodering Library\ properties=Library eigenschappen - Date\ format=Datum formaat Default=Standaard From 9146b94dcb7053b7fb02aa3afb7bd25b61e737e4 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 22 Mar 2018 10:28:33 +0100 Subject: [PATCH 27/48] New translations JabRef_en.properties (German) --- src/main/resources/l10n/JabRef_de.properties | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/resources/l10n/JabRef_de.properties b/src/main/resources/l10n/JabRef_de.properties index 9f423eba2f9..286de9eb566 100644 --- a/src/main/resources/l10n/JabRef_de.properties +++ b/src/main/resources/l10n/JabRef_de.properties @@ -284,8 +284,6 @@ Library\ encoding=Zeichenkodierung der Bibliothek Library\ properties=Eigenschaften der Bibliothek -Library\ type=Typ der Bibliothek - Date\ format=Datumsformat Default=Standard @@ -2352,4 +2350,5 @@ Group\ containing\ entries\ cited\ in\ a\ given\ TeX\ file=Gruppe mit Einträgen Any\ file=Beliebige Datei +No\ linked\ files\ found\ for\ export.=Keine verknüpften Dateien für den Export gefunden. From eecb317786369d89f90b535c39d299718f4e9deb Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 22 Mar 2018 10:28:37 +0100 Subject: [PATCH 28/48] New translations JabRef_en.properties (Japanese) --- src/main/resources/l10n/JabRef_ja.properties | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/resources/l10n/JabRef_ja.properties b/src/main/resources/l10n/JabRef_ja.properties index e35d500c7bd..3c4ae9a4ccd 100644 --- a/src/main/resources/l10n/JabRef_ja.properties +++ b/src/main/resources/l10n/JabRef_ja.properties @@ -284,8 +284,6 @@ Library\ encoding=データベースのエンコーディング Library\ properties=データベース特性 -Library\ type=データベース型 - Date\ format=日付書式 Default=既定値 @@ -2352,4 +2350,5 @@ Group\ containing\ entries\ cited\ in\ a\ given\ TeX\ file=特定のTeXファイ Any\ file=任意のファイル +No\ linked\ files\ found\ for\ export.=エクスポートしようとしましたが,リンク先のファイルが見つかりません. From 1939ef70a7c9c3906880eeac9c887f925e3c4dd4 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 22 Mar 2018 10:28:38 +0100 Subject: [PATCH 29/48] New translations Menu_en.properties (Greek) --- src/main/resources/l10n/Menu_el.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/l10n/Menu_el.properties b/src/main/resources/l10n/Menu_el.properties index 4a28053d693..7242007853d 100644 --- a/src/main/resources/l10n/Menu_el.properties +++ b/src/main/resources/l10n/Menu_el.properties @@ -6,7 +6,7 @@ Append\ library=&Προσάρτηση βιβλιοθήκης Autogenerate\ BibTeX\ keys=&Αυτόματη παραγωγή BibTeX Close\ library=&Κλείσιμο βιβλιοθήκης Copy=Αντιγραφή -Copy\ title=&Αντιγραφή συνδέσμου (link) +Copy\ title=&Αντιγραφή συνδέσμου Copy\ \\cite{BibTeX\ key}=Αντιγραφή \\c&ite{BibTeX key} Copy\ BibTeX\ key=Αντιγραφή&BibTeX key Customize\ entry\ types=&Προσαρμογή τύπου καταχώρησης @@ -68,7 +68,7 @@ Next\ preview\ layout=&Επόμενη προεπισκόπιση δομής Previous\ preview\ layout=&Προηγούμενη προεπισκόπιση δομής # Export menu Toggle\ entry\ preview=&Εναλλαγή προβολής καταχώρησης -Toggle\ groups\ interface=Εναλλαγή επιφάνειας &ομάδων +Toggle\ groups\ interface=Εναλλαγή επιφάνειας &ομάδων Tools=&Εργαλεία Unabbreviate\ journal\ names=Ονόματα περιοδικών χωρίς συντομογραφία # Edit From ef6886113cdc8d95f66c0a403fd497b79f9a1e82 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 22 Mar 2018 10:28:42 +0100 Subject: [PATCH 30/48] New translations JabRef_en.properties (Greek) --- src/main/resources/l10n/JabRef_el.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/resources/l10n/JabRef_el.properties b/src/main/resources/l10n/JabRef_el.properties index d04dc094108..6f3f1f24b04 100644 --- a/src/main/resources/l10n/JabRef_el.properties +++ b/src/main/resources/l10n/JabRef_el.properties @@ -250,7 +250,6 @@ cut\ entry=αποκοπή entry - Default=Προεπιλογή Default\ encoding=Προεπιλεγμένη κωδικοποίηση From 33e8a670c519263eb74e4a2aede758d5da09f326 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 22 Mar 2018 10:28:45 +0100 Subject: [PATCH 31/48] New translations JabRef_en.properties (Indonesian) --- src/main/resources/l10n/JabRef_in.properties | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/resources/l10n/JabRef_in.properties b/src/main/resources/l10n/JabRef_in.properties index f41a221c28f..cf91a80649a 100644 --- a/src/main/resources/l10n/JabRef_in.properties +++ b/src/main/resources/l10n/JabRef_in.properties @@ -282,8 +282,6 @@ Library\ encoding=Enkoding basisdata Library\ properties=Properti basisdata -Library\ type=Tipe perpustakaan - Date\ format=Format tanggal Default=Bawaan From 8eb1ca5532d069f7621028108175b0c8a29b7bcb Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 22 Mar 2018 10:28:46 +0100 Subject: [PATCH 32/48] New translations Menu_en.properties (Italian) --- src/main/resources/l10n/Menu_it.properties | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/resources/l10n/Menu_it.properties b/src/main/resources/l10n/Menu_it.properties index 10689c8ffc2..49f5cc332c6 100644 --- a/src/main/resources/l10n/Menu_it.properties +++ b/src/main/resources/l10n/Menu_it.properties @@ -21,6 +21,7 @@ Export=&Esporta Export\ selected\ entries\ to\ clipboard=Esporta le voci selezionate negli appunti # Menu names +File=&File Find\ duplicates=Ricerca &duplicati Help=&Aiuto @@ -113,6 +114,7 @@ Open\ folder=Apri cartella Find\ unlinked\ files...=Trovati file non collegati... Hide/show\ toolbar=Mostra/Nascondi la barra degli strumenti +Fork\ me\ on\ GitHub=Esegui il fork da GitHub Save\ selected\ as\ plain\ BibTeX...=Salva la selezione in formato BibTeX base... Groups=Gruppi @@ -123,6 +125,7 @@ Quality=Qualità Online\ help\ forum=Forum di aiuto online Manage\ protected\ terms=Gestione dei termini protetti Website=Sito web +Blog=Blog JabRef\ resources=Risorse per JabRef Development\ version=Versione di sviluppo View\ change\ log=Visualizza la lista delle modifiche From 33e106167fd3a28345d132bffe8641787d05f977 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 22 Mar 2018 10:28:49 +0100 Subject: [PATCH 33/48] New translations JabRef_en.properties (Italian) --- src/main/resources/l10n/JabRef_it.properties | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/resources/l10n/JabRef_it.properties b/src/main/resources/l10n/JabRef_it.properties index 67892000b1c..059305477c7 100644 --- a/src/main/resources/l10n/JabRef_it.properties +++ b/src/main/resources/l10n/JabRef_it.properties @@ -210,6 +210,7 @@ Color\ for\ marking\ incomplete\ entries=Colore per contrassegnare voci incomple Column\ width=Larghezza della colonna Command\ line\ id=Identificativo della riga di comando +Comments=Commenti Contained\ in=Contenuto in @@ -281,8 +282,6 @@ Library\ encoding=Codifica libreria Library\ properties=Proprietà della libreria -Library\ type=Tipo di libreria - Date\ format=Formato data Default=Predefinito @@ -385,6 +384,7 @@ Edit\ entry=Modifica voce Save\ file=Modifica il collegamento al file Edit\ file\ type=Modifica il tipo di file +Add\ group=Aggiungi un gruppo Edit\ group=Modifica il gruppo @@ -470,7 +470,9 @@ Field\ to\ filter=Campi da filtrare Field\ to\ group\ by=Campo di raggruppamento +File=File +file=file File\ '%0'\ is\ already\ open.=Il file '%0' è già aperto. File\ changed=File modificato @@ -801,6 +803,7 @@ Nothing\ to\ undo=Niente da annullare occurrences=ricorrenze +OK=Ok One\ or\ more\ file\ links\ are\ of\ the\ type\ '%0',\ which\ is\ undefined.\ What\ do\ you\ want\ to\ do?=Uno o più collegamenti a file sono del tipo '%0', non definito. Come procedere? One\ or\ more\ keys\ will\ be\ overwritten.\ Continue?=Una o più chiavi saranno sovrascritte. Continuare? @@ -855,6 +858,7 @@ Overwrite\ existing\ field\ values=Sovrascrivi i valori esistenti del campo Overwrite\ keys=Sovrascrivi chiavi pairs\ processed=coppie elaborate +Password=Password Paste=Incolla @@ -1237,6 +1241,7 @@ Use\ autocompletion\ for\ the\ following\ fields=Usa l'autocompletamento per i s Use\ other\ look\ and\ feel=Usa un altro "Look-and-Feel" Use\ regular\ expression\ search=Ricerca l'espressione regolare +Username=Nome utente Value\ cleared\ externally=Valore cancellato esternamente @@ -2200,6 +2205,7 @@ get\ involved=collabora con noi Used\ libraries=Librerie usate Existing\ file=File esistente +ID=ID ID\ type=Tipo di ID ID-based\ entry\ generator=Generatore di voci basato su ID Fetcher\ '%0'\ did\ not\ find\ an\ entry\ for\ id\ '%1'.=Il collettore '%0' non ha trovato una voce per l'id '%1' @@ -2295,6 +2301,9 @@ There\ exists\ already\ a\ group\ with\ the\ same\ name.=Esiste già almeno un g empty\ BibTeX\ key=chiave BibTeX vuota +Aux\ file=File aux +Any\ file=Qualsiasi file +No\ linked\ files\ found\ for\ export.=Nessun file collegati trovati per esportazione. From d765004995fa06393c1af9ad18680b2758bb66bc Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 22 Mar 2018 10:28:53 +0100 Subject: [PATCH 34/48] New translations JabRef_en.properties (Tagalog) --- src/main/resources/l10n/JabRef_tl.properties | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/resources/l10n/JabRef_tl.properties b/src/main/resources/l10n/JabRef_tl.properties index b72d1e4e59c..96fee68b713 100644 --- a/src/main/resources/l10n/JabRef_tl.properties +++ b/src/main/resources/l10n/JabRef_tl.properties @@ -284,8 +284,6 @@ Library\ encoding=Pag-incode ng library Library\ properties=Katangian ng library -Library\ type=Uri ng library - Date\ format=Petsa ng pag-format Default=Default From c2b79b86660514e673d394bf25a6764ff99471f0 Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Fri, 23 Mar 2018 16:08:13 +0100 Subject: [PATCH 35/48] update slf4j from 1.8.0-beta1 -> 1.8.0-beta2 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 149179ee2cc..ad8e5b70a44 100644 --- a/build.gradle +++ b/build.gradle @@ -138,7 +138,7 @@ dependencies { compile 'com.mashape.unirest:unirest-java:1.4.9' // >1.8.0-beta is required for java 9 compatibility - compile 'org.slf4j:slf4j-api:1.8.0-beta1' + compile 'org.slf4j:slf4j-api:1.8.0-beta2' compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.11.0' compile 'org.apache.logging.log4j:log4j-jcl:2.11.0' compile 'org.apache.logging.log4j:log4j-api:2.11.0' From 3c4a3ef65e62dab6b0382f7db6fced8abb59a581 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Fri, 23 Mar 2018 19:37:59 +0100 Subject: [PATCH 36/48] Make it easier to create FXML dialogs (#3880) * Extract swing dialog display to dialog service * Embed preference dialog in JavaFX window * Use new version of afterburner * Fix injection into controller classes * Fix build and code cleanup --- build.gradle | 3 +- javafx/scene/control/annotations.xml | 5 + lib/afterburner.fx.jar | Bin 0 -> 18245 bytes .../org/jabref/gui/AbstractController.java | 35 -- .../org/jabref/gui/AbstractDialogView.java | 16 - .../java/org/jabref/gui/AbstractView.java | 50 --- .../java/org/jabref/gui/DefaultInjector.java | 10 + .../org/jabref/gui/actions/CleanupAction.java | 27 +- .../jabref/gui/actions/CopyFilesAction.java | 4 +- .../gui/actions/ShowPreferencesAction.java | 7 +- .../org/jabref/gui/cleanup/CleanupDialog.java | 34 ++ .../jabref/gui/copyfiles/CopyFilesDialog.fxml | 5 +- .../copyfiles/CopyFilesDialogController.java | 59 --- .../gui/copyfiles/CopyFilesDialogView.java | 77 +++- .../gui/documentviewer/DocumentViewer.fxml | 2 +- .../DocumentViewerController.java | 109 ----- .../documentviewer/DocumentViewerView.java | 133 +++++- .../fileannotationtab/FileAnnotationTab.fxml | 5 +- .../fileannotationtab/FileAnnotationTab.java | 8 +- .../FileAnnotationTabController.java | 144 ------- .../FileAnnotationTabView.java | 136 ++++++- .../jabref/gui/errorconsole/ErrorConsole.css | 5 - .../jabref/gui/errorconsole/ErrorConsole.fxml | 40 +- .../errorconsole/ErrorConsoleController.java | 122 ------ .../gui/errorconsole/ErrorConsoleView.java | 141 ++++++- .../org/jabref/gui/groups/GroupSidePane.java | 6 +- .../java/org/jabref/gui/groups/GroupTree.fxml | 2 +- .../gui/groups/GroupTreeController.java | 378 ----------------- .../org/jabref/gui/groups/GroupTreeView.java | 376 ++++++++++++++++- .../org/jabref/gui/help/AboutDialog.css | 0 .../java/org/jabref/gui/help/AboutDialog.fxml | 91 +++++ .../gui/help/AboutDialogController.java | 77 ---- .../org/jabref/gui/help/AboutDialogView.java | 88 +++- .../journals/ManageJournalAbbreviations.css | 0 .../journals/ManageJournalAbbreviations.fxml | 4 +- .../ManageJournalAbbreviationsController.java | 365 ----------------- .../ManageJournalAbbreviationsView.java | 385 +++++++++++++++++- .../jabref/gui/keyboard/KeyBindingsDialog.css | 5 - .../gui/keyboard/KeyBindingsDialog.fxml | 27 ++ .../keyboard/KeyBindingsDialogController.java | 70 ---- .../gui/keyboard/KeyBindingsDialogView.java | 95 ++++- .../org/jabref/gui/preftabs/ExternalTab.java | 2 +- .../gui/preftabs/PreferencesDialog.java | 141 +++---- .../java/org/jabref/gui/util/BaseDialog.java | 31 ++ .../org/jabref/gui/util/ControlHelper.java | 26 ++ .../java/org/jabref/gui/util/ThemeLoader.java | 4 +- .../org/jabref/logic/l10n/Localization.java | 2 +- .../logic/l10n/LocalizationLocator.java | 12 + ...airhacks.afterburner.views.ResourceLocator | 1 + .../org/jabref/gui/help/AboutDialog.fxml | 108 ----- .../gui/keyboard/KeyBindingsDialog.fxml | 40 -- src/test/java/org/jabref/gui/GUITest.java | 19 - 52 files changed, 1677 insertions(+), 1855 deletions(-) create mode 100644 javafx/scene/control/annotations.xml create mode 100644 lib/afterburner.fx.jar delete mode 100644 src/main/java/org/jabref/gui/AbstractController.java delete mode 100644 src/main/java/org/jabref/gui/AbstractDialogView.java delete mode 100644 src/main/java/org/jabref/gui/AbstractView.java create mode 100644 src/main/java/org/jabref/gui/cleanup/CleanupDialog.java rename src/main/{resources => java}/org/jabref/gui/copyfiles/CopyFilesDialog.fxml (83%) delete mode 100644 src/main/java/org/jabref/gui/copyfiles/CopyFilesDialogController.java delete mode 100644 src/main/java/org/jabref/gui/documentviewer/DocumentViewerController.java delete mode 100644 src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTabController.java delete mode 100644 src/main/java/org/jabref/gui/errorconsole/ErrorConsoleController.java delete mode 100644 src/main/java/org/jabref/gui/groups/GroupTreeController.java rename src/main/{resources => java}/org/jabref/gui/help/AboutDialog.css (100%) create mode 100644 src/main/java/org/jabref/gui/help/AboutDialog.fxml delete mode 100644 src/main/java/org/jabref/gui/help/AboutDialogController.java rename src/main/{resources => java}/org/jabref/gui/journals/ManageJournalAbbreviations.css (100%) rename src/main/{resources => java}/org/jabref/gui/journals/ManageJournalAbbreviations.fxml (93%) delete mode 100644 src/main/java/org/jabref/gui/journals/ManageJournalAbbreviationsController.java rename src/main/{resources => java}/org/jabref/gui/keyboard/KeyBindingsDialog.css (78%) create mode 100644 src/main/java/org/jabref/gui/keyboard/KeyBindingsDialog.fxml delete mode 100644 src/main/java/org/jabref/gui/keyboard/KeyBindingsDialogController.java create mode 100644 src/main/java/org/jabref/gui/util/BaseDialog.java create mode 100644 src/main/java/org/jabref/logic/l10n/LocalizationLocator.java create mode 100644 src/main/resources/META-INF/services/com.airhacks.afterburner.views.ResourceLocator delete mode 100644 src/main/resources/org/jabref/gui/help/AboutDialog.fxml delete mode 100644 src/main/resources/org/jabref/gui/keyboard/KeyBindingsDialog.fxml diff --git a/build.gradle b/build.gradle index dd891366ede..05e64349175 100644 --- a/build.gradle +++ b/build.gradle @@ -85,6 +85,7 @@ configurations { } dependencies { + // Include all jar-files in the 'lib' folder as dependencies compile fileTree(dir: 'lib', includes: ['*.jar']) compile 'com.jgoodies:jgoodies-common:1.8.1' @@ -123,7 +124,6 @@ dependencies { compile 'com.google.guava:guava:24.1-jre' // JavaFX stuff - compile 'com.airhacks:afterburner.fx:1.7.0' compile 'de.codecentric.centerdevice:javafxsvg:1.3.0' compile 'de.jensd:fontawesomefx-materialdesignfont:1.7.22-4' compile 'de.saxsys:mvvmfx-validation:1.7.0' @@ -132,6 +132,7 @@ dependencies { compile 'org.fxmisc.flowless:flowless:0.6' compile 'org.fxmisc.richtext:richtextfx:0.8.2' compile 'com.sibvisions.external.jvxfx:dndtabpane:0.1' + compile 'javax.inject:javax.inject:1' // Cannot be updated to 9.*.* until Jabref works with Java 9 diff --git a/javafx/scene/control/annotations.xml b/javafx/scene/control/annotations.xml new file mode 100644 index 00000000000..240687d556c --- /dev/null +++ b/javafx/scene/control/annotations.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/lib/afterburner.fx.jar b/lib/afterburner.fx.jar new file mode 100644 index 0000000000000000000000000000000000000000..816b3e27f5d649d6b0c44d69c7a2578d0136a473 GIT binary patch literal 18245 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 { - - @FXML protected T viewModel; - private Stage stage; - - /** - * Gets the associated view model. - * - * Without this method the {@link FXMLLoader} is not able to resolve references in the fxml file of the form - * text="${controller.viewModel.someProperty}" - */ - public T getViewModel() { - return viewModel; - } - - /** - * Returns the stage where this controller is displayed. - * The stage can be used to e.g. close the dialog. - */ - public Stage getStage() { - return stage; - } - - public void setStage(Stage stage) { - this.stage = Objects.requireNonNull(stage); - } -} diff --git a/src/main/java/org/jabref/gui/AbstractDialogView.java b/src/main/java/org/jabref/gui/AbstractDialogView.java deleted file mode 100644 index d7880e3cd11..00000000000 --- a/src/main/java/org/jabref/gui/AbstractDialogView.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.jabref.gui; - -import java.util.function.Function; - -public abstract class AbstractDialogView extends AbstractView { - - public AbstractDialogView() { - super(); - } - - public AbstractDialogView(Function injectionContext) { - super(injectionContext); - } - - public abstract void show(); -} diff --git a/src/main/java/org/jabref/gui/AbstractView.java b/src/main/java/org/jabref/gui/AbstractView.java deleted file mode 100644 index 266ddedb429..00000000000 --- a/src/main/java/org/jabref/gui/AbstractView.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.jabref.gui; - -import java.util.Optional; -import java.util.function.Function; - -import javafx.scene.Parent; -import javafx.stage.Stage; - -import org.jabref.Globals; -import org.jabref.logic.l10n.Localization; - -import com.airhacks.afterburner.views.FXMLView; - -public class AbstractView extends FXMLView { - - public AbstractView() { - this(f -> null); - } - - public AbstractView(Function injectionContext) { - super(injectionContext); - - // Set resource bundle to internal localizations - bundle = Localization.getMessages(); - } - - @Override - public Parent getView() { - Parent view = super.getView(); - - // Add our base css file - Globals.getThemeLoader().installBaseCss(view); - - // Notify controller about the stage, where it is displayed - view.sceneProperty().addListener((observable, oldValue, newValue) -> { - if (newValue != null && newValue.getWindow() instanceof Stage) { - Stage stage = (Stage) newValue.getWindow(); - if (stage != null) { - getController().ifPresent(controller -> controller.setStage(stage)); - } - } - }); - return view; - } - - private Optional getController() { - return Optional.ofNullable(presenterProperty.get()).map( - presenter -> (AbstractController) presenter); - } -} diff --git a/src/main/java/org/jabref/gui/DefaultInjector.java b/src/main/java/org/jabref/gui/DefaultInjector.java index 5c96fe7395b..e94e6fe8697 100644 --- a/src/main/java/org/jabref/gui/DefaultInjector.java +++ b/src/main/java/org/jabref/gui/DefaultInjector.java @@ -59,4 +59,14 @@ public T instantiatePresenter(Class clazz, Function injec return Injector.instantiatePresenter(clazz, injectionContext); } + + @Override + public void injectMembers(Object instance, Function injectionContext) { + LOGGER.debug("Inject into " + instance.getClass().getName()); + + // Use our own method to construct dependencies + Injector.setInstanceSupplier(DefaultInjector::createDependency); + + Injector.injectMembers(instance, injectionContext); + } } diff --git a/src/main/java/org/jabref/gui/actions/CleanupAction.java b/src/main/java/org/jabref/gui/actions/CleanupAction.java index f0f34af7379..d46b77402ef 100644 --- a/src/main/java/org/jabref/gui/actions/CleanupAction.java +++ b/src/main/java/org/jabref/gui/actions/CleanupAction.java @@ -4,16 +4,12 @@ import java.util.Optional; import javax.swing.JOptionPane; -import javax.swing.JScrollPane; - -import javafx.embed.swing.SwingNode; -import javafx.scene.control.ButtonType; -import javafx.scene.control.DialogPane; import org.jabref.Globals; import org.jabref.gui.BasePanel; import org.jabref.gui.DialogService; import org.jabref.gui.JabRefFrame; +import org.jabref.gui.cleanup.CleanupDialog; import org.jabref.gui.cleanup.CleanupPresetPanel; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableFieldChange; @@ -67,27 +63,14 @@ public void run() { if (canceled) { return; } - CleanupPresetPanel presetPanel = new CleanupPresetPanel(panel.getBibDatabaseContext(), - CleanupPreset.loadFromPreferences(preferences)); - - SwingNode node = new SwingNode(); - presetPanel.getScrollPane().setVisible(true); - - JScrollPane scrollPane = presetPanel.getScrollPane(); - node.setContent(scrollPane); - node.setVisible(true); - - DialogPane pane = new DialogPane(); - pane.setContent(node); - pane.setPrefSize(600, 600); - - Optional ok = dialogService.showCustomDialogAndWait(Localization.lang("Cleanup entries"), pane, ButtonType.OK, ButtonType.CANCEL); + CleanupDialog cleanupDialog = new CleanupDialog(panel.getBibDatabaseContext(), CleanupPreset.loadFromPreferences(preferences)); - if (!ok.isPresent() || ((ok.isPresent() && (ok.get() == ButtonType.CANCEL)))) { + Optional chosenPreset = cleanupDialog.showAndWait(); + if (!chosenPreset.isPresent()) { canceled = true; return; } - CleanupPreset cleanupPreset = presetPanel.getCleanupPreset(); + CleanupPreset cleanupPreset = chosenPreset.get(); cleanupPreset.storeInPreferences(preferences); if (cleanupPreset.isRenamePDF() && Globals.prefs.getBoolean(JabRefPreferences.ASK_AUTO_NAMING_PDFS_AGAIN)) { diff --git a/src/main/java/org/jabref/gui/actions/CopyFilesAction.java b/src/main/java/org/jabref/gui/actions/CopyFilesAction.java index 8ba3e2db382..39ea9b34d4c 100644 --- a/src/main/java/org/jabref/gui/actions/CopyFilesAction.java +++ b/src/main/java/org/jabref/gui/actions/CopyFilesAction.java @@ -47,8 +47,8 @@ private void showDialog(List data) { dialogService.showInformationDialogAndWait(Localization.lang("Copy linked files to folder..."), Localization.lang("No linked files found for export.")); return; } - CopyFilesDialogView dlg = new CopyFilesDialogView(databaseContext, new CopyFilesResultListDependency(data)); - dlg.show(); + CopyFilesDialogView dialog = new CopyFilesDialogView(databaseContext, new CopyFilesResultListDependency(data)); + dialog.show(); } @Override diff --git a/src/main/java/org/jabref/gui/actions/ShowPreferencesAction.java b/src/main/java/org/jabref/gui/actions/ShowPreferencesAction.java index c6b551ef0a9..6208911fc6b 100644 --- a/src/main/java/org/jabref/gui/actions/ShowPreferencesAction.java +++ b/src/main/java/org/jabref/gui/actions/ShowPreferencesAction.java @@ -14,17 +14,12 @@ public ShowPreferencesAction(JabRefFrame jabRefFrame) { @Override public void execute() { - // output(Localization.lang("Opening preferences...")); if (prefsDialog == null) { prefsDialog = new PreferencesDialog(jabRefFrame); - //prefsDialog.setLocationRelativeTo(JabRefFrame.this); } else { prefsDialog.setValues(); } - prefsDialog.setVisible(true); - //output(""); - + prefsDialog.show(); } - } diff --git a/src/main/java/org/jabref/gui/cleanup/CleanupDialog.java b/src/main/java/org/jabref/gui/cleanup/CleanupDialog.java new file mode 100644 index 00000000000..4ac358e8434 --- /dev/null +++ b/src/main/java/org/jabref/gui/cleanup/CleanupDialog.java @@ -0,0 +1,34 @@ +package org.jabref.gui.cleanup; + +import javax.swing.JScrollPane; + +import javafx.scene.control.ButtonType; + +import org.jabref.gui.util.BaseDialog; +import org.jabref.gui.util.ControlHelper; +import org.jabref.logic.cleanup.CleanupPreset; +import org.jabref.logic.l10n.Localization; +import org.jabref.model.database.BibDatabaseContext; + +public class CleanupDialog extends BaseDialog { + + public CleanupDialog(BibDatabaseContext databaseContext, CleanupPreset initialPreset) { + setTitle(Localization.lang("Cleanup entries")); + getDialogPane().setPrefSize(600, 600); + getDialogPane().getButtonTypes().setAll(ButtonType.OK, ButtonType.CANCEL); + + CleanupPresetPanel presetPanel = new CleanupPresetPanel(databaseContext, initialPreset); + presetPanel.getScrollPane().setVisible(true); + JScrollPane scrollPane = presetPanel.getScrollPane(); + + setResultConverter(button -> { + if (button == ButtonType.OK) { + return presetPanel.getCleanupPreset(); + } else { + return null; + } + }); + + ControlHelper.setSwingContent(getDialogPane(), scrollPane); + } +} diff --git a/src/main/resources/org/jabref/gui/copyfiles/CopyFilesDialog.fxml b/src/main/java/org/jabref/gui/copyfiles/CopyFilesDialog.fxml similarity index 83% rename from src/main/resources/org/jabref/gui/copyfiles/CopyFilesDialog.fxml rename to src/main/java/org/jabref/gui/copyfiles/CopyFilesDialog.fxml index 88aa1b0a03b..671b569acf3 100644 --- a/src/main/resources/org/jabref/gui/copyfiles/CopyFilesDialog.fxml +++ b/src/main/java/org/jabref/gui/copyfiles/CopyFilesDialog.fxml @@ -6,8 +6,9 @@ - - +

diff --git a/src/main/java/org/jabref/gui/copyfiles/CopyFilesDialogController.java b/src/main/java/org/jabref/gui/copyfiles/CopyFilesDialogController.java deleted file mode 100644 index 6c3b79bfa1d..00000000000 --- a/src/main/java/org/jabref/gui/copyfiles/CopyFilesDialogController.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.jabref.gui.copyfiles; - -import javax.inject.Inject; - -import javafx.event.ActionEvent; -import javafx.fxml.FXML; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TableView; -import javafx.scene.paint.Color; -import javafx.scene.text.Text; - -import org.jabref.gui.AbstractController; -import org.jabref.gui.util.ValueTableCellFactory; - -import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon; -import de.jensd.fx.glyphs.materialdesignicons.utils.MaterialDesignIconFactory; - -public class CopyFilesDialogController extends AbstractController { - - @FXML private TableView tvResult; - @FXML private TableColumn colStatus; - @FXML private TableColumn colMessage; - @FXML private TableColumn colFile; - - @Inject private CopyFilesResultListDependency copyfilesresultlistDependency; //This var must have the same name as the key in the View - - @FXML - private void close(@SuppressWarnings("unused") ActionEvent event) { - getStage().close(); - } - - @FXML - private void initialize() { - viewModel = new CopyFilesDialogViewModel(copyfilesresultlistDependency); - setupTable(); - } - - private void setupTable() { - colFile.setCellValueFactory(cellData -> cellData.getValue().getFile()); - colMessage.setCellValueFactory(cellData -> cellData.getValue().getMessage()); - colStatus.setCellValueFactory(cellData -> cellData.getValue().getIcon()); - - colFile.setCellFactory(new ValueTableCellFactory().withText(item -> item).withTooltip(item -> item)); - colStatus.setCellFactory(new ValueTableCellFactory().withGraphic(item -> { - - Text icon = MaterialDesignIconFactory.get().createIcon(item); - if (item == MaterialDesignIcon.CHECK) { - icon.setFill(Color.GREEN); - } - if (item == MaterialDesignIcon.ALERT) { - icon.setFill(Color.RED); - } - return icon; - })); - - tvResult.setItems(viewModel.copyFilesResultListProperty()); - tvResult.setColumnResizePolicy((param) -> true); - } -} diff --git a/src/main/java/org/jabref/gui/copyfiles/CopyFilesDialogView.java b/src/main/java/org/jabref/gui/copyfiles/CopyFilesDialogView.java index 7c7c24b5a90..cd4b33832ea 100644 --- a/src/main/java/org/jabref/gui/copyfiles/CopyFilesDialogView.java +++ b/src/main/java/org/jabref/gui/copyfiles/CopyFilesDialogView.java @@ -1,36 +1,69 @@ package org.jabref.gui.copyfiles; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; +import javafx.scene.paint.Color; +import javafx.scene.text.Text; -import javafx.scene.control.Alert.AlertType; -import javafx.scene.control.DialogPane; - -import org.jabref.gui.AbstractDialogView; -import org.jabref.gui.FXDialog; +import org.jabref.gui.util.BaseDialog; +import org.jabref.gui.util.ValueTableCellFactory; import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; -public class CopyFilesDialogView extends AbstractDialogView { +import com.airhacks.afterburner.views.ViewLoader; +import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon; +import de.jensd.fx.glyphs.materialdesignicons.utils.MaterialDesignIconFactory; + +public class CopyFilesDialogView extends BaseDialog { + + @FXML private TableView tvResult; + @FXML private TableColumn colStatus; + @FXML private TableColumn colMessage; + @FXML private TableColumn colFile; + private final CopyFilesDialogViewModel viewModel; public CopyFilesDialogView(BibDatabaseContext bibDatabaseContext, CopyFilesResultListDependency results) { - super(createContext(bibDatabaseContext, results)); + this.setTitle(Localization.lang("Result")); + this.setResizable(true); + + ViewLoader.view(this) + .load() + .setAsContent(this.getDialogPane()); + + viewModel = new CopyFilesDialogViewModel(results); } - @Override - public void show() { - FXDialog copyFilesResultDlg = new FXDialog(AlertType.INFORMATION, Localization.lang("Result")); - copyFilesResultDlg.setResizable(true); - copyFilesResultDlg.setDialogPane((DialogPane) this.getView()); - copyFilesResultDlg.show(); + @FXML + private void close(@SuppressWarnings("unused") ActionEvent event) { + close(); } - private static Function createContext(BibDatabaseContext bibDatabaseContext, CopyFilesResultListDependency copyfilesresultlistDependency) { - Map context = new HashMap<>(); - //The "keys" of the HashMap must have the same name as the with @inject annotated field in the controller - context.put("bibdatabasecontext", bibDatabaseContext); - context.put("copyfilesresultlistDependency", copyfilesresultlistDependency); - return context::get; + @FXML + private void initialize() { + setupTable(); + } + + private void setupTable() { + colFile.setCellValueFactory(cellData -> cellData.getValue().getFile()); + colMessage.setCellValueFactory(cellData -> cellData.getValue().getMessage()); + colStatus.setCellValueFactory(cellData -> cellData.getValue().getIcon()); + + colFile.setCellFactory(new ValueTableCellFactory().withText(item -> item).withTooltip(item -> item)); + colStatus.setCellFactory(new ValueTableCellFactory().withGraphic(item -> { + + Text icon = MaterialDesignIconFactory.get().createIcon(item); + if (item == MaterialDesignIcon.CHECK) { + icon.setFill(Color.GREEN); + } + if (item == MaterialDesignIcon.ALERT) { + icon.setFill(Color.RED); + } + return icon; + })); + + tvResult.setItems(viewModel.copyFilesResultListProperty()); + tvResult.setColumnResizePolicy((param) -> true); } } diff --git a/src/main/java/org/jabref/gui/documentviewer/DocumentViewer.fxml b/src/main/java/org/jabref/gui/documentviewer/DocumentViewer.fxml index b111649ddf2..57e1f086228 100644 --- a/src/main/java/org/jabref/gui/documentviewer/DocumentViewer.fxml +++ b/src/main/java/org/jabref/gui/documentviewer/DocumentViewer.fxml @@ -15,7 +15,7 @@ + fx:controller="org.jabref.gui.documentviewer.DocumentViewerView"> diff --git a/src/main/java/org/jabref/gui/documentviewer/DocumentViewerController.java b/src/main/java/org/jabref/gui/documentviewer/DocumentViewerController.java deleted file mode 100644 index 08abde5f290..00000000000 --- a/src/main/java/org/jabref/gui/documentviewer/DocumentViewerController.java +++ /dev/null @@ -1,109 +0,0 @@ -package org.jabref.gui.documentviewer; - -import javax.inject.Inject; - -import javafx.event.ActionEvent; -import javafx.fxml.FXML; -import javafx.scene.control.ComboBox; -import javafx.scene.control.Label; -import javafx.scene.control.ScrollBar; -import javafx.scene.control.TextField; -import javafx.scene.control.ToggleButton; -import javafx.scene.layout.BorderPane; - -import org.jabref.gui.AbstractController; -import org.jabref.gui.StateManager; -import org.jabref.gui.util.OnlyIntegerFormatter; -import org.jabref.gui.util.TaskExecutor; -import org.jabref.gui.util.ViewModelListCellFactory; -import org.jabref.model.entry.LinkedFile; - -public class DocumentViewerController extends AbstractController { - - @FXML private ScrollBar scrollBar; - @FXML private ComboBox fileChoice; - @FXML private BorderPane mainPane; - @FXML private ToggleButton modeLive; - @FXML private TextField currentPage; - @FXML private Label maxPages; - - @Inject private StateManager stateManager; - @Inject private TaskExecutor taskExecutor; - private DocumentViewerControl viewer; - - @FXML - private void initialize() { - viewModel = new DocumentViewerViewModel(stateManager); - - setupViewer(); - setupScrollbar(); - setupFileChoice(); - setupPageControls(); - setupModeButtons(); - } - - private void setupModeButtons() { - viewModel.liveModeProperty().bind(modeLive.selectedProperty()); - } - - private void setupScrollbar() { - scrollBar.valueProperty().bindBidirectional(viewer.scrollYProperty()); - scrollBar.maxProperty().bind(viewer.scrollYMaxProperty()); - } - - private void setupPageControls() { - OnlyIntegerFormatter integerFormatter = new OnlyIntegerFormatter(1); - viewModel.currentPageProperty().bindBidirectional(integerFormatter.valueProperty()); - currentPage.setTextFormatter(integerFormatter); - maxPages.textProperty().bind(viewModel.maxPagesProperty().asString()); - } - - private void setupFileChoice() { - ViewModelListCellFactory cellFactory = new ViewModelListCellFactory() - .withText(LinkedFile::getLink); - fileChoice.setButtonCell(cellFactory.call(null)); - fileChoice.setCellFactory(cellFactory); - fileChoice.getSelectionModel().selectedItemProperty().addListener( - (observable, oldValue, newValue) -> viewModel.switchToFile(newValue)); - // We always want that the first item is selected after a change - // This also automatically selects the first file on the initial load - fileChoice.itemsProperty().addListener( - (observable, oldValue, newValue) -> fileChoice.getSelectionModel().selectFirst()); - fileChoice.itemsProperty().bind(viewModel.filesProperty()); - } - - private void setupViewer() { - viewer = new DocumentViewerControl(taskExecutor); - viewModel.currentDocumentProperty().addListener((observable, oldDocument, newDocument) -> { - if (newDocument != null) { - viewer.show(newDocument); - } - }); - viewModel.currentPageProperty().bindBidirectional(viewer.currentPageProperty()); - mainPane.setCenter(viewer); - } - - public void nextPage(ActionEvent actionEvent) { - viewModel.showNextPage(); - } - - public void previousPage(ActionEvent actionEvent) { - viewModel.showPreviousPage(); - } - - public void fitWidth(ActionEvent actionEvent) { - viewer.setPageWidth(viewer.getWidth()); - } - - public void zoomIn(ActionEvent actionEvent) { - viewer.changePageWidth(100); - } - - public void zoomOut(ActionEvent actionEvent) { - viewer.changePageWidth(-100); - } - - public void fitSinglePage(ActionEvent actionEvent) { - viewer.setPageHeight(viewer.getHeight()); - } -} diff --git a/src/main/java/org/jabref/gui/documentviewer/DocumentViewerView.java b/src/main/java/org/jabref/gui/documentviewer/DocumentViewerView.java index 5ca7efd27d2..60ef762d9bc 100644 --- a/src/main/java/org/jabref/gui/documentviewer/DocumentViewerView.java +++ b/src/main/java/org/jabref/gui/documentviewer/DocumentViewerView.java @@ -1,25 +1,130 @@ package org.jabref.gui.documentviewer; -import javafx.scene.control.Alert.AlertType; +import javax.inject.Inject; + +import javafx.event.ActionEvent; +import javafx.fxml.FXML; import javafx.scene.control.ButtonBar; -import javafx.scene.control.DialogPane; +import javafx.scene.control.ButtonType; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.control.ScrollBar; +import javafx.scene.control.TextField; +import javafx.scene.control.ToggleButton; +import javafx.scene.layout.BorderPane; +import javafx.stage.Modality; -import org.jabref.gui.AbstractDialogView; -import org.jabref.gui.FXDialog; +import org.jabref.gui.StateManager; +import org.jabref.gui.util.BaseDialog; +import org.jabref.gui.util.OnlyIntegerFormatter; +import org.jabref.gui.util.TaskExecutor; +import org.jabref.gui.util.ViewModelListCellFactory; import org.jabref.logic.l10n.Localization; +import org.jabref.model.entry.LinkedFile; + +import com.airhacks.afterburner.views.ViewLoader; + +public class DocumentViewerView extends BaseDialog { + + @FXML private ScrollBar scrollBar; + @FXML private ComboBox fileChoice; + @FXML private BorderPane mainPane; + @FXML private ToggleButton modeLive; + @FXML private TextField currentPage; + @FXML private Label maxPages; -public class DocumentViewerView extends AbstractDialogView { + @Inject private StateManager stateManager; + @Inject private TaskExecutor taskExecutor; + private DocumentViewerControl viewer; + private DocumentViewerViewModel viewModel; + + public DocumentViewerView() { + this.setTitle(Localization.lang("Document viewer")); + this.initModality(Modality.NONE); + this.setResizable(true); + + ViewLoader.view(this) + .load() + .setAsContent(this.getDialogPane()); + + // Remove button bar at bottom, but add close button to keep the dialog closable by clicking the "x" window symbol + getDialogPane().getButtonTypes().add(ButtonType.CLOSE); + getDialogPane().getChildren().removeIf(node -> node instanceof ButtonBar); + } - @Override - public void show() { - FXDialog dialog = new FXDialog(AlertType.INFORMATION, Localization.lang("Document viewer"), false); - DialogPane dialogPane = (DialogPane) this.getView(); + @FXML + private void initialize() { + viewModel = new DocumentViewerViewModel(stateManager); - // Remove button bar at bottom - dialogPane.getChildren().removeIf(node -> node instanceof ButtonBar); + setupViewer(); + setupScrollbar(); + setupFileChoice(); + setupPageControls(); + setupModeButtons(); + } + + private void setupModeButtons() { + viewModel.liveModeProperty().bind(modeLive.selectedProperty()); + } + + private void setupScrollbar() { + scrollBar.valueProperty().bindBidirectional(viewer.scrollYProperty()); + scrollBar.maxProperty().bind(viewer.scrollYMaxProperty()); + } + + private void setupPageControls() { + OnlyIntegerFormatter integerFormatter = new OnlyIntegerFormatter(1); + viewModel.currentPageProperty().bindBidirectional(integerFormatter.valueProperty()); + currentPage.setTextFormatter(integerFormatter); + maxPages.textProperty().bind(viewModel.maxPagesProperty().asString()); + } + + private void setupFileChoice() { + ViewModelListCellFactory cellFactory = new ViewModelListCellFactory() + .withText(LinkedFile::getLink); + fileChoice.setButtonCell(cellFactory.call(null)); + fileChoice.setCellFactory(cellFactory); + fileChoice.getSelectionModel().selectedItemProperty().addListener( + (observable, oldValue, newValue) -> viewModel.switchToFile(newValue)); + // We always want that the first item is selected after a change + // This also automatically selects the first file on the initial load + fileChoice.itemsProperty().addListener( + (observable, oldValue, newValue) -> fileChoice.getSelectionModel().selectFirst()); + fileChoice.itemsProperty().bind(viewModel.filesProperty()); + } + + private void setupViewer() { + viewer = new DocumentViewerControl(taskExecutor); + viewModel.currentDocumentProperty().addListener((observable, oldDocument, newDocument) -> { + if (newDocument != null) { + viewer.show(newDocument); + } + }); + viewModel.currentPageProperty().bindBidirectional(viewer.currentPageProperty()); + mainPane.setCenter(viewer); + } + + public void nextPage(ActionEvent actionEvent) { + viewModel.showNextPage(); + } + + public void previousPage(ActionEvent actionEvent) { + viewModel.showPreviousPage(); + } + + public void fitWidth(ActionEvent actionEvent) { + viewer.setPageWidth(viewer.getWidth()); + } + + public void zoomIn(ActionEvent actionEvent) { + viewer.changePageWidth(100); + } + + public void zoomOut(ActionEvent actionEvent) { + viewer.changePageWidth(-100); + } - dialog.setDialogPane(dialogPane); - dialog.setResizable(true); - dialog.show(); + public void fitSinglePage(ActionEvent actionEvent) { + viewer.setPageHeight(viewer.getHeight()); } } diff --git a/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTab.fxml b/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTab.fxml index a9b8bbfb029..d56bfd1de4b 100644 --- a/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTab.fxml +++ b/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTab.fxml @@ -17,8 +17,9 @@ - - + diff --git a/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTab.java b/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTab.java index 7b9da1a8179..027f8f8f676 100644 --- a/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTab.java @@ -1,5 +1,6 @@ package org.jabref.gui.entryeditor.fileannotationtab; +import javafx.scene.Parent; import javafx.scene.control.Tooltip; import org.jabref.gui.entryeditor.EntryEditorTab; @@ -8,6 +9,8 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; +import com.airhacks.afterburner.views.ViewLoader; + public class FileAnnotationTab extends EntryEditorTab { private final FileAnnotationCache fileAnnotationCache; @@ -26,6 +29,9 @@ public boolean shouldShow(BibEntry entry) { @Override protected void bindToEntry(BibEntry entry) { - setContent(new FileAnnotationTabView(entry, fileAnnotationCache).getView()); + Parent content = ViewLoader.view(new FileAnnotationTabView(entry, fileAnnotationCache)) + .load() + .getView(); + setContent(content); } } diff --git a/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTabController.java b/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTabController.java deleted file mode 100644 index 40f8dc874b7..00000000000 --- a/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTabController.java +++ /dev/null @@ -1,144 +0,0 @@ -package org.jabref.gui.entryeditor.fileannotationtab; - -import java.nio.file.Path; - -import javax.inject.Inject; - -import javafx.beans.binding.Bindings; -import javafx.collections.ListChangeListener; -import javafx.event.ActionEvent; -import javafx.fxml.FXML; -import javafx.geometry.HPos; -import javafx.geometry.Pos; -import javafx.scene.Node; -import javafx.scene.control.ComboBox; -import javafx.scene.control.Label; -import javafx.scene.control.ListView; -import javafx.scene.control.SelectionMode; -import javafx.scene.control.TextArea; -import javafx.scene.layout.ColumnConstraints; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.RowConstraints; -import javafx.scene.text.Font; -import javafx.scene.text.TextAlignment; - -import org.jabref.gui.AbstractController; -import org.jabref.gui.util.ViewModelListCellFactory; -import org.jabref.logic.l10n.Localization; -import org.jabref.logic.pdf.FileAnnotationCache; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.util.FileUpdateMonitor; - -import org.fxmisc.easybind.EasyBind; - -public class FileAnnotationTabController extends AbstractController { - - @FXML - public ComboBox files; - @FXML - public ListView annotationList; - @FXML - public Label author; - @FXML - public Label page; - @FXML - public Label date; - @FXML - public TextArea content; - @FXML - public TextArea marking; - @FXML - public GridPane grid; - - @Inject - private FileAnnotationCache fileAnnotationCache; - @Inject - private BibEntry entry; - @Inject - private FileUpdateMonitor fileMonitor; - - @FXML - public void initialize() { - viewModel = new FileAnnotationTabViewModel(fileAnnotationCache, entry, fileMonitor); - - // Set-up files list - files.getItems().setAll(viewModel.filesProperty().get()); - files.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> viewModel.notifyNewSelectedFile(newValue)); - files.getSelectionModel().selectFirst(); - - // Set-up annotation list - annotationList.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); - annotationList.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> viewModel.notifyNewSelectedAnnotation(newValue)); - ViewModelListCellFactory cellFactory = new ViewModelListCellFactory() - .withTooltip(FileAnnotationViewModel::getMarking) - .withGraphic(annotation -> { - return createFileAnnotationNode(annotation); - }); - annotationList.setCellFactory(cellFactory); - annotationList.setPlaceholder(new Label(Localization.lang("File has no attached annotations"))); - Bindings.bindContent(annotationList.itemsProperty().get(), viewModel.annotationsProperty()); - annotationList.getSelectionModel().selectFirst(); - annotationList.itemsProperty().get().addListener( - (ListChangeListener) c -> annotationList.getSelectionModel().selectFirst()); - - // Set-up details pane - content.textProperty().bind(EasyBind.select(viewModel.currentAnnotationProperty()).selectObject(FileAnnotationViewModel::contentProperty)); - marking.textProperty().bind(EasyBind.select(viewModel.currentAnnotationProperty()).selectObject(FileAnnotationViewModel::markingProperty)); - grid.disableProperty().bind(viewModel.isAnnotationsEmpty()); - } - - private Node createFileAnnotationNode(FileAnnotationViewModel annotation) { - GridPane node = new GridPane(); - - ColumnConstraints firstColumn = new ColumnConstraints(); - ColumnConstraints secondColumn = new ColumnConstraints(); - firstColumn.setPercentWidth(70); - secondColumn.setPercentWidth(30); - firstColumn.setHalignment(HPos.LEFT); - secondColumn.setHalignment(HPos.RIGHT); - node.getColumnConstraints().addAll(firstColumn, secondColumn); - - RowConstraints firstRow = new RowConstraints(); - RowConstraints secondRow = new RowConstraints(); - firstRow.setMinHeight(10); - firstRow.setPrefHeight(15); - secondRow.setMinHeight(10); - secondRow.setPrefHeight(35); - node.getRowConstraints().addAll(firstRow, secondRow); - - Label marking = new Label(annotation.getMarking()); - Label author = new Label(annotation.getAuthor()); - Label date = new Label(annotation.getDate()); - Label page = new Label(Localization.lang("Page") + ": " + annotation.getPage()); - - marking.setFont(new Font("System Bold", 15)); - marking.setPrefWidth(250); - author.setFont(new Font("System", 14)); - - marking.setPrefHeight(10); - author.setPrefHeight(30); - date.setPrefHeight(10); - page.setPrefHeight(30); - - // add alignment for text in the list - marking.setTextAlignment(TextAlignment.LEFT); - marking.setAlignment(Pos.TOP_LEFT); - author.setTextAlignment(TextAlignment.LEFT); - author.setAlignment(Pos.TOP_LEFT); - date.setTextAlignment(TextAlignment.RIGHT); - date.setAlignment(Pos.TOP_RIGHT); - page.setTextAlignment(TextAlignment.RIGHT); - page.setAlignment(Pos.TOP_RIGHT); - - node.add(marking, 0, 0); - node.add(author, 0, 1); - node.add(date, 1, 0); - node.add(page, 1, 1); - - return node; - } - - public void copy(ActionEvent event) { - viewModel.copyCurrentAnnotation(); - } -} diff --git a/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTabView.java b/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTabView.java index 3e216334b61..aa5179bd56f 100644 --- a/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTabView.java +++ b/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTabView.java @@ -1,23 +1,137 @@ package org.jabref.gui.entryeditor.fileannotationtab; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; +import java.nio.file.Path; -import org.jabref.gui.AbstractView; +import javax.inject.Inject; + +import javafx.beans.binding.Bindings; +import javafx.collections.ListChangeListener; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.geometry.HPos; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.control.ListView; +import javafx.scene.control.SelectionMode; +import javafx.scene.control.TextArea; +import javafx.scene.layout.ColumnConstraints; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.RowConstraints; +import javafx.scene.text.Font; +import javafx.scene.text.TextAlignment; + +import org.jabref.gui.util.ViewModelListCellFactory; +import org.jabref.logic.l10n.Localization; import org.jabref.logic.pdf.FileAnnotationCache; import org.jabref.model.entry.BibEntry; +import org.jabref.model.util.FileUpdateMonitor; + +import org.fxmisc.easybind.EasyBind; + +public class FileAnnotationTabView { + + @FXML public ComboBox files; + @FXML public ListView annotationList; + @FXML public Label author; + @FXML public Label page; + @FXML public Label date; + @FXML public TextArea content; + @FXML public TextArea marking; + @FXML public GridPane grid; + private final BibEntry entry; + private final FileAnnotationCache fileAnnotationCache; + private FileAnnotationTabViewModel viewModel; -public class FileAnnotationTabView extends AbstractView { + @Inject + private FileUpdateMonitor fileMonitor; public FileAnnotationTabView(BibEntry entry, FileAnnotationCache fileAnnotationCache) { - super(createContext(entry, fileAnnotationCache)); + this.entry = entry; + this.fileAnnotationCache = fileAnnotationCache; + } + + @FXML + public void initialize() { + viewModel = new FileAnnotationTabViewModel(fileAnnotationCache, entry, fileMonitor); + + // Set-up files list + files.getItems().setAll(viewModel.filesProperty().get()); + files.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> viewModel.notifyNewSelectedFile(newValue)); + files.getSelectionModel().selectFirst(); + + // Set-up annotation list + annotationList.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); + annotationList.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> viewModel.notifyNewSelectedAnnotation(newValue)); + ViewModelListCellFactory cellFactory = new ViewModelListCellFactory() + .withTooltip(FileAnnotationViewModel::getMarking) + .withGraphic(this::createFileAnnotationNode); + annotationList.setCellFactory(cellFactory); + annotationList.setPlaceholder(new Label(Localization.lang("File has no attached annotations"))); + Bindings.bindContent(annotationList.itemsProperty().get(), viewModel.annotationsProperty()); + annotationList.getSelectionModel().selectFirst(); + annotationList.itemsProperty().get().addListener( + (ListChangeListener) c -> annotationList.getSelectionModel().selectFirst()); + + // Set-up details pane + content.textProperty().bind(EasyBind.select(viewModel.currentAnnotationProperty()).selectObject(FileAnnotationViewModel::contentProperty)); + marking.textProperty().bind(EasyBind.select(viewModel.currentAnnotationProperty()).selectObject(FileAnnotationViewModel::markingProperty)); + grid.disableProperty().bind(viewModel.isAnnotationsEmpty()); + } + + private Node createFileAnnotationNode(FileAnnotationViewModel annotation) { + GridPane node = new GridPane(); + + ColumnConstraints firstColumn = new ColumnConstraints(); + ColumnConstraints secondColumn = new ColumnConstraints(); + firstColumn.setPercentWidth(70); + secondColumn.setPercentWidth(30); + firstColumn.setHalignment(HPos.LEFT); + secondColumn.setHalignment(HPos.RIGHT); + node.getColumnConstraints().addAll(firstColumn, secondColumn); + + RowConstraints firstRow = new RowConstraints(); + RowConstraints secondRow = new RowConstraints(); + firstRow.setMinHeight(10); + firstRow.setPrefHeight(15); + secondRow.setMinHeight(10); + secondRow.setPrefHeight(35); + node.getRowConstraints().addAll(firstRow, secondRow); + + Label marking = new Label(annotation.getMarking()); + Label author = new Label(annotation.getAuthor()); + Label date = new Label(annotation.getDate()); + Label page = new Label(Localization.lang("Page") + ": " + annotation.getPage()); + + marking.setFont(new Font("System Bold", 15)); + marking.setPrefWidth(250); + author.setFont(new Font("System", 14)); + + marking.setPrefHeight(10); + author.setPrefHeight(30); + date.setPrefHeight(10); + page.setPrefHeight(30); + + // add alignment for text in the list + marking.setTextAlignment(TextAlignment.LEFT); + marking.setAlignment(Pos.TOP_LEFT); + author.setTextAlignment(TextAlignment.LEFT); + author.setAlignment(Pos.TOP_LEFT); + date.setTextAlignment(TextAlignment.RIGHT); + date.setAlignment(Pos.TOP_RIGHT); + page.setTextAlignment(TextAlignment.RIGHT); + page.setAlignment(Pos.TOP_RIGHT); + + node.add(marking, 0, 0); + node.add(author, 0, 1); + node.add(date, 1, 0); + node.add(page, 1, 1); + + return node; } - private static Function createContext(BibEntry entry, FileAnnotationCache fileAnnotationCache) { - Map context = new HashMap<>(); - context.put("entry", entry); - context.put("fileAnnotationCache", fileAnnotationCache); - return context::get; + public void copy(ActionEvent event) { + viewModel.copyCurrentAnnotation(); } } diff --git a/src/main/java/org/jabref/gui/errorconsole/ErrorConsole.css b/src/main/java/org/jabref/gui/errorconsole/ErrorConsole.css index 29153a512a4..f356121a647 100644 --- a/src/main/java/org/jabref/gui/errorconsole/ErrorConsole.css +++ b/src/main/java/org/jabref/gui/errorconsole/ErrorConsole.css @@ -33,8 +33,3 @@ .custom-buttons { -fx-padding: 5.0px; } - -.dialog-pane *.button-bar { - -fx-max-height: 0.0; - -fx-pref-height: 0.0; -} diff --git a/src/main/java/org/jabref/gui/errorconsole/ErrorConsole.fxml b/src/main/java/org/jabref/gui/errorconsole/ErrorConsole.fxml index a82f9e00b4d..ab10833b4fd 100644 --- a/src/main/java/org/jabref/gui/errorconsole/ErrorConsole.fxml +++ b/src/main/java/org/jabref/gui/errorconsole/ErrorConsole.fxml @@ -1,35 +1,25 @@ - - - + + xmlns="http://javafx.com/javafx/8.0.60" fx:controller="org.jabref.gui.errorconsole.ErrorConsoleView"> - - - - - - - -