diff --git a/CHANGELOG.md b/CHANGELOG.md index 1067763a760..09ee0dd7875 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,7 +43,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We removed the redundant new lines of markings and wrapped the summary in the File annotation tab. [#3823](https://github.com/JabRef/jabref/issues/3823) - We add auto url formatting when user paste link to URL field in entry editor. [koppor#254](https://github.com/koppor/jabref/issues/254) - We added a minimal height for the entry editor so that it can no longer be hidden by accident. [#4279](https://github.com/JabRef/jabref/issues/4279) -- We added a new keyboard shortcut so that the entry editor could be closed by Ctrl + E. [#4222] (https://github.com/JabRef/jabref/issues/4222) +- We added a new keyboard shortcut so that the entry editor could be closed by Ctrl + E. [#4222] (https://github.com/JabRef/jabref/issues/4222) - We added an option in the preference dialog box, that allows user to pick the dark or light theme option. [#4130] (https://github.com/JabRef/jabref/issues/4130) - We updated updated the Related Articles tab to accept JSON from the new version of the Mr. DLib service - We added an option in the preference dialog box that allows user to choose behavior after dragging and dropping files in Entry Editor. [#4356](https://github.com/JabRef/jabref/issues/4356) @@ -68,6 +68,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We fixed an issue where the custom file column were sorted incorrectly. https://github.com/JabRef/jabref/issues/3119 - We fixed an issues where the entry losses focus when a field is edited and at the same time used for sorting. https://github.com/JabRef/jabref/issues/3373 - We fixed an issue where the menu on Mac OS was not displayed in the usual Mac-specific way. https://github.com/JabRef/jabref/issues/3146 +- We improved the integrity check for page numbers. [#4113](https://github.com/JabRef/jabref/issues/4113) and [feature request in the forum](http://discourse.jabref.org/t/pages-field-allow-use-of-en-dash/1199) - We fixed an issue where the order of fields in customized entry types was not saved correctly. [#4033](http://github.com/JabRef/jabref/issues/4033) - We fixed an issue where the groups tree of the last database was still shown even after the database was already closed. - We fixed an issue where the "Open file dialog" may disappear behind other windows. https://github.com/JabRef/jabref/issues/3410 diff --git a/build.gradle b/build.gradle index f364470d047..6913fab8cc0 100644 --- a/build.gradle +++ b/build.gradle @@ -110,7 +110,7 @@ dependencies { compile "org.libreoffice:ridl:5.4.2" compile "org.libreoffice:unoil:5.4.2" - compile 'io.github.java-diff-utils:java-diff-utils:2.2.0' + compile 'io.github.java-diff-utils:java-diff-utils:4.0' compile 'info.debatty:java-string-similarity:1.1.0' antlr3 'org.antlr:antlr:3.5.2' @@ -125,7 +125,7 @@ dependencies { compile 'net.java.dev.glazedlists:glazedlists_java15:1.9.1' - compile 'com.google.guava:guava:27.0-jre' + compile 'com.google.guava:guava:27.0.1-jre' // JavaFX stuff compile 'de.jensd:fontawesomefx-materialdesignfont:1.7.22-4' @@ -168,14 +168,14 @@ dependencies { testCompile 'org.junit-pioneer:junit-pioneer:0.3.0' testRuntime 'org.apache.logging.log4j:log4j-core:2.11.1' testRuntime 'org.apache.logging.log4j:log4j-jul:2.11.1' - testCompile 'org.mockito:mockito-core:2.23.0' + testCompile 'org.mockito:mockito-core:2.23.4' testCompile 'com.github.tomakehurst:wiremock:2.19.0' testCompile 'org.assertj:assertj-swing-junit:3.8.0' testCompile 'org.reflections:reflections:0.9.11' testCompile 'org.xmlunit:xmlunit-core:2.6.2' testCompile 'org.xmlunit:xmlunit-matchers:2.6.2' - testCompile 'com.tngtech.archunit:archunit-junit5-api:0.9.2' - testRuntime 'com.tngtech.archunit:archunit-junit5-engine:0.9.2' + testRuntime 'com.tngtech.archunit:archunit-junit5-engine:0.9.3' + testCompile 'com.tngtech.archunit:archunit-junit5-api:0.9.3' testCompile "org.testfx:testfx-core:4.0.+" testCompile "org.testfx:testfx-junit5:4.0.+" diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index 349b7acc6d7..ec78513a06b 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -291,7 +291,6 @@ .check-box > .box, .menu-button, .choice-box, -.color-picker.split-button > .color-picker-label, .combo-box-base, .combo-box-base:editable > .arrow-button { -fx-background-color: transparent; @@ -956,3 +955,23 @@ We want to have a look that matches our icons in the tool-bar */ .progress-bar > .track { -fx-background-color: -jr-accent; } + +.jfx-color-picker:armed, +.jfx-color-picker:hover, +.jfx-color-picker:focused, +.jfx-color-picker { + -fx-background-color: transparent, transparent, transparent, transparent; + -fx-background-radius: 0px; + -fx-background-insets: 0px; + -fx-effect: null; +} + +.color-palette { + -fx-background-color: -fx-background; + -fx-background-radius: 0px; + -fx-background-insets: 0px; +} + +.color-palette-region .button { + -fx-border-width: 0px; +} diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index f57f69d6134..6291f893d02 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -272,7 +272,7 @@ public void output(String s) { } private void setupActions() { - SaveDatabaseAction saveAction = new SaveDatabaseAction(this); + SaveDatabaseAction saveAction = new SaveDatabaseAction(this, Globals.prefs); CleanupAction cleanUpAction = new CleanupAction(this, Globals.prefs); actions.put(Actions.UNDO, undoAction); diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index a7f2586d7e0..e6ef5d3128f 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -1335,7 +1335,7 @@ private boolean confirmClose(BasePanel panel) { if (response.isPresent() && response.get().equals(saveChanges)) { // The user wants to save. try { - SaveDatabaseAction saveAction = new SaveDatabaseAction(panel); + SaveDatabaseAction saveAction = new SaveDatabaseAction(panel, Globals.prefs); if (!saveAction.save()) { // The action was either canceled or unsuccessful. output(Localization.lang("Unable to save library")); diff --git a/src/main/java/org/jabref/gui/dialogs/AutosaveUIManager.java b/src/main/java/org/jabref/gui/dialogs/AutosaveUIManager.java index 1fb08fbb184..2ce31738e54 100644 --- a/src/main/java/org/jabref/gui/dialogs/AutosaveUIManager.java +++ b/src/main/java/org/jabref/gui/dialogs/AutosaveUIManager.java @@ -1,5 +1,6 @@ package org.jabref.gui.dialogs; +import org.jabref.Globals; import org.jabref.gui.BasePanel; import org.jabref.gui.exporter.SaveDatabaseAction; import org.jabref.model.database.event.AutosaveEvent; @@ -25,7 +26,7 @@ public AutosaveUIManager(BasePanel panel) { @Subscribe public void listen(@SuppressWarnings("unused") AutosaveEvent event) { try { - new SaveDatabaseAction(panel).save(); + new SaveDatabaseAction(panel, Globals.prefs).save(); } catch (Throwable e) { LOGGER.error("Problem occured while saving.", e); } diff --git a/src/main/java/org/jabref/gui/exporter/SaveDatabaseAction.java b/src/main/java/org/jabref/gui/exporter/SaveDatabaseAction.java index ecd1d7e6a2f..3a4fc68ffd2 100644 --- a/src/main/java/org/jabref/gui/exporter/SaveDatabaseAction.java +++ b/src/main/java/org/jabref/gui/exporter/SaveDatabaseAction.java @@ -14,7 +14,6 @@ import javafx.scene.layout.VBox; import javafx.scene.text.Text; -import org.jabref.Globals; import org.jabref.gui.BasePanel; import org.jabref.gui.DialogService; import org.jabref.gui.JabRefFrame; @@ -53,16 +52,18 @@ public class SaveDatabaseAction { private final BasePanel panel; private final JabRefFrame frame; private final DialogService dialogService; + private final JabRefPreferences prefs; - public SaveDatabaseAction(BasePanel panel) { + public SaveDatabaseAction(BasePanel panel, JabRefPreferences prefs) { this.panel = panel; this.frame = panel.frame(); this.dialogService = frame.getDialogService(); + this.prefs = prefs; } private boolean saveDatabase(Path file, boolean selectedOnly, Charset encoding, SavePreferences.DatabaseSaveType saveType) throws SaveException { try { - SavePreferences preferences = Globals.prefs.loadForSaveFromPreferences() + SavePreferences preferences = prefs.loadForSaveFromPreferences() .withEncoding(encoding) .withSaveType(saveType); @@ -124,7 +125,7 @@ private boolean doSave() { panel.getBibDatabaseContext() .getMetaData() .getEncoding() - .orElse(Globals.prefs.getDefaultEncoding()), + .orElse(prefs.getDefaultEncoding()), SavePreferences.DatabaseSaveType.ALL); if (success) { @@ -182,10 +183,10 @@ private Optional getSavePath() { FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder() .addExtensionFilter(StandardFileType.BIBTEX_DB) .withDefaultExtension(StandardFileType.BIBTEX_DB) - .withInitialDirectory(Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY)) + .withInitialDirectory(prefs.get(JabRefPreferences.WORKING_DIRECTORY)) .build(); Optional selectedPath = dialogService.showFileSaveDialog(fileDialogConfiguration); - selectedPath.ifPresent(path -> Globals.prefs.setWorkingDir(path.getParent())); + selectedPath.ifPresent(path -> prefs.setWorkingDir(path.getParent())); return selectedPath; } @@ -228,7 +229,7 @@ public void saveAs(Path file) { private boolean readyForAutosave(BibDatabaseContext context) { return ((context.getLocation() == DatabaseLocation.SHARED) || ((context.getLocation() == DatabaseLocation.LOCAL) - && Globals.prefs.getBoolean(JabRefPreferences.LOCAL_AUTO_SAVE))) + && prefs.getBoolean(JabRefPreferences.LOCAL_AUTO_SAVE))) && context.getDatabasePath().isPresent(); } @@ -240,7 +241,7 @@ private boolean readyForBackup(BibDatabaseContext context) { public void saveSelectedAsPlain() { getSavePath().ifPresent(path -> { try { - saveDatabase(path, true, Globals.prefs.getDefaultEncoding(), SavePreferences.DatabaseSaveType.PLAIN_BIBTEX); + saveDatabase(path, true, prefs.getDefaultEncoding(), SavePreferences.DatabaseSaveType.PLAIN_BIBTEX); frame.getFileHistory().newFile(path); frame.output(Localization.lang("Saved selected to '%0'.", path.toString())); } catch (SaveException ex) { diff --git a/src/main/java/org/jabref/gui/groups/GroupDialog.java b/src/main/java/org/jabref/gui/groups/GroupDialog.java index 85f320b0040..3d334919446 100644 --- a/src/main/java/org/jabref/gui/groups/GroupDialog.java +++ b/src/main/java/org/jabref/gui/groups/GroupDialog.java @@ -8,7 +8,6 @@ import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; -import javafx.geometry.HPos; import javafx.geometry.Insets; import javafx.scene.Node; import javafx.scene.control.ButtonType; @@ -20,11 +19,9 @@ import javafx.scene.control.TextField; import javafx.scene.control.Toggle; import javafx.scene.control.ToggleGroup; -import javafx.scene.layout.ColumnConstraints; -import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; import javafx.scene.layout.StackPane; -import javafx.scene.paint.Color; +import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.scene.text.FontPosture; import javafx.scene.text.Text; @@ -56,6 +53,8 @@ import org.jabref.model.strings.StringUtil; import org.jabref.preferences.JabRefPreferences; +import com.jfoenix.controls.JFXColorPicker; + /** * Dialog for creating or modifying groups. Operates directly on the Vector * containing group information. @@ -67,15 +66,11 @@ class GroupDialog extends BaseDialog { private static final int INDEX_SEARCH_GROUP = 2; private static final int INDEX_AUTO_GROUP = 3; private static final int INDEX_TEX_GROUP = 4; - private static final int TEXTFIELD_LENGTH = 40; - private static final int HGAP = 7; - private static final int VGAP = 5; - private static final Insets PADDING = new Insets(5, 5, 5, 5); // for all types private final TextField nameField = new TextField(); private final TextField descriptionField = new TextField(); - private final TextField colorField = new TextField(); + private final JFXColorPicker colorField = new JFXColorPicker(); private final TextField iconField = new TextField(); private final RadioButton explicitRadioButton = new RadioButton(Localization.lang("Statically group entries by manual assignment")); private final RadioButton keywordsRadioButton = new RadioButton(Localization.lang("Dynamically group entries by searching a field for a keyword")); @@ -123,24 +118,9 @@ class GroupDialog extends BaseDialog { public GroupDialog(JabRefFrame jabrefFrame, AbstractGroup editedGroup) { this.setTitle(Localization.lang("Edit group")); - nameField.setPrefColumnCount(GroupDialog.TEXTFIELD_LENGTH); - descriptionField.setPrefColumnCount(GroupDialog.TEXTFIELD_LENGTH); - colorField.setPrefColumnCount(GroupDialog.TEXTFIELD_LENGTH); - iconField.setPrefColumnCount(GroupDialog.TEXTFIELD_LENGTH); explicitRadioButton.setSelected(true); - keywordGroupSearchTerm.setPrefColumnCount(GroupDialog.TEXTFIELD_LENGTH); - keywordGroupSearchField.setPrefColumnCount(GroupDialog.TEXTFIELD_LENGTH); - searchGroupSearchExpression.setPrefColumnCount(GroupDialog.TEXTFIELD_LENGTH); - autoGroupKeywordsField.setPrefColumnCount(10); - autoGroupKeywordsDeliminator.setPrefColumnCount(10); - autoGroupKeywordsDeliminator.setPrefColumnCount(10); - autoGroupPersonsField.setPrefColumnCount(10); - texGroupFilePath.setPrefColumnCount(TEXTFIELD_LENGTH); + descriptionWebView.setPrefWidth(585); - optionsPanel.setPadding(PADDING); - optionsPanel.setStyle("-fx-content-display:top;" - + "-fx-border-insets:0 0 0 0;" - + "-fx-border-color:#D3D3D3"); // set default values (overwritten if editedGroup != null) keywordGroupSearchField.setText(jabrefFrame.prefs().get(JabRefPreferences.GROUPS_DEFAULT_FIELD)); @@ -152,181 +132,91 @@ public GroupDialog(JabRefFrame jabrefFrame, AbstractGroup editedGroup) { searchRadioButton.setToggleGroup(groupType); autoRadioButton.setToggleGroup(groupType); texRadioButton.setToggleGroup(groupType); - ToggleGroup groupHierarchy = new ToggleGroup(); - independentButton.setToggleGroup(groupHierarchy); - intersectionButton.setToggleGroup(groupHierarchy); - unionButton.setToggleGroup(groupHierarchy); - // build individual layout cards for each group - GridPane explicitPanel = new GridPane(); - GridPane keywordPanel = new GridPane(); - GridPane searchPanel = new GridPane(); - GridPane autoPanel = new GridPane(); - GridPane texPanel = new GridPane(); - // ... for explicit group - optionsPanel.getChildren().add(explicitPanel); + // Build individual layout cards for each group + VBox explicitPanel = createOptionsExplicitGroup(); explicitPanel.setVisible(true); - // ... for keyword group - optionsPanel.getChildren().add(keywordPanel); - keywordPanel.setVisible(false); - keywordPanel.setHgap(HGAP); - keywordPanel.setVgap(VGAP); - keywordPanel.setPadding(PADDING); - ColumnConstraints keywordPanelLCol = new ColumnConstraints(); - keywordPanelLCol.setHalignment(HPos.RIGHT); - keywordPanel.getColumnConstraints().add(keywordPanelLCol); - ColumnConstraints keywordPanelRCol = new ColumnConstraints(); - keywordPanelRCol.setHalignment(HPos.LEFT); - keywordPanel.getColumnConstraints().add(keywordPanelRCol); - keywordPanel.add(new Label(Localization.lang("Field")), 0, 0); - keywordPanel.add(keywordGroupSearchField, 1, 0); - keywordPanel.add(new Label(Localization.lang("Keyword")), 0, 1); - keywordPanel.add(keywordGroupSearchTerm, 1, 1); - GridPane.setHalignment(keywordGroupCaseSensitive, HPos.LEFT); - keywordPanel.add(keywordGroupCaseSensitive, 0, 2, 2, 1); - GridPane.setHalignment(keywordGroupRegExp, HPos.LEFT); - keywordPanel.add(keywordGroupRegExp, 0, 3, 2, 1); - // ... for search group - optionsPanel.getChildren().add(searchPanel); - searchPanel.setVisible(false); - searchPanel.setHgap(HGAP); - searchPanel.setVgap(VGAP); - searchPanel.setPadding(PADDING); - searchPanel.add(new Label(Localization.lang("Search expression")), 0, 0); - searchPanel.add(searchGroupSearchExpression, 1, 0, 2, 1); - searchPanel.add(searchGroupCaseSensitive, 0, 1, 2, 1); - searchPanel.add(searchGroupRegExp, 0, 2, 2, 1); - // ... for auto group - optionsPanel.getChildren().add(autoPanel); - autoPanel.setVisible(false); - autoPanel.setHgap(HGAP); - autoPanel.setVgap(VGAP); - autoPanel.setPadding(PADDING); - ToggleGroup tg = new ToggleGroup(); - autoGroupKeywordsOption.setToggleGroup(tg); - autoGroupPersonsOption.setToggleGroup(tg); - Label placeholderLabel = new Label(); - placeholderLabel.setPrefWidth(30); - autoPanel.add(autoGroupKeywordsOption, 0, 0, 3, 1); - autoPanel.add(placeholderLabel, 0, 1); - autoPanel.add(new Label(Localization.lang("Field to group by") + ":"), 1, 1); - autoPanel.add(autoGroupKeywordsField, 2, 1); - autoPanel.add(new Label(Localization.lang("Use the following delimiter character(s):")), 1, 2); - autoPanel.add(autoGroupKeywordsDeliminator, 2, 2); - autoPanel.add(autoGroupKeywordsHierarchicalDeliminator, 2, 3); - autoPanel.add(autoGroupPersonsOption, 0, 4, 3, 1); - autoPanel.add(new Label(Localization.lang("Field to group by") + ":"), 1, 5); - autoPanel.add(autoGroupPersonsField, 2, 5); - autoGroupKeywordsOption.setSelected(true); - autoGroupKeywordsField.setText(Globals.prefs.get(JabRefPreferences.GROUPS_DEFAULT_FIELD)); - autoGroupKeywordsDeliminator.setText(Globals.prefs.get(JabRefPreferences.KEYWORD_SEPARATOR)); - autoGroupKeywordsHierarchicalDeliminator.setText(Keyword.DEFAULT_HIERARCHICAL_DELIMITER.toString()); - autoGroupPersonsField.setText(FieldName.AUTHOR); - // ... for tex group - optionsPanel.getChildren().add(texPanel); - texPanel.setVisible(false); - texPanel.setHgap(HGAP); - texPanel.setVgap(VGAP); - texPanel.setPadding(PADDING); - texPanel.add(new Label(Localization.lang("Aux file")), 0, 0); - texPanel.add(texGroupFilePath, 1, 0); + VBox keywordPanel = createOptionsKeywordGroup(); + VBox searchPanel = createOptionsSearchGroup(); + VBox autoPanel = createOptionsAutoGroup(); + VBox texPanel = createOptionsTexGroup(); + optionsPanel.getChildren().addAll(explicitPanel, keywordPanel, searchPanel, autoPanel, texPanel); + optionsPanel.setPadding(new Insets(0, 0, 0, 10)); // ... for buttons panel getDialogPane().getButtonTypes().setAll(ButtonType.OK, ButtonType.CANCEL); - // General panel - GridPane generalPanel = new GridPane(); - GridPane textFieldPanel = new GridPane(); - GridPane selectPanel = new GridPane(); - generalPanel.add(textFieldPanel, 0, 0); - generalPanel.add(selectPanel, 0, 1); - generalPanel.setVgap(VGAP); - generalPanel.setPadding(PADDING); - generalPanel.setStyle("-fx-content-display:top;" - + "-fx-border-insets:0 0 0 0;" - + "-fx-border-color:#D3D3D3"); - - ColumnConstraints columnLabel = new ColumnConstraints(); - columnLabel.setHalignment(HPos.RIGHT); - textFieldPanel.getColumnConstraints().add(columnLabel); - ColumnConstraints columnTextField = new ColumnConstraints(); - columnTextField.setHalignment(HPos.LEFT); - textFieldPanel.getColumnConstraints().add(columnTextField); - textFieldPanel.setVgap(VGAP); - textFieldPanel.setHgap(HGAP); - textFieldPanel.add(new Label(Localization.lang("Name")), 0, 0); - textFieldPanel.add(nameField, 1, 0); - textFieldPanel.add(new Label(Localization.lang("Description")), 0, 1); - textFieldPanel.add(descriptionField, 1, 1); - textFieldPanel.add(new Label(Localization.lang("Color")), 0, 2); - textFieldPanel.add(colorField, 1, 2); - textFieldPanel.add(new Label(Localization.lang("Icon")), 0, 3); - textFieldPanel.add(iconField, 1, 3); - - selectPanel.setVgap(VGAP); - selectPanel.add(explicitRadioButton, 0, 0); - selectPanel.add(keywordsRadioButton, 0, 1); - selectPanel.add(searchRadioButton, 0, 2); - selectPanel.add(autoRadioButton, 0, 3); - selectPanel.add(texRadioButton, 0, 4); - - // Context panel - GridPane contextPanel = new GridPane(); - contextPanel.setVgap(VGAP); - contextPanel.setHgap(HGAP); - contextPanel.setPadding(PADDING); - contextPanel.setStyle("-fx-content-display:top;" - + "-fx-border-insets:0 0 0 0;" - + "-fx-border-color:#D3D3D3"); - contextPanel.add(independentButton, 0, 0); - contextPanel.add(intersectionButton, 0, 1); - contextPanel.add(unionButton, 0, 2); + // General information + VBox contextPanel = new VBox(10); + contextPanel.setPadding(new Insets(0, 0, 0, 10)); + contextPanel.getChildren().setAll( + independentButton, + intersectionButton, + unionButton + ); + ToggleGroup groupHierarchy = new ToggleGroup(); + independentButton.setToggleGroup(groupHierarchy); + intersectionButton.setToggleGroup(groupHierarchy); + unionButton.setToggleGroup(groupHierarchy); + + colorField.setMinHeight(20); + VBox generalPanel = new VBox(10); + generalPanel.getChildren().setAll( + new VBox( + new Label(Localization.lang("Name")), + nameField + ), + new VBox( + new Label(Localization.lang("Description")), + descriptionField + ), + new HBox(30, + new VBox( + new Label(Localization.lang("Icon")), + iconField + ), + new VBox( + new Label(Localization.lang("Color")), + colorField + ) + ), + new VBox(5, + new Label(Localization.lang("Hierarchical context")), + contextPanel + ) + ); + + VBox selectPanel = new VBox(10, + explicitRadioButton, + keywordsRadioButton, + searchRadioButton, + autoRadioButton, + texRadioButton + ); + selectPanel.setPadding(new Insets(0, 0, 0, 10)); // Description panel - ScrollPane sp = new ScrollPane(descriptionWebView); - sp.setPadding(PADDING); - sp.setHbarPolicy(ScrollBarPolicy.AS_NEEDED); - sp.setVbarPolicy(ScrollBarPolicy.AS_NEEDED); - sp.setStyle("-fx-content-display:top;" - + "-fx-border-insets:0 0 0 0;" - + "-fx-border-color:#D3D3D3"); - - // create border - HBox title1 = new HBox(); - HBox title2 = new HBox(); - HBox title3 = new HBox(); - HBox title4 = new HBox(); - Label title1Label = new Label(Localization.lang("General")); - Label title2Label = new Label(Localization.lang("Hierarchical context")); - Label title3Label = new Label(Localization.lang("Options")); - Label title4Label = new Label(Localization.lang("Description")); - title1Label.setTextFill(Color.web("#778899")); - title2Label.setTextFill(Color.web("#778899")); - title3Label.setTextFill(Color.web("#778899")); - title4Label.setTextFill(Color.web("#778899")); - title1.setPadding(new Insets(10, 0, 0, 0)); - title2.setPadding(new Insets(10, 0, 0, 0)); - title3.setPadding(new Insets(10, 0, 0, 0)); - title4.setPadding(new Insets(10, 0, 0, 0)); - title1.getChildren().add(title1Label); - title2.getChildren().add(title2Label); - title3.getChildren().add(title3Label); - title4.getChildren().add(title4Label); + ScrollPane descriptionPane = new ScrollPane(descriptionWebView); + descriptionPane.setHbarPolicy(ScrollBarPolicy.AS_NEEDED); + descriptionPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED); // create layout - GridPane mainPanel = new GridPane(); + VBox mainPanel = new VBox(15); getDialogPane().setContent(mainPanel); - mainPanel.setPrefHeight(810); - mainPanel.setPrefWidth(630); - mainPanel.setPadding(new Insets(5, 15, 5, 5)); - mainPanel.add(title1, 0, 0); - mainPanel.add(generalPanel, 0, 1); - mainPanel.add(title2, 0, 2); - mainPanel.add(contextPanel, 0, 3); - mainPanel.add(title3, 0, 4); - mainPanel.add(optionsPanel, 0, 5); - mainPanel.add(title4, 0, 6); - mainPanel.add(sp, 0, 7); + mainPanel.setPadding(new Insets(5, 15, 5, 15)); + mainPanel.getChildren().setAll( + generalPanel, + new VBox(5, + new Label(Localization.lang("Type")), + selectPanel + ), + new VBox( + new Label(Localization.lang("Options")), + optionsPanel + ), + new Label(Localization.lang("Description")), + descriptionPane + ); updateComponents(); @@ -416,11 +306,8 @@ groupName, getContext(), resultingGroup = new TexGroup(groupName, getContext(), Paths.get(texGroupFilePath.getText().trim()), new DefaultAuxParser(new BibDatabase()), Globals.getFileUpdateMonitor()); } - try { - resultingGroup.setColor(Color.valueOf(colorField.getText())); - } catch (IllegalArgumentException ex) { - // Ignore invalid color (we should probably notify the user instead...) - } + + resultingGroup.setColor(colorField.getValue()); resultingGroup.setDescription(descriptionField.getText()); resultingGroup.setIconName(iconField.getText()); return resultingGroup; @@ -438,7 +325,6 @@ groupName, getContext(), Boolean newBoolean) -> updateComponents(); nameField.textProperty().addListener(caretListener); - colorField.textProperty().addListener(caretListener); descriptionField.textProperty().addListener(caretListener); iconField.textProperty().addListener(caretListener); keywordGroupSearchField.textProperty().addListener(caretListener); @@ -456,7 +342,7 @@ groupName, getContext(), setContext(GroupHierarchyType.INDEPENDENT); } else { nameField.setText(editedGroup.getName()); - colorField.setText(editedGroup.getColor().map(Color::toString).orElse("")); + editedGroup.getColor().ifPresent(colorField::setValue); descriptionField.setText(editedGroup.getDescription().orElse("")); iconField.setText(editedGroup.getIconName().orElse("")); @@ -527,11 +413,11 @@ private static String formatRegExException(String regExp, Exception e) { sb.append(StringUtil.quoteForHTML(sa[i])); } String s = Localization.lang( - "The regular expression %0 is invalid:", - StringUtil.quoteForHTML(regExp)) - + "

" - + sb - + ""; + "The regular expression %0 is invalid:", + StringUtil.quoteForHTML(regExp)) + + "

" + + sb + + ""; if (!(e instanceof PatternSyntaxException)) { return s; } @@ -543,6 +429,89 @@ private static String formatRegExException(String regExp, Exception e) { return s; } + private VBox createOptionsTexGroup() { + VBox texPanel = new VBox(); + texPanel.setVisible(false); + texPanel.getChildren().add(new Label(Localization.lang("Aux file"))); + texPanel.getChildren().add(texGroupFilePath); + return texPanel; + } + + private VBox createOptionsAutoGroup() { + VBox autoPanel = new VBox(10); + autoPanel.setVisible(false); + ToggleGroup tg = new ToggleGroup(); + autoGroupKeywordsOption.setToggleGroup(tg); + autoGroupPersonsOption.setToggleGroup(tg); + VBox fieldToGroupByKeywords = new VBox( + new Label(Localization.lang("Field to group by") + ":"), + autoGroupKeywordsField + ); + fieldToGroupByKeywords.setPadding(new Insets(0, 0, 0, 20)); + VBox delimiterCharacters = new VBox( + new Label(Localization.lang("Use the following delimiter character(s):")), + new HBox(10, + autoGroupKeywordsDeliminator, + autoGroupKeywordsHierarchicalDeliminator + ) + ); + delimiterCharacters.setPadding(new Insets(0, 0, 0, 20)); + VBox fieldToGroupByPersons = new VBox( + new Label(Localization.lang("Field to group by") + ":"), + autoGroupPersonsField + ); + fieldToGroupByPersons.setPadding(new Insets(0, 0, 0, 20)); + autoPanel.getChildren().setAll( + autoGroupKeywordsOption, + fieldToGroupByKeywords, + delimiterCharacters, + autoGroupPersonsOption, + fieldToGroupByPersons + ); + autoGroupKeywordsOption.setSelected(true); + autoGroupKeywordsField.setText(Globals.prefs.get(JabRefPreferences.GROUPS_DEFAULT_FIELD)); + autoGroupKeywordsDeliminator.setText(Globals.prefs.get(JabRefPreferences.KEYWORD_SEPARATOR)); + autoGroupKeywordsHierarchicalDeliminator.setText(Keyword.DEFAULT_HIERARCHICAL_DELIMITER.toString()); + autoGroupPersonsField.setText(FieldName.AUTHOR); + return autoPanel; + } + + private VBox createOptionsSearchGroup() { + VBox searchPanel = new VBox(10); + searchPanel.setVisible(false); + searchPanel.getChildren().setAll( + new VBox( + new Label(Localization.lang("Search expression")), + searchGroupSearchExpression + ), + searchGroupCaseSensitive, + searchGroupRegExp + ); + return searchPanel; + } + + private VBox createOptionsExplicitGroup() { + return new VBox(); + } + + private VBox createOptionsKeywordGroup() { + VBox keywordPanel = new VBox(10); + keywordPanel.setVisible(false); + keywordPanel.getChildren().setAll( + new VBox( + new Label(Localization.lang("Field")), + keywordGroupSearchField + ), + new VBox( + new Label(Localization.lang("Keyword")), + keywordGroupSearchTerm + ), + keywordGroupCaseSensitive, + keywordGroupRegExp + ); + return keywordPanel; + } + private void updateComponents() { // all groups need a name boolean okEnabled = !nameField.getText().trim().isEmpty(); diff --git a/src/main/java/org/jabref/gui/mergeentries/DiffHighlighting.java b/src/main/java/org/jabref/gui/mergeentries/DiffHighlighting.java index f4812fbc4ad..acffbc7acc0 100644 --- a/src/main/java/org/jabref/gui/mergeentries/DiffHighlighting.java +++ b/src/main/java/org/jabref/gui/mergeentries/DiffHighlighting.java @@ -7,31 +7,42 @@ import javafx.scene.text.Text; -import difflib.Delta; -import difflib.DiffUtils; +import com.github.difflib.DiffUtils; +import com.github.difflib.algorithm.DiffException; +import com.github.difflib.patch.AbstractDelta; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class DiffHighlighting { + private static final Logger LOGGER = LoggerFactory.getLogger(DiffHighlighting.class); + private DiffHighlighting() { } public static List generateDiffHighlighting(String baseString, String modifiedString, String separator) { List stringList = Arrays.asList(baseString.split(separator)); List result = stringList.stream().map(DiffHighlighting::forUnchanged).collect(Collectors.toList()); - List> deltaList = DiffUtils.diff(stringList, Arrays.asList(modifiedString.split(separator))).getDeltas(); - Collections.reverse(deltaList); - for (Delta delta : deltaList) { - int startPos = delta.getOriginal().getPosition(); - List lines = delta.getOriginal().getLines(); - int offset = 0; - switch (delta.getType()) { + List> deltaList; + try { + deltaList = DiffUtils.diff(stringList, Arrays.asList(modifiedString.split(separator))).getDeltas(); + } catch (DiffException e) { + LOGGER.error("Error while generating diff of " + baseString + " and " + modifiedString); + return Collections.emptyList(); + } + Collections.reverse(deltaList); + for (AbstractDelta delta : deltaList) { + int startPos = delta.getSource().getPosition(); + List lines = delta.getSource().getLines(); + int offset = 0; + switch (delta.getType()) { case CHANGE: for (String line : lines) { result.set(startPos + offset, forRemoved(line + separator)); offset++; } result.set(startPos + offset - 1, forRemoved(stringList.get((startPos + offset) - 1) + separator)); - result.add(startPos + offset, forAdded(String.join(separator, delta.getRevised().getLines()))); + result.add(startPos + offset, forAdded(String.join(separator, delta.getTarget().getLines()))); break; case DELETE: for (String line : lines) { @@ -40,12 +51,12 @@ public static List generateDiffHighlighting(String baseString, String modi } break; case INSERT: - result.add(delta.getOriginal().getPosition(), forAdded(String.join(separator, delta.getRevised().getLines()))); + result.add(delta.getSource().getPosition(), forAdded(String.join(separator, delta.getTarget().getLines()))); break; default: break; - } } + } return result; } @@ -76,13 +87,19 @@ public static Text forRemoved(String text) { public static List generateSymmetricHighlighting(String baseString, String modifiedString, String separator) { List stringList = Arrays.asList(baseString.split(separator)); List result = stringList.stream().map(text -> DiffHighlighting.forUnchanged(text + separator)).collect(Collectors.toList()); - List> deltaList = DiffUtils.diff(stringList, Arrays.asList(modifiedString.split(separator))).getDeltas(); - Collections.reverse(deltaList); - for (Delta delta : deltaList) { - int startPos = delta.getOriginal().getPosition(); - List lines = delta.getOriginal().getLines(); - int offset = 0; - switch (delta.getType()) { + List> deltaList; + try { + deltaList = DiffUtils.diff(stringList, Arrays.asList(modifiedString.split(separator))).getDeltas(); + } catch (DiffException e) { + LOGGER.error("Error while generating diff of " + baseString + " and " + modifiedString); + return Collections.emptyList(); + } + Collections.reverse(deltaList); + for (AbstractDelta delta : deltaList) { + int startPos = delta.getSource().getPosition(); + List lines = delta.getSource().getLines(); + int offset = 0; + switch (delta.getType()) { case CHANGE: for (String line : lines) { result.set(startPos + offset, forChanged(line + separator)); @@ -99,10 +116,9 @@ public static List generateSymmetricHighlighting(String baseString, String break; default: break; - } } + } return result; } - } diff --git a/src/main/java/org/jabref/gui/shared/SharedDatabaseLoginDialogViewModel.java b/src/main/java/org/jabref/gui/shared/SharedDatabaseLoginDialogViewModel.java index dddbce8101a..2f1f0803b8d 100644 --- a/src/main/java/org/jabref/gui/shared/SharedDatabaseLoginDialogViewModel.java +++ b/src/main/java/org/jabref/gui/shared/SharedDatabaseLoginDialogViewModel.java @@ -163,7 +163,7 @@ private void openSharedDatabase(DBMSConnectionProperties connectionProperties) { if (!folder.getValue().isEmpty()) { try { - new SaveDatabaseAction(panel).saveAs(Paths.get(folder.getValue())); + new SaveDatabaseAction(panel, Globals.prefs).saveAs(Paths.get(folder.getValue())); } catch (Throwable e) { LOGGER.error("Error while saving the database", e); } diff --git a/src/main/java/org/jabref/logic/exporter/ExporterFactory.java b/src/main/java/org/jabref/logic/exporter/ExporterFactory.java index 75c71e77d4d..be7b62252f3 100644 --- a/src/main/java/org/jabref/logic/exporter/ExporterFactory.java +++ b/src/main/java/org/jabref/logic/exporter/ExporterFactory.java @@ -38,7 +38,8 @@ public static ExporterFactory create(Map customFormats // Initialize build-in exporters exporters.add(new TemplateExporter("HTML", "html", "html", null, StandardFileType.HTML, layoutPreferences, savePreferences)); exporters.add(new TemplateExporter(Localization.lang("Simple HTML"), "simplehtml", "simplehtml", null, StandardFileType.HTML, layoutPreferences, savePreferences)); - exporters.add(new TemplateExporter("DocBook 4.4", "docbook", "docbook", null, StandardFileType.XML, layoutPreferences, savePreferences)); + exporters.add(new TemplateExporter("DocBook 5.1", "docbook5", "docbook5", null, StandardFileType.XML, layoutPreferences, savePreferences)); + exporters.add(new TemplateExporter("DocBook 4", "docbook4", "docbook4", null, StandardFileType.XML, layoutPreferences, savePreferences)); exporters.add(new TemplateExporter("DIN 1505", "din1505", "din1505winword", "din1505", StandardFileType.RTF, layoutPreferences, savePreferences)); exporters.add(new TemplateExporter("BibO RDF", "bibordf", "bibordf", null, StandardFileType.RDF, layoutPreferences, savePreferences)); exporters.add(new TemplateExporter(Localization.lang("HTML table"), "tablerefs", "tablerefs", "tablerefs", StandardFileType.HTML, layoutPreferences, savePreferences)); diff --git a/src/main/java/org/jabref/logic/integrity/PagesChecker.java b/src/main/java/org/jabref/logic/integrity/PagesChecker.java index 0040afd2f2a..187394f404a 100644 --- a/src/main/java/org/jabref/logic/integrity/PagesChecker.java +++ b/src/main/java/org/jabref/logic/integrity/PagesChecker.java @@ -10,27 +10,29 @@ public class PagesChecker implements ValueChecker { - private static final String PAGES_EXP_BIBTEX = "" + "\\A" // begin String - + "\\d+" // number - + "(?:" // non-capture group - + "\\+|\\-{2}\\d+" // + or --number (range) - + ")?" // optional group - + "(?:" // non-capture group - + "," // comma - + "\\d+(?:\\+|\\-{2}\\d+)?" // repeat former pattern - + ")*" // repeat group 0,* - + "\\z"; // end String + private static final String PAGES_EXP_BIBTEX = "" + + "\\A" // begin String + + "(" + + "[A-Za-z]?\\d*" // optional prefix and number + + "(" + + "\\+|-{2}" // separator + + "[A-Za-z]?\\d*" // optional prefix and number + + ")?" + + ",?" // page range separation + + ")*" + + "\\z"; // end String - private static final String PAGES_EXP_BIBLATEX = "" + "\\A" // begin String - + "\\d+" // number - + "(?:" // non-capture group - + "\\+|\\-{1,2}\\d+" // + or --number (range) - + ")?" // optional group - + "(?:" // non-capture group - + "," // comma - + "\\d+(?:\\+|\\-{1,2}\\d+)?" // repeat former pattern - + ")*" // repeat group 0,* - + "\\z"; // end String + private static final String PAGES_EXP_BIBLATEX = "" + + "\\A" // begin String + + "(" + + "[A-Za-z]?\\d*" // optional prefix and number + + "(" + + "\\+|-{1,2}|\u2013" // separator + + "[A-Za-z]?\\d*" // optional prefix and number + + ")?" + + ",?" // page range separation + + ")*" + + "\\z"; // end String private final Predicate isValidPageNumber; diff --git a/src/main/java/org/jabref/logic/layout/LayoutEntry.java b/src/main/java/org/jabref/logic/layout/LayoutEntry.java index 21ef1b49abb..18927ef8cf5 100644 --- a/src/main/java/org/jabref/logic/layout/LayoutEntry.java +++ b/src/main/java/org/jabref/logic/layout/LayoutEntry.java @@ -34,8 +34,10 @@ import org.jabref.logic.layout.format.Authors; import org.jabref.logic.layout.format.CompositeFormat; import org.jabref.logic.layout.format.CreateBibORDFAuthors; -import org.jabref.logic.layout.format.CreateDocBookAuthors; -import org.jabref.logic.layout.format.CreateDocBookEditors; +import org.jabref.logic.layout.format.CreateDocBook4Authors; +import org.jabref.logic.layout.format.CreateDocBook4Editors; +import org.jabref.logic.layout.format.CreateDocBook5Authors; +import org.jabref.logic.layout.format.CreateDocBook5Editors; import org.jabref.logic.layout.format.CurrentDate; import org.jabref.logic.layout.format.DOICheck; import org.jabref.logic.layout.format.DOIStrip; @@ -444,10 +446,14 @@ private LayoutFormatter getLayoutFormatterByName(String name) throws Exception { return new CompositeFormat(); case "CreateBibORDFAuthors": return new CreateBibORDFAuthors(); - case "CreateDocBookAuthors": - return new CreateDocBookAuthors(); - case "CreateDocBookEditors": - return new CreateDocBookEditors(); + case "CreateDocBook4Authors": + return new CreateDocBook4Authors(); + case "CreateDocBook4Editors": + return new CreateDocBook4Editors(); + case "CreateDocBook5Authors": + return new CreateDocBook5Authors(); + case "CreateDocBook5Editors": + return new CreateDocBook5Editors(); case "CurrentDate": return new CurrentDate(); case "DateFormatter": diff --git a/src/main/java/org/jabref/logic/layout/format/CreateDocBook4Authors.java b/src/main/java/org/jabref/logic/layout/format/CreateDocBook4Authors.java new file mode 100644 index 00000000000..3e04ae04eae --- /dev/null +++ b/src/main/java/org/jabref/logic/layout/format/CreateDocBook4Authors.java @@ -0,0 +1,22 @@ +package org.jabref.logic.layout.format; + +import org.jabref.logic.layout.LayoutFormatter; +import org.jabref.model.entry.AuthorList; +import org.jabref.model.entry.FieldName; + +/** + * Create DocBook authors formatter. + */ +public class CreateDocBook4Authors implements LayoutFormatter { + + @Override + public String format(String fieldText) { + StringBuilder sb = new StringBuilder(100); + AuthorList al = AuthorList.parse(fieldText); + DocBookAuthorFormatter formatter = new DocBookAuthorFormatter(); + formatter.addBody(sb, al, FieldName.AUTHOR, DocBookVersion.DOCBOOK_4); + return sb.toString(); + + } + +} diff --git a/src/main/java/org/jabref/logic/layout/format/CreateDocBookEditors.java b/src/main/java/org/jabref/logic/layout/format/CreateDocBook4Editors.java similarity index 57% rename from src/main/java/org/jabref/logic/layout/format/CreateDocBookEditors.java rename to src/main/java/org/jabref/logic/layout/format/CreateDocBook4Editors.java index 5f199c7bad5..0a8950742b9 100644 --- a/src/main/java/org/jabref/logic/layout/format/CreateDocBookEditors.java +++ b/src/main/java/org/jabref/logic/layout/format/CreateDocBook4Editors.java @@ -1,19 +1,21 @@ package org.jabref.logic.layout.format; +import org.jabref.logic.layout.LayoutFormatter; import org.jabref.model.entry.AuthorList; import org.jabref.model.entry.FieldName; /** - * Create DocBook editors formatter. + * Create DocBook4 editors formatter. */ -public class CreateDocBookEditors extends CreateDocBookAuthors { +public class CreateDocBook4Editors implements LayoutFormatter { @Override public String format(String fieldText) { // L.Xue StringBuilder sb = new StringBuilder(100); AuthorList al = AuthorList.parse(fieldText); - addBody(sb, al, FieldName.EDITOR); + DocBookAuthorFormatter formatter = new DocBookAuthorFormatter(); + formatter.addBody(sb, al, FieldName.EDITOR, DocBookVersion.DOCBOOK_4); return sb.toString(); } diff --git a/src/main/java/org/jabref/logic/layout/format/CreateDocBook5Authors.java b/src/main/java/org/jabref/logic/layout/format/CreateDocBook5Authors.java new file mode 100644 index 00000000000..53cc52c14d7 --- /dev/null +++ b/src/main/java/org/jabref/logic/layout/format/CreateDocBook5Authors.java @@ -0,0 +1,24 @@ +package org.jabref.logic.layout.format; + +import org.jabref.logic.layout.LayoutFormatter; +import org.jabref.model.entry.AuthorList; +import org.jabref.model.entry.FieldName; + +/** + * Create DocBook5 authors formatter + */ +public class CreateDocBook5Authors implements LayoutFormatter { + + @Override + public String format(String fieldText) { + + StringBuilder sb = new StringBuilder(100); + AuthorList al = AuthorList.parse(fieldText); + + DocBookAuthorFormatter authorFormatter = new DocBookAuthorFormatter(); + authorFormatter.addBody(sb, al, FieldName.AUTHOR, DocBookVersion.DOCBOOK_5); + return sb.toString(); + + } + +} diff --git a/src/main/java/org/jabref/logic/layout/format/CreateDocBook5Editors.java b/src/main/java/org/jabref/logic/layout/format/CreateDocBook5Editors.java new file mode 100644 index 00000000000..55892a37521 --- /dev/null +++ b/src/main/java/org/jabref/logic/layout/format/CreateDocBook5Editors.java @@ -0,0 +1,23 @@ +package org.jabref.logic.layout.format; + +import org.jabref.logic.layout.LayoutFormatter; +import org.jabref.model.entry.AuthorList; +import org.jabref.model.entry.FieldName; + +/** + * Create DocBook editors formatter. + */ +public class CreateDocBook5Editors implements LayoutFormatter { + + @Override + public String format(String fieldText) { + // L.Xue + StringBuilder sb = new StringBuilder(100); + AuthorList al = AuthorList.parse(fieldText); + DocBookAuthorFormatter formatter = new DocBookAuthorFormatter(); + formatter.addBody(sb, al, FieldName.EDITOR, DocBookVersion.DOCBOOK_5); + return sb.toString(); + + } + +} diff --git a/src/main/java/org/jabref/logic/layout/format/CreateDocBookAuthors.java b/src/main/java/org/jabref/logic/layout/format/DocBookAuthorFormatter.java similarity index 54% rename from src/main/java/org/jabref/logic/layout/format/CreateDocBookAuthors.java rename to src/main/java/org/jabref/logic/layout/format/DocBookAuthorFormatter.java index d2ffb6d250c..8bcf75058d3 100644 --- a/src/main/java/org/jabref/logic/layout/format/CreateDocBookAuthors.java +++ b/src/main/java/org/jabref/logic/layout/format/DocBookAuthorFormatter.java @@ -1,42 +1,42 @@ package org.jabref.logic.layout.format; -import org.jabref.logic.layout.LayoutFormatter; import org.jabref.model.entry.Author; import org.jabref.model.entry.AuthorList; -import org.jabref.model.entry.FieldName; /** - * Create DocBook authors formatter. + * DocBook author formatter for both version 4 and 5 + * */ -public class CreateDocBookAuthors implements LayoutFormatter { +public class DocBookAuthorFormatter { private static final XMLChars XML_CHARS = new XMLChars(); - @Override - public String format(String fieldText) { - - StringBuilder sb = new StringBuilder(100); - - AuthorList al = AuthorList.parse(fieldText); - - addBody(sb, al, FieldName.AUTHOR); - return sb.toString(); - - } - - public void addBody(StringBuilder sb, AuthorList al, String tagName) { + /** + * + * @param sb {@link StringBuilder} + * @param al {@link AuthorList} + * @param tagName Editor or author field/tag + * @param version @link {@link DocBookVersion} + */ + public void addBody(StringBuilder sb, AuthorList al, String tagName, DocBookVersion version) { for (int i = 0; i < al.getNumberOfAuthors(); i++) { sb.append('<').append(tagName).append('>'); + if (version == DocBookVersion.DOCBOOK_5) { + sb.append(""); + } Author a = al.getAuthor(i); a.getFirst().filter(first -> !first.isEmpty()).ifPresent(first -> sb.append("") - .append(CreateDocBookAuthors.XML_CHARS.format(first)).append("")); + .append(XML_CHARS.format(first)).append("")); a.getVon().filter(von -> !von.isEmpty()).ifPresent(von -> sb.append("") - .append(CreateDocBookAuthors.XML_CHARS.format(von)).append("")); + .append(XML_CHARS.format(von)).append("")); a.getLast().filter(last -> !last.isEmpty()).ifPresent(last -> { - sb.append("").append(CreateDocBookAuthors.XML_CHARS.format(last)); + sb.append("").append(XML_CHARS.format(last)); a.getJr().filter(jr -> !jr.isEmpty()) - .ifPresent(jr -> sb.append(' ').append(CreateDocBookAuthors.XML_CHARS.format(jr))); + .ifPresent(jr -> sb.append(' ').append(XML_CHARS.format(jr))); sb.append(""); + if (version == DocBookVersion.DOCBOOK_5) { + sb.append(""); + } }); if (i < (al.getNumberOfAuthors() - 1)) { @@ -46,5 +46,4 @@ public void addBody(StringBuilder sb, AuthorList al, String tagName) { } } } - -} +} \ No newline at end of file diff --git a/src/main/java/org/jabref/logic/layout/format/DocBookVersion.java b/src/main/java/org/jabref/logic/layout/format/DocBookVersion.java new file mode 100644 index 00000000000..9b435717f07 --- /dev/null +++ b/src/main/java/org/jabref/logic/layout/format/DocBookVersion.java @@ -0,0 +1,6 @@ +package org.jabref.logic.layout.format; + +public enum DocBookVersion { + DOCBOOK_4, + DOCBOOK_5 +} diff --git a/src/main/java/org/jabref/model/groups/AbstractGroup.java b/src/main/java/org/jabref/model/groups/AbstractGroup.java index aafbe366f11..e61d3b30e52 100644 --- a/src/main/java/org/jabref/model/groups/AbstractGroup.java +++ b/src/main/java/org/jabref/model/groups/AbstractGroup.java @@ -4,6 +4,8 @@ import java.util.Objects; import java.util.Optional; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; import javafx.scene.paint.Color; import org.jabref.model.entry.BibEntry; @@ -18,7 +20,7 @@ public abstract class AbstractGroup implements SearchMatcher { /** * The group's name. */ - protected final String name; + protected final StringProperty name = new SimpleStringProperty(); /** * The hierarchical context of the group. */ @@ -29,14 +31,14 @@ public abstract class AbstractGroup implements SearchMatcher { protected Optional iconName = Optional.empty(); protected AbstractGroup(String name, GroupHierarchyType context) { - this.name = name; + this.name.setValue(name); this.context = Objects.requireNonNull(context); } @Override public String toString() { return "AbstractGroup{" + - "name='" + name + '\'' + + "name='" + name.getValue() + '\'' + ", context=" + context + ", color=" + color + ", isExpanded=" + isExpanded + @@ -54,13 +56,13 @@ public boolean equals(Object other) { return false; } AbstractGroup that = (AbstractGroup) other; - return Objects.equals(this.name, that.name) && Objects.equals(this.description, that.description) + return Objects.equals(this.name.getValue(), that.name.getValue()) && Objects.equals(this.description, that.description) && Objects.equals(this.context, that.context); } @Override public int hashCode() { - return Objects.hash(name, description, context); + return Objects.hash(name.getValue(), description, context); } public Optional getColor() { @@ -122,6 +124,10 @@ public GroupHierarchyType getHierarchicalContext() { * Returns this group's name, e.g. for display in a list/tree. */ public final String getName() { + return name.getValue(); + } + + public StringProperty nameProperty() { return name; } diff --git a/src/main/java/org/jabref/model/groups/AutomaticKeywordGroup.java b/src/main/java/org/jabref/model/groups/AutomaticKeywordGroup.java index f4952a4f751..3549d35acc9 100644 --- a/src/main/java/org/jabref/model/groups/AutomaticKeywordGroup.java +++ b/src/main/java/org/jabref/model/groups/AutomaticKeywordGroup.java @@ -37,7 +37,7 @@ public String getField() { @Override public AbstractGroup deepCopy() { - return new AutomaticKeywordGroup(this.name, this.context, field, this.keywordDelimiter, keywordHierarchicalDelimiter); + return new AutomaticKeywordGroup(this.name.getValue(), this.context, field, this.keywordDelimiter, keywordHierarchicalDelimiter); } @Override diff --git a/src/main/java/org/jabref/model/groups/AutomaticPersonsGroup.java b/src/main/java/org/jabref/model/groups/AutomaticPersonsGroup.java index 58f11af3b4c..04cd3a2b1e6 100644 --- a/src/main/java/org/jabref/model/groups/AutomaticPersonsGroup.java +++ b/src/main/java/org/jabref/model/groups/AutomaticPersonsGroup.java @@ -38,7 +38,7 @@ public int hashCode() { @Override public AbstractGroup deepCopy() { - return new AutomaticPersonsGroup(this.name, this.context, this.field); + return new AutomaticPersonsGroup(this.name.getValue(), this.context, this.field); } @Override diff --git a/src/main/java/org/jabref/model/groups/ExplicitGroup.java b/src/main/java/org/jabref/model/groups/ExplicitGroup.java index ae58004df5d..423da74b3e5 100644 --- a/src/main/java/org/jabref/model/groups/ExplicitGroup.java +++ b/src/main/java/org/jabref/model/groups/ExplicitGroup.java @@ -64,7 +64,7 @@ public List getLegacyEntryKeys() { @Override public int hashCode() { - return Objects.hash(name, context, legacyEntryKeys, iconName, color, description, isExpanded); + return Objects.hash(name.getValue(), context, legacyEntryKeys, iconName, color, description, isExpanded); } @Override diff --git a/src/main/java/org/jabref/model/groups/TexGroup.java b/src/main/java/org/jabref/model/groups/TexGroup.java index a9e7f82e006..92a47028eae 100644 --- a/src/main/java/org/jabref/model/groups/TexGroup.java +++ b/src/main/java/org/jabref/model/groups/TexGroup.java @@ -49,7 +49,7 @@ public boolean isDynamic() { @Override public AbstractGroup deepCopy() { try { - return new TexGroup(name, context, filePath, auxParser, fileMonitor); + return new TexGroup(name.getValue(), context, filePath, auxParser, fileMonitor); } catch (IOException ex) { // This should never happen because we were able to monitor the file just fine until now LOGGER.error("Problem creating copy of group", ex); diff --git a/src/main/java/org/jabref/styletester/StyleTester.fxml b/src/main/java/org/jabref/styletester/StyleTester.fxml index 6eaf7bae249..1f9d65669cf 100644 --- a/src/main/java/org/jabref/styletester/StyleTester.fxml +++ b/src/main/java/org/jabref/styletester/StyleTester.fxml @@ -35,7 +35,7 @@ - + + diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 68bddf2d2bc..d2c7308105f 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2232,3 +2232,4 @@ Default\ drag\ &\ drop\ action=Default drag & drop action Copy\ file\ to\ default\ file\ folder=Copy file to default file folder Link\ file\ (without\ copying)=Link file (without copying) Copy,\ rename\ and\ link\ file=Copy, rename and link file +Type=Type diff --git a/src/main/resources/resource/layout/docbook.begin.layout b/src/main/resources/resource/layout/docbook4.begin.layout similarity index 100% rename from src/main/resources/resource/layout/docbook.begin.layout rename to src/main/resources/resource/layout/docbook4.begin.layout diff --git a/src/main/resources/resource/layout/docbook.end.layout b/src/main/resources/resource/layout/docbook4.end.layout similarity index 100% rename from src/main/resources/resource/layout/docbook.end.layout rename to src/main/resources/resource/layout/docbook4.end.layout diff --git a/src/main/resources/resource/layout/docbook.layout b/src/main/resources/resource/layout/docbook4.layout similarity index 86% rename from src/main/resources/resource/layout/docbook.layout rename to src/main/resources/resource/layout/docbook4.layout index 07ea7765597..c74993e66ce 100644 --- a/src/main/resources/resource/layout/docbook.layout +++ b/src/main/resources/resource/layout/docbook4.layout @@ -1,7 +1,7 @@ -\begin{author} \format[CreateDocBookAuthors]{\author} \end{author} -\begin{editor} \format[CreateDocBookEditors]{\editor} \end{editor} +\begin{author} \format[CreateDocBook4Authors]{\author} \end{author} +\begin{editor} \format[CreateDocBook4Editors]{\editor} \end{editor} \format[XMLChars,RemoveLatexCommands]{\title} \begin{journal} \format[XMLChars]{\journal}\end{journal} diff --git a/src/main/resources/resource/layout/docbook.mastersthesis.layout b/src/main/resources/resource/layout/docbook4.mastersthesis.layout similarity index 86% rename from src/main/resources/resource/layout/docbook.mastersthesis.layout rename to src/main/resources/resource/layout/docbook4.mastersthesis.layout index 8523421ac8c..b5baaa15a64 100644 --- a/src/main/resources/resource/layout/docbook.mastersthesis.layout +++ b/src/main/resources/resource/layout/docbook4.mastersthesis.layout @@ -1,6 +1,6 @@ -\begin{author} \format[CreateDocBookAuthors]{\author} \end{author} +\begin{author} \format[CreateDocBook4Authors]{\author} \end{author} \format[XMLChars,RemoveLatexCommands]{\title} \begin{school} diff --git a/src/main/resources/resource/layout/docbook5.article.layout b/src/main/resources/resource/layout/docbook5.article.layout new file mode 100644 index 00000000000..b79d36f7e71 --- /dev/null +++ b/src/main/resources/resource/layout/docbook5.article.layout @@ -0,0 +1,36 @@ + + + +\begin{author} \format[CreateDocBook5Authors]{\author} \end{author} + +\begin{editor} \format[CreateDocBook5Editors]{\editor} \end{editor} + + + \begin{title} \format[XMLChars,RemoveLatexCommands]{\title} \end{title} + + + \begin{journal} + \n + \begin{volume} \volume \end{volume} + \begin{pages} \format[FormatPagesForXML]{\pages} \end{pages} + \begin{year} \year \end{year} + \end{journal} + + + \begin{url} + \format[XMLChars]{\url} + \end{url} + \begin{doi} + \format[XMLChars]{\doi} + \end{doi} + \begin{isbn} + \format[XMLChars]{\isbn} + \end{isbn} + + + \begin{abstract} + + \format[XMLChars,RemoveLatexCommands]{\abstract} + + \end{abstract} + diff --git a/src/main/resources/resource/layout/docbook5.begin.layout b/src/main/resources/resource/layout/docbook5.begin.layout new file mode 100644 index 00000000000..0ab61fa7f2c --- /dev/null +++ b/src/main/resources/resource/layout/docbook5.begin.layout @@ -0,0 +1,7 @@ + + + + diff --git a/src/main/resources/resource/layout/docbook5.book.layout b/src/main/resources/resource/layout/docbook5.book.layout new file mode 100644 index 00000000000..de92664abfa --- /dev/null +++ b/src/main/resources/resource/layout/docbook5.book.layout @@ -0,0 +1,40 @@ + + + +\begin{author} \format[CreateDocBook5Authors]{\author} \end{author} + +\begin{editor} \format[CreateDocBook5Editors]{\editor} \end{editor} + + + \begin{title} \format[XMLChars,RemoveLatexCommands]{\title} \end{title} + + + \n + \begin{booktitle}\format[XMLChars,RemoveLatexCommands]{\booktitle}\end{booktitle} + \begin{edition}\format[XMLChars,RemoveLatexCommands]{\edition}\end{edition} + \begin{year}\year\end{year} + \begin{pages}\format[FormatPagesForXML]{\pages} \end{pages} + \begin{publisher}\end{publisher} + \publisher +

\address
+ \begin{publisher}\end{publisher} + + + + + \begin{url} + \format[XMLChars]{\url} + \end{url} + \begin{doi} + \format[XMLChars]{\doi} + \end{doi} + \begin{isbn} + \format[XMLChars]{\isbn} + \end{isbn} + + \begin{abstract} + + \format[XMLChars,RemoveLatexCommands]{\abstract} + + \end{abstract} + \ No newline at end of file diff --git a/src/main/resources/resource/layout/docbook5.booklet.layout b/src/main/resources/resource/layout/docbook5.booklet.layout new file mode 100644 index 00000000000..d3e0eadc65d --- /dev/null +++ b/src/main/resources/resource/layout/docbook5.booklet.layout @@ -0,0 +1,26 @@ + + + +\begin{author}\format[CreateDocBook5Authors]{\author}\end{author} + +\begin{editor}\format[CreateDocBook5Editors]{\editor}\end{editor} + + + \begin{title}\format[XMLChars,RemoveLatexCommands]{\title} \end{title} + + \n + \begin{booktitle}\format[XMLChars,RemoveLatexCommands]{\booktitle}\end{booktitle} + \begin{year}\year\end{year} + \begin{howpublished}\howpublished\end{howpublished} + \begin{publisher}\end{publisher} + \begin{publisher}\format[XMLChars]{\publisher} \end{publisher} + \begin{location}\begin{address}
\location
\end{address}\end{location} + \begin{publisher}
\end{publisher} +
+ + \begin{url}\format[XMLChars]{\url}\end{url} + \begin{doi}\format[XMLChars]{\doi}\end{doi} + \begin{isbn}\format[XMLChars]{\isbn}\end{isbn} + + \begin{abstract}\format[XMLChars,RemoveLatexCommands]{\abstract}\end{abstract} +
diff --git a/src/main/resources/resource/layout/docbook5.collection.layout b/src/main/resources/resource/layout/docbook5.collection.layout new file mode 100644 index 00000000000..f3846b1a40b --- /dev/null +++ b/src/main/resources/resource/layout/docbook5.collection.layout @@ -0,0 +1,30 @@ + + + +\begin{editor}\format[CreateDocBook5Editors]{\editor}\end{editor} + + + \begin{title}\format[XMLChars,RemoveLatexCommands]{\title} \end{title} + + \n + \begin{booktitle}\format[XMLChars,RemoveLatexCommands]{\booktitle}\end{booktitle} + \begin{edition}\format[XMLChars,RemoveLatexCommands]{\edition}\end{edition} + \begin{year}\year\end{year} + \begin{volume}\volume \end{volume} + \begin{chapter}\chapter \end{chapter} + \begin{pages}\format[FormatPagesForXML]{\pages} \end{pages} + \begin{publisher}\end{publisher} + \begin{publisher}\format[XMLChars]{\publisher} \end{publisher} + \begin{location}\begin{address}
\location
\end{address}\end{location} + \begin{publisher}
\end{publisher} +
+ \begin{series}\format[XMLChars,RemoveLatexCommands]{\series}\end{series} + \begin{series}\begin{editora}\format[XMLChars,RemoveLatexCommands]{\editora}\end{editora}\end{series} + + + \begin{url}\format[XMLChars]{\url}\end{url} + \begin{doi}\format[XMLChars]{\doi}\end{doi} + \begin{isbn}\format[XMLChars]{\isbn}\end{isbn} + + \begin{abstract}\format[XMLChars,RemoveLatexCommands]{\abstract}\end{abstract} +
diff --git a/src/main/resources/resource/layout/docbook5.end.layout b/src/main/resources/resource/layout/docbook5.end.layout new file mode 100644 index 00000000000..0ef7a6a17b2 --- /dev/null +++ b/src/main/resources/resource/layout/docbook5.end.layout @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/resources/resource/layout/docbook5.inbook.layout b/src/main/resources/resource/layout/docbook5.inbook.layout new file mode 100644 index 00000000000..fef76871a2f --- /dev/null +++ b/src/main/resources/resource/layout/docbook5.inbook.layout @@ -0,0 +1,30 @@ + + + +\begin{author}\format[CreateDocBook5Authors]{\author}\end{author} + +\begin{editor}\format[CreateDocBook5Editors]{\editor}\end{editor} + + + \begin{title}\format[XMLChars,RemoveLatexCommands]{\title} \end{title} + + \n + \begin{booktitle}\format[XMLChars,RemoveLatexCommands]{\booktitle}\end{booktitle} + \begin{edition}\format[XMLChars,RemoveLatexCommands]{\edition}\end{edition} + \begin{year}\year\end{year} + \begin{series}\format[XMLChars,RemoveLatexCommands]{\series}\end{series} + \begin{volume}\volume \end{volume} + \begin{chapter}\chapter \end{chapter} + \begin{pages}\format[FormatPagesForXML]{\pages} \end{pages} + \begin{publisher}\end{publisher} + \begin{publisher}\format[XMLChars]{\publisher} \end{publisher} + \begin{location}\begin{address}
{\location}
\end{address}\end{location} + \begin{publisher}
\end{publisher} +
+ + \begin{url}\format[XMLChars]{\url}\end{url} + \begin{doi}\format[XMLChars]{\doi}\end{doi} + \begin{isbn}\format[XMLChars]{\isbn}\end{isbn} + + \begin{abstract}\format[XMLChars,RemoveLatexCommands]{\abstract}\end{abstract} +
diff --git a/src/main/resources/resource/layout/docbook5.incollection.layout b/src/main/resources/resource/layout/docbook5.incollection.layout new file mode 100644 index 00000000000..e14ed2fdb83 --- /dev/null +++ b/src/main/resources/resource/layout/docbook5.incollection.layout @@ -0,0 +1,30 @@ + + + +\begin{author}\format[CreateDocBook5Authors]{\author}\end{author} + +\begin{editor}\format[CreateDocBook5Editors]{\editor}\end{editor} + + + \begin{title}\format[XMLChars,RemoveLatexCommands]{\title} \end{title} + + \n + \begin{booktitle}\format[XMLChars,RemoveLatexCommands]{\booktitle}\end{booktitle} + \begin{edition}\format[XMLChars,RemoveLatexCommands]{\edition}\end{edition} + \begin{year}\year\end{year} + \begin{series}\format[XMLChars,RemoveLatexCommands]{\series}\end{series} + \begin{volume}\volume \end{volume} + \begin{chapter}\chapter \end{chapter} + \begin{pages}\format[FormatPagesForXML]{\pages} \end{pages} + \begin{publisher}\end{publisher} + \begin{publisher}\format[XMLChars]{\publisher} \end{publisher} + \begin{location}\begin{address}
\location
\end{address}\end{location} + \begin{publisher}
\end{publisher} +
+ + \begin{url}\format[XMLChars]{\url}\end{url} + \begin{doi}\format[XMLChars]{\doi}\end{doi} + \begin{isbn}\format[XMLChars]{\isbn}\end{isbn} + + \begin{abstract}\format[XMLChars,RemoveLatexCommands]{\abstract}\end{abstract} +
diff --git a/src/main/resources/resource/layout/docbook5.layout b/src/main/resources/resource/layout/docbook5.layout new file mode 100644 index 00000000000..b5e4c7b3770 --- /dev/null +++ b/src/main/resources/resource/layout/docbook5.layout @@ -0,0 +1,27 @@ + + + + +\begin{author} \format[CreateDocBook5Authors]{\author} \end{author} + +\begin{editor} \format[CreateDocBook5Editors]{\editor} \end{editor} + + + \begin{title} \format[XMLChars,RemoveLatexCommands]{\title} \end{title} + + \begin{url} + \format[XMLChars]{\url} + \end{url} + \begin{doi} + \format[XMLChars]{\doi} + \end{doi} + \begin{isbn} + \format[XMLChars]{\isbn} + \end{isbn} + + \begin{abstract} + + \format[XMLChars,RemoveLatexCommands]{\abstract} + + \end{abstract} + diff --git a/src/main/resources/resource/layout/docbook5.phdthesis.layout b/src/main/resources/resource/layout/docbook5.phdthesis.layout new file mode 100644 index 00000000000..e64ad00ced4 --- /dev/null +++ b/src/main/resources/resource/layout/docbook5.phdthesis.layout @@ -0,0 +1,30 @@ + + + + \begin{author}\format[CreateDocBook5Authors]{\author} \end{author} + + + \begin{title}\format[XMLChars,RemoveLatexCommands]{\title} \end{title} + + + \n + \begin{institution}\format[XMLChars]{\institution}\end{institution} + \begin{year}\year\end{year} + + + \begin{url} + \format[XMLChars]{\url} + \end{url} + \begin{doi} + \format[XMLChars]{\doi} + \end{doi} + \begin{isbn} + \format[XMLChars]{\isbn} + \end{isbn} + + \begin{abstract} + + \format[XMLChars,RemoveLatexCommands]{\abstract} + + \end{abstract} + diff --git a/src/main/resources/resource/layout/docbook5.www.layout b/src/main/resources/resource/layout/docbook5.www.layout new file mode 100644 index 00000000000..a3032e88efa --- /dev/null +++ b/src/main/resources/resource/layout/docbook5.www.layout @@ -0,0 +1,23 @@ + + + +\begin{author}\format[CreateDocBook5Authors]{\author} \end{author} + +\begin{editor}\format[CreateDocBook5Editors]{\editor} \end{editor} + + + \n + \begin{title}\format[XMLChars,RemoveLatexCommands]{\title} \end{title} + \begin{year}\year\end{year} + + + \begin{url} + \format[XMLChars]{\url} + \end{url} + + \begin{abstract} + + \format[XMLChars,RemoveLatexCommands]{\abstract} + + \end{abstract} + diff --git a/src/test/java/org/jabref/architecture/TestArchitectureTests.java b/src/test/java/org/jabref/architecture/TestArchitectureTests.java index c37c450d8a0..da908308d9d 100644 --- a/src/test/java/org/jabref/architecture/TestArchitectureTests.java +++ b/src/test/java/org/jabref/architecture/TestArchitectureTests.java @@ -23,6 +23,7 @@ public class TestArchitectureTests { private static final String CLASS_ORG_JABREF_PREFERENCES = "org.jabref.preferences.JabRefPreferences"; 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_SAVE_DATABASE_ACTION_TEST = "SaveDatabaseActionTest"; 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"; @@ -36,9 +37,11 @@ public TestArchitectureTests() { exceptions = new ArrayList<>(); exceptions.add(CLASS_ORG_JABREF_PREFERENCES_TEST); exceptions.add(CLASS_ORG_JABREF_PREFERENCES_MIGRATIONS_TEST); + exceptions.add(CLASS_ORG_JABREF_SAVE_DATABASE_ACTION_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); + } public static Stream data() { diff --git a/src/test/java/org/jabref/gui/exporter/SaveDatabaseActionTest.java b/src/test/java/org/jabref/gui/exporter/SaveDatabaseActionTest.java new file mode 100644 index 00000000000..a0bce778175 --- /dev/null +++ b/src/test/java/org/jabref/gui/exporter/SaveDatabaseActionTest.java @@ -0,0 +1,103 @@ +package org.jabref.gui.exporter; + +import java.io.File; +import java.nio.file.Path; +import java.util.Optional; + +import org.jabref.gui.BasePanel; +import org.jabref.gui.DialogService; +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.util.FileDialogConfiguration; +import org.jabref.model.database.BibDatabaseContext; +import org.jabref.model.database.shared.DatabaseLocation; +import org.jabref.preferences.JabRefPreferences; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class SaveDatabaseActionTest { + + private static final String TEST_FILE_PATH = "C:\\Users\\John_Doe\\Jabref"; + private final File file = new File(TEST_FILE_PATH); + private Optional path = Optional.of(file.toPath()); + + private DialogService dialogService = mock(DialogService.class); + private JabRefPreferences preferences = mock(JabRefPreferences.class); + private BasePanel basePanel = mock(BasePanel.class); + private JabRefFrame jabRefFrame = mock(JabRefFrame.class); + private BibDatabaseContext dbContext = spy(BibDatabaseContext.class); + private SaveDatabaseAction saveDatabaseAction; + + @Before + public void setUp() { + when(basePanel.frame()).thenReturn(jabRefFrame); + when(basePanel.getBibDatabaseContext()).thenReturn(dbContext); + when(jabRefFrame.getDialogService()).thenReturn(dialogService); + + saveDatabaseAction = spy(new SaveDatabaseAction(basePanel, preferences)); + } + + @Test + public void saveAsShouldSetWorkingDirectory() { + when(preferences.get(JabRefPreferences.WORKING_DIRECTORY)).thenReturn(TEST_FILE_PATH); + when(dialogService.showFileSaveDialog(any(FileDialogConfiguration.class))).thenReturn(path); + doNothing().when(saveDatabaseAction).saveAs(any()); + + saveDatabaseAction.saveAs(); + + verify(preferences, times(1)).setWorkingDir(path.get().getParent()); + } + + @Test + public void saveAsShouldNotSetWorkingDirectoryIfNotSelected() { + when(preferences.get(JabRefPreferences.WORKING_DIRECTORY)).thenReturn(TEST_FILE_PATH); + when(dialogService.showFileSaveDialog(any(FileDialogConfiguration.class))).thenReturn(Optional.empty()); + doNothing().when(saveDatabaseAction).saveAs(any()); + + saveDatabaseAction.saveAs(); + + verify(preferences, times(0)).setWorkingDir(path.get().getParent()); + } + + @Test + public void saveAsShouldSetNewDatabasePathIntoContext() { + when(dbContext.getDatabasePath()).thenReturn(Optional.empty()); + when(dbContext.getLocation()).thenReturn(DatabaseLocation.LOCAL); + when(preferences.getBoolean(JabRefPreferences.LOCAL_AUTO_SAVE)).thenReturn(false); + + saveDatabaseAction.saveAs(file.toPath()); + + verify(dbContext, times(1)).setDatabaseFile(file.toPath()); + } + + @Test + public void saveShouldShowSaveAsIfDatabaseNotSelected() { + when(dbContext.getDatabasePath()).thenReturn(Optional.empty()); + when(dbContext.getLocation()).thenReturn(DatabaseLocation.LOCAL); + when(preferences.getBoolean(JabRefPreferences.LOCAL_AUTO_SAVE)).thenReturn(false); + when(dialogService.showFileSaveDialog(any())).thenReturn(path); + doNothing().when(saveDatabaseAction).saveAs(file.toPath()); + + saveDatabaseAction.save(); + + verify(saveDatabaseAction, times(1)).saveAs(file.toPath()); + } + + @Test + public void saveShouldNotSaveDatabaseIfPathNotSet() { + when(dbContext.getDatabasePath()).thenReturn(Optional.empty()); + + boolean result = saveDatabaseAction.save(); + + assertFalse(result); + } +} diff --git a/src/test/java/org/jabref/logic/exporter/DocBook5ExporterTest.java b/src/test/java/org/jabref/logic/exporter/DocBook5ExporterTest.java new file mode 100644 index 00000000000..948d47facf7 --- /dev/null +++ b/src/test/java/org/jabref/logic/exporter/DocBook5ExporterTest.java @@ -0,0 +1,85 @@ +package org.jabref.logic.exporter; + +import java.net.URISyntaxException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.LocalDate; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.jabref.logic.layout.LayoutFormatterPreferences; +import org.jabref.logic.xmp.XmpPreferences; +import org.jabref.model.database.BibDatabaseContext; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.BibtexEntryTypes; +import org.jabref.model.entry.FieldName; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junitpioneer.jupiter.TempDirectory; +import org.mockito.Answers; +import org.xmlunit.builder.Input; +import org.xmlunit.builder.Input.Builder; +import org.xmlunit.diff.DefaultNodeMatcher; +import org.xmlunit.diff.ElementSelectors; +import org.xmlunit.matchers.CompareMatcher; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.Mockito.mock; + +@ExtendWith(TempDirectory.class) +public class DocBook5ExporterTest { + + public BibDatabaseContext databaseContext; + public Charset charset; + public List entries; + + private Path xmlFile; + private Exporter exportFormat; + + @BeforeEach + public void setUp() throws URISyntaxException { + xmlFile = Paths.get(DocBook5ExporterTest.class.getResource("Docbook5ExportFormat.xml").toURI()); + + Map customFormats = new HashMap<>(); + LayoutFormatterPreferences layoutPreferences = mock(LayoutFormatterPreferences.class, Answers.RETURNS_DEEP_STUBS); + SavePreferences savePreferences = mock(SavePreferences.class); + XmpPreferences xmpPreferences = mock(XmpPreferences.class); + ExporterFactory exporterFactory = ExporterFactory.create(customFormats, layoutPreferences, savePreferences, xmpPreferences); + + exportFormat = exporterFactory.getExporterByName("docbook5").get(); + + LocalDate myDate = LocalDate.of(2018, 1, 1); + + databaseContext = new BibDatabaseContext(); + charset = StandardCharsets.UTF_8; + BibEntry entry = new BibEntry(BibtexEntryTypes.BOOK); + entry.setField(FieldName.TITLE, "my paper title"); + entry.setField(FieldName.AUTHOR, "Stefan Kolb and Tobias Diez"); + entry.setField(FieldName.ISBN, "1-2-34"); + entry.setCiteKey("mykey"); + entry.setDate(new org.jabref.model.entry.Date(myDate)); + entries = Arrays.asList(entry); + } + + @Test + public void testPerformExportForSingleEntry(@TempDirectory.TempDir Path testFolder) throws Exception { + + Path path = testFolder.resolve("ThisIsARandomlyNamedFile"); + + exportFormat.export(databaseContext, path, charset, entries); + + Builder control = Input.from(Files.newInputStream(xmlFile)); + Builder test = Input.from(Files.newInputStream(path)); + + assertThat(test, CompareMatcher.isSimilarTo(control) + .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText)).throwComparisonFailure()); + } + +} diff --git a/src/test/java/org/jabref/logic/integrity/PagesCheckerBibLatexTest.java b/src/test/java/org/jabref/logic/integrity/PagesCheckerBibLatexTest.java new file mode 100644 index 00000000000..9958b8c4172 --- /dev/null +++ b/src/test/java/org/jabref/logic/integrity/PagesCheckerBibLatexTest.java @@ -0,0 +1,73 @@ +package org.jabref.logic.integrity; + +import java.util.Optional; + +import org.jabref.model.database.BibDatabaseContext; +import org.jabref.model.database.BibDatabaseMode; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class PagesCheckerBibLatexTest { + + private PagesChecker checker; + + @BeforeEach + void setUp() { + BibDatabaseContext database = new BibDatabaseContext(); + database.setMode(BibDatabaseMode.BIBLATEX); + checker = new PagesChecker(database); + } + + @Test + void acceptsSinglePage() { + assertEquals(Optional.empty(), checker.checkValue("12")); + } + + @Test + void acceptsSinglePageRange() { + assertEquals(Optional.empty(), checker.checkValue("12-15")); + } + + @Test + void acceptsSinglePageRangeWithDoubleDashes() { + assertEquals(Optional.empty(), checker.checkValue("12--15")); + } + + @Test + void acceptsSinglePageRangeWithEnDashes() { + assertEquals(Optional.empty(), checker.checkValue("12–15")); + } + + @Test + void acceptsSinglePageRangeWithPagePrefix() { + assertEquals(Optional.empty(), checker.checkValue("R795--R804")); + } + + @Test + void acceptsMultiplePageRange() { + assertEquals(Optional.empty(), checker.checkValue("12-15,18-29")); + } + + @Test + void acceptsOpenEndPageRange() { + assertEquals(Optional.empty(), checker.checkValue("-15")); + } + + @Test + void acceptsOpenStartPageRange() { + assertEquals(Optional.empty(), checker.checkValue("12-")); + } + + @Test + void complainsAboutPPrefix() { + assertEquals(Optional.of("should contain a valid page number range"), checker.checkValue("p. 12")); + } + + @Test + void complainsAboutPPPrefix() { + assertEquals(Optional.of("should contain a valid page number range"), checker.checkValue("pp. 12-15")); + } +} diff --git a/src/test/resources/org/jabref/logic/exporter/Docbook5ExportFormat.xml b/src/test/resources/org/jabref/logic/exporter/Docbook5ExportFormat.xml new file mode 100644 index 00000000000..ddb29f48635 --- /dev/null +++ b/src/test/resources/org/jabref/logic/exporter/Docbook5ExportFormat.xml @@ -0,0 +1,40 @@ + + + + + + + + StefanKolb + TobiasDiez + + + + + my paper title + + + + + + 2018 + + + +
+ +
+ + + + + + + 1-2-34 + + + +
\ No newline at end of file